Mercurial > projects > doodle
comparison doodle/gtk/canvas.d @ 79:535bae7a7305
Checkpoint
author | "David Bryant <bagnose@gmail.com>" |
---|---|
date | Sun, 15 Aug 2010 23:18:05 +0930 |
parents | 024a5608087f |
children | b759414d2b72 |
comparison
equal
deleted
inserted
replaced
78:024a5608087f | 79:535bae7a7305 |
---|---|
33 | 33 |
34 import std.math; | 34 import std.math; |
35 import std.stdio; | 35 import std.stdio; |
36 } | 36 } |
37 | 37 |
38 // | |
39 // TODO | |
40 // Pass out a scope Drawing reference to the layers for drawing on instead of cairo context. | |
41 // Create a class called LayerStack so we don't have to provide that non-gtk behaviour here. | |
42 // | |
43 | |
44 final class Canvas : Table, private IViewport { | 38 final class Canvas : Table, private IViewport { |
45 this(in Layer[] layers, IEventHandler eventHandler, IGrid grid, in double pixelsPerMillimetre) { | 39 this(in Layer[] layers, IEventHandler eventHandler, IGrid grid, in double pixelsPerMillimetre) { |
46 super(3, 3, 0); | 40 super(3, 3, 0); |
47 | 41 |
48 _damageScreen = Rectangle.DEFAULT; | 42 _damageScreen = Rectangle.DEFAULT; |
49 | 43 |
50 _layerStack = new LayerStack(layers); | |
51 _eventHandler = eventHandler; | 44 _eventHandler = eventHandler; |
52 _grid = grid; | 45 _grid = grid; |
53 _pixelsPerMillimetre = pixelsPerMillimetre; | 46 _pixelsPerMillimetre = pixelsPerMillimetre; |
47 | |
48 _layerStack = new LayerStack(layers); | |
54 | 49 |
55 // Create our child widgets and register callbacks | 50 // Create our child widgets and register callbacks |
56 | 51 |
57 _hRuler = new HRuler; | 52 _hRuler = new HRuler; |
58 attach(_hRuler, | 53 attach(_hRuler, |
134 2, 3, | 129 2, 3, |
135 1, 2, | 130 1, 2, |
136 AttachOptions.SHRINK, | 131 AttachOptions.SHRINK, |
137 AttachOptions.FILL | AttachOptions.EXPAND, | 132 AttachOptions.FILL | AttachOptions.EXPAND, |
138 0, 0); | 133 0, 0); |
134 | |
135 _cursors = [ | |
136 Cursor.DEFAULT : CursorType.ARROW, | |
137 Cursor.HAND : CursorType.HAND1, | |
138 Cursor.CROSSHAIR : CursorType.CROSSHAIR, | |
139 Cursor.PENCIL : CursorType.PENCIL | |
140 ]; | |
139 } | 141 } |
140 | 142 |
141 protected { // XXX the compiler complains about unimplemented methods if this is private | 143 protected { // XXX the compiler complains about unimplemented methods if this is private |
142 | 144 |
143 // IViewport overrides: | 145 // IViewport overrides: |
144 | 146 |
145 void zoomRelative(in Point screenDatum, in double factor) { | 147 void zoomRelative(in Point screenDatum, in double factor) { |
146 _screenModel.zoomRelative(factor, screenDatum); | 148 _screenModel.zoomRelative(factor, screenDatum); |
147 | |
148 consolidateBounds; | 149 consolidateBounds; |
149 | |
150 updateAdjustments; | 150 updateAdjustments; |
151 updateRulers; | 151 updateRulers; |
152 _grid.zoomChanged(_screenModel.zoom); | 152 _grid.zoomChanged(_screenModel.zoom); |
153 queueDraw; | 153 queueDraw; |
154 } | 154 } |
155 | 155 |
156 void panRelative(in Vector screenDisplacement) { | 156 void panRelative(in Vector screenDisplacement) { |
157 _screenModel.panRelativeScreen(screenDisplacement); | 157 _screenModel.panRelativeScreen(screenDisplacement); |
158 | |
159 consolidateBounds; | 158 consolidateBounds; |
160 | |
161 updateAdjustments; | 159 updateAdjustments; |
162 updateRulers; | 160 updateRulers; |
163 queueDraw; | 161 queueDraw; |
164 } | 162 } |
165 | 163 |
166 void setCursor(in Cursor cursor) { | 164 void setCursor(in Cursor cursor) { |
167 // FIXME how about an associative array instead of a switch statement? | 165 _drawingArea.setCursor(new gdk.Cursor.Cursor(_cursors[cursor])); |
168 CursorType cursorType; | |
169 | |
170 switch (cursor) { | |
171 case Cursor.DEFAULT: | |
172 cursorType = CursorType.ARROW; | |
173 break; | |
174 case Cursor.HAND: | |
175 cursorType = CursorType.HAND1; | |
176 break; | |
177 case Cursor.CROSSHAIR: | |
178 cursorType = CursorType.CROSSHAIR; | |
179 break; | |
180 case Cursor.PENCIL: | |
181 cursorType = CursorType.PENCIL; | |
182 break; | |
183 default: | |
184 assert(0); | |
185 } | |
186 | |
187 _drawingArea.setCursor(new gdk.Cursor.Cursor(cursorType)); | |
188 } | 166 } |
189 | 167 |
190 void damageModel(in Rectangle area) { | 168 void damageModel(in Rectangle area) { |
191 _damageScreen = _damageScreen | _screenModel.modelToScreen(area); | 169 _damageScreen = _damageScreen | _screenModel.modelToScreen(area); |
192 } | 170 } |
197 } | 175 } |
198 | 176 |
199 private { | 177 private { |
200 | 178 |
201 void initialiseBounds(in Rectangle viewBoundsScreen) { | 179 void initialiseBounds(in Rectangle viewBoundsScreen) { |
202 Rectangle lb = _layerStack.bounds; | 180 Rectangle layerBounds = _layerStack.bounds; |
203 | 181 Rectangle paddedLayerBounds = growCentre(layerBounds, 2 * layerBounds.size); |
204 // FIXME use a function that grows a rectangle about its centre | |
205 // and change 2.0 to a class-level constant | |
206 Rectangle paddedLayerBounds = expand(move(lb, - lb.size), 2.0 * lb.size); | |
207 | |
208 _screenModel = new ScreenModel(0.25 * _pixelsPerMillimetre, paddedLayerBounds, viewBoundsScreen); | 182 _screenModel = new ScreenModel(0.25 * _pixelsPerMillimetre, paddedLayerBounds, viewBoundsScreen); |
209 | |
210 _grid.zoomChanged(_screenModel.zoom); | 183 _grid.zoomChanged(_screenModel.zoom); |
211 | 184 |
212 updateAdjustments; | 185 updateAdjustments; |
213 updateRulers; | 186 updateRulers; |
214 } | 187 } |
215 | 188 |
216 void consolidateBounds() { | 189 void consolidateBounds() { |
217 Rectangle lb = _layerStack.bounds; | 190 Rectangle layerBounds = _layerStack.bounds; |
218 | 191 Rectangle paddedLayerBounds = growCentre(layerBounds, 2 * layerBounds.size); |
219 // FIXME likewise as above | |
220 Rectangle paddedLayerBounds = expand(move(lb, - lb.size), 2.0 * lb.size); | |
221 | |
222 _screenModel.consolidateCanvasBounds(paddedLayerBounds); | 192 _screenModel.consolidateCanvasBounds(paddedLayerBounds); |
223 | 193 |
224 updateAdjustments; | 194 updateAdjustments; |
225 updateRulers; | 195 updateRulers; |
226 } | 196 } |
227 | 197 |
228 bool onConfigure(GdkEventConfigure * event, Widget widget) { | 198 bool onConfigure(GdkEventConfigure * event, Widget widget) { |
229 assert(widget is _drawingArea); | 199 assert(widget is _drawingArea); |
230 | 200 |
231 Rectangle viewBoundsScreen = Rectangle(Point(0.0, 0.0), Vector(cast(double)event.width, cast(double)event.height)); | 201 Rectangle viewBoundsScreen = Rectangle(Point(0.0, 0.0), Vector(cast(double)event.width, cast(double)event.height)); |
232 | 202 if (_screenModel is null) { initialiseBounds(viewBoundsScreen); } |
233 if (_screenModel is null) { | 203 else { consolidateBounds; } |
234 initialiseBounds(viewBoundsScreen); | |
235 } | |
236 else { | |
237 consolidateBounds; | |
238 } | |
239 | 204 |
240 return true; | 205 return true; |
241 } | 206 } |
242 | 207 |
243 bool onExpose(GdkEventExpose * event, Widget widget) { | 208 bool onExpose(GdkEventExpose * event, Widget widget) { |
252 scope modelCr = new Context(dr); | 217 scope modelCr = new Context(dr); |
253 scope screenCr = new Context(dr); | 218 scope screenCr = new Context(dr); |
254 | 219 |
255 Rectangle screenDamage = | 220 Rectangle screenDamage = |
256 event is null ? _screenModel.viewBoundsScreen : | 221 event is null ? _screenModel.viewBoundsScreen : |
257 // FIXME next line sucks | |
258 Rectangle(_screenModel.viewBoundsScreen.position + Vector(cast(double)event.area.x, _screenModel.viewBoundsScreen.h - cast(double)(event.area.y + event.area.height)), | 222 Rectangle(_screenModel.viewBoundsScreen.position + Vector(cast(double)event.area.x, _screenModel.viewBoundsScreen.h - cast(double)(event.area.y + event.area.height)), |
259 Vector(cast(double)event.area.width, cast(double)event.area.height)); | 223 Vector(cast(double)event.area.width, cast(double)event.area.height)); |
260 | 224 |
261 Rectangle modelDamage = _screenModel.screenToModel(screenDamage); | 225 Rectangle modelDamage = _screenModel.screenToModel(screenDamage); |
262 | |
263 //trace("Screen damage: %s, model damage: %s", screenDamage, modelDamage); | |
264 | 226 |
265 modelCr.save; screenCr.save; { | 227 modelCr.save; screenCr.save; { |
266 { | 228 { |
267 // Setup model context and clip | 229 // Setup model context and clip |
268 modelCr.translate(0.0, _screenModel.viewBoundsScreen.h); | 230 modelCr.translate(0.0, _screenModel.viewBoundsScreen.h); |
398 updateRulers; | 360 updateRulers; |
399 queueDraw; | 361 queueDraw; |
400 } | 362 } |
401 | 363 |
402 void updateRulers() { | 364 void updateRulers() { |
403 immutable Point viewLeftBottom = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1); | 365 immutable Point viewLeftBottom = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner0); |
404 immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1); | 366 immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1); |
405 | 367 |
406 // Define these just to obtain the position | 368 // Define these just to obtain the position |
407 // below and we can preserve it | 369 // below and we can preserve it |
408 double lower, upper, position, maxSize; | 370 double lower, upper, position, maxSize; |
422 | 384 |
423 void updateAdjustments() { | 385 void updateAdjustments() { |
424 immutable Point viewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0)); | 386 immutable Point viewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0)); |
425 immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1); | 387 immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1); |
426 | 388 |
427 // Adjust the canvas size if necessary FIXME is this required?? | 389 // Adjust the canvas size if necessary |
428 _screenModel.canvasAccommodate(Rectangle(viewLeftBottom, viewRightTop)); | 390 _screenModel.canvasAccommodate(Rectangle(viewLeftBottom, viewRightTop)); |
429 | 391 |
430 // FIXME | 392 Rectangle viewBoundsModel = _screenModel.viewBoundsModel; |
431 Rectangle modelSize = _screenModel.screenToModel(_screenModel.viewBoundsScreen); | |
432 | 393 |
433 // Update the adjustments | 394 // Update the adjustments |
434 | 395 |
435 GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct; | 396 GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct; |
436 GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct; | 397 GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct; |
438 gtk_adjustment_set_lower(hGtkAdjustment, _screenModel.canvasBoundsModel.x0); | 399 gtk_adjustment_set_lower(hGtkAdjustment, _screenModel.canvasBoundsModel.x0); |
439 gtk_adjustment_set_upper(hGtkAdjustment, _screenModel.canvasBoundsModel.x1); | 400 gtk_adjustment_set_upper(hGtkAdjustment, _screenModel.canvasBoundsModel.x1); |
440 gtk_adjustment_set_value(hGtkAdjustment, viewLeftBottom.x); | 401 gtk_adjustment_set_value(hGtkAdjustment, viewLeftBottom.x); |
441 gtk_adjustment_set_step_increment(hGtkAdjustment, _screenModel.canvasBoundsModel.w / 16.0); | 402 gtk_adjustment_set_step_increment(hGtkAdjustment, _screenModel.canvasBoundsModel.w / 16.0); |
442 gtk_adjustment_set_page_increment(hGtkAdjustment, _screenModel.canvasBoundsModel.w / 4.0); | 403 gtk_adjustment_set_page_increment(hGtkAdjustment, _screenModel.canvasBoundsModel.w / 4.0); |
443 gtk_adjustment_set_page_size(hGtkAdjustment, modelSize.w); | 404 gtk_adjustment_set_page_size(hGtkAdjustment, viewBoundsModel.w); |
444 | 405 |
445 gtk_adjustment_set_lower(vGtkAdjustment, _screenModel.canvasBoundsModel.y0); | 406 gtk_adjustment_set_lower(vGtkAdjustment, _screenModel.canvasBoundsModel.y0); |
446 gtk_adjustment_set_upper(vGtkAdjustment, _screenModel.canvasBoundsModel.y1); | 407 gtk_adjustment_set_upper(vGtkAdjustment, _screenModel.canvasBoundsModel.y1); |
447 gtk_adjustment_set_value(vGtkAdjustment, viewLeftBottom.y); | 408 gtk_adjustment_set_value(vGtkAdjustment, viewLeftBottom.y); |
448 gtk_adjustment_set_step_increment(vGtkAdjustment, _screenModel.canvasBoundsModel.h / 16.0); | 409 gtk_adjustment_set_step_increment(vGtkAdjustment, _screenModel.canvasBoundsModel.h / 16.0); |
449 gtk_adjustment_set_page_increment(vGtkAdjustment, _screenModel.canvasBoundsModel.h / 4.0); | 410 gtk_adjustment_set_page_increment(vGtkAdjustment, _screenModel.canvasBoundsModel.h / 4.0); |
450 gtk_adjustment_set_page_size(vGtkAdjustment, modelSize.h); | 411 gtk_adjustment_set_page_size(vGtkAdjustment, viewBoundsModel.h); |
451 | 412 |
452 _hAdjustment.changed; | 413 _hAdjustment.changed; |
453 _hAdjustment.valueChanged; | 414 _hAdjustment.valueChanged; |
454 _vAdjustment.changed; | 415 _vAdjustment.changed; |
455 _vAdjustment.valueChanged; | 416 _vAdjustment.valueChanged; |
464 } | 425 } |
465 } | 426 } |
466 | 427 |
467 void onRealize(Widget widget) { | 428 void onRealize(Widget widget) { |
468 assert(widget is _drawingArea); | 429 assert(widget is _drawingArea); |
469 //writefln("Got realize\n"); | |
470 _drawingArea.grabFocus(); | 430 _drawingArea.grabFocus(); |
471 } | 431 } |
472 | 432 |
473 LayerStack _layerStack; | |
474 IEventHandler _eventHandler; | 433 IEventHandler _eventHandler; |
475 IGrid _grid; | 434 IGrid _grid; |
476 double _pixelsPerMillimetre; | 435 double _pixelsPerMillimetre; |
436 LayerStack _layerStack; | |
437 | |
438 immutable CursorType[Cursor] _cursors; | |
477 | 439 |
478 // Child widgets: | 440 // Child widgets: |
479 HRuler _hRuler; | 441 HRuler _hRuler; |
480 VRuler _vRuler; | 442 VRuler _vRuler; |
481 DrawingArea _drawingArea; | 443 DrawingArea _drawingArea; |
482 Adjustment _hAdjustment; | 444 Adjustment _hAdjustment; |
483 HScrollbar _hScrollbar; | 445 HScrollbar _hScrollbar; |
484 Adjustment _vAdjustment; | 446 Adjustment _vAdjustment; |
485 VScrollbar _vScrollbar; | 447 VScrollbar _vScrollbar; |
486 | 448 |
487 Rectangle _damageScreen; // in screens | 449 Rectangle _damageScreen; |
488 ScreenModel _screenModel; | 450 ScreenModel _screenModel; |
489 } | 451 } |
490 } | 452 } |