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 }