Mercurial > projects > doodle
comparison doodle/gtk/canvas.d @ 71:0f7cf6c6f206
Reimplemented gtk.canvas in terms of tk.pixel_model but
needs a lot of consolidation.
author | "David Bryant <bagnose@gmail.com>" |
---|---|
date | Sat, 14 Aug 2010 20:48:41 +0930 |
parents | 0e61702c6ea6 |
children | 5cc2de64f6d0 |
comparison
equal
deleted
inserted
replaced
70:0e61702c6ea6 | 71:0f7cf6c6f206 |
---|---|
8 private { | 8 private { |
9 import doodle.core.misc; | 9 import doodle.core.misc; |
10 import doodle.core.logging; | 10 import doodle.core.logging; |
11 import doodle.cairo.routines; | 11 import doodle.cairo.routines; |
12 import doodle.gtk.conversions; | 12 import doodle.gtk.conversions; |
13 import doodle.tk.pixel_model; | |
13 | 14 |
14 import cairo.Surface; | 15 import cairo.Surface; |
15 | 16 |
16 import gtk.Widget; | 17 import gtk.Widget; |
17 import gtk.Toolbar; | 18 import gtk.Toolbar; |
33 import std.math; | 34 import std.math; |
34 import std.stdio; | 35 import std.stdio; |
35 | 36 |
36 import core.stdc.string : strlen; | 37 import core.stdc.string : strlen; |
37 } | 38 } |
38 | |
39 // x and y run right and up respectively | |
40 | 39 |
41 final class Canvas : Table, private IViewport { | 40 final class Canvas : Table, private IViewport { |
42 this(in Layer[] layers, IEventHandler eventHandler, IGrid grid, in double pixelsPerMillimetre) { | 41 this(in Layer[] layers, IEventHandler eventHandler, IGrid grid, in double pixelsPerMillimetre) { |
43 super(3, 3, 0); | 42 super(3, 3, 0); |
44 | 43 |
138 protected { // XXX the compiler complains about unimplemented methods if this is private | 137 protected { // XXX the compiler complains about unimplemented methods if this is private |
139 | 138 |
140 // IViewport overrides: | 139 // IViewport overrides: |
141 | 140 |
142 void zoomRelative(in Point pixelDatum, in double factor) { | 141 void zoomRelative(in Point pixelDatum, in double factor) { |
143 // Work out pixel distance from current centre to datum, | 142 _pixelModel.zoomRelative(factor, pixelDatum); |
144 // Do the zoom, then work out the new centre that keeps the | |
145 // pixel distance the same | |
146 | |
147 Point oldModelDatum = pixelToModel(pixelDatum); | |
148 Vector pixelDistance = modelToPixel(oldModelDatum - _viewCentre); | |
149 _zoom = clampZoom(factor * _zoom); | |
150 _viewCentre = oldModelDatum - pixelToModel(pixelDistance); | |
151 | 143 |
152 consolidateBounds; | 144 consolidateBounds; |
153 | 145 |
154 updateAdjustments; | 146 updateAdjustments; |
155 updateRulers; | 147 updateRulers; |
156 _grid.zoomChanged(_zoom); | 148 _grid.zoomChanged(_pixelModel.zoom); |
157 queueDraw; | 149 queueDraw; |
158 } | 150 } |
159 | 151 |
160 void panRelative(in Vector pixelDisplacement) { | 152 void panRelative(in Vector pixelDisplacement) { |
161 _viewCentre = _viewCentre + pixelToModel(pixelDisplacement); | 153 _pixelModel.panRelativePixel(pixelDisplacement); |
162 | 154 |
163 consolidateBounds; | 155 consolidateBounds; |
164 | 156 |
165 updateAdjustments; | 157 updateAdjustments; |
166 updateRulers; | 158 updateRulers; |
189 | 181 |
190 _drawingArea.setCursor(new gdk.Cursor.Cursor(cursorType)); | 182 _drawingArea.setCursor(new gdk.Cursor.Cursor(cursorType)); |
191 } | 183 } |
192 | 184 |
193 void damageModel(in Rectangle area) { | 185 void damageModel(in Rectangle area) { |
194 _damage = _damage | modelToPixel(area); | 186 _damage = _damage | _pixelModel.modelToPixel(area); |
195 } | 187 } |
196 | 188 |
197 void damagePixel(in Rectangle area) { | 189 void damagePixel(in Rectangle area) { |
198 _damage = _damage | area; | 190 _damage = _damage | area; |
199 } | 191 } |
206 foreach (layer; _layers) { bounds = bounds | layer.bounds; } | 198 foreach (layer; _layers) { bounds = bounds | layer.bounds; } |
207 assert(bounds.valid); | 199 assert(bounds.valid); |
208 return bounds; | 200 return bounds; |
209 } | 201 } |
210 | 202 |
211 void initialiseBounds() { | 203 void initialiseBounds(in Rectangle viewBounds) { |
212 Rectangle lb = layerBounds; | 204 Rectangle lb = layerBounds; |
213 | 205 |
214 // FIXME use a function that grows a rectangle about its centre | 206 // FIXME use a function that grows a rectangle about its centre |
215 // and change 2.0 to a class-level constant | 207 // and change 2.0 to a class-level constant |
216 Rectangle paddedLayerBounds = expand(move(lb, - lb.size), 2.0 * lb.size); | 208 Rectangle paddedLayerBounds = expand(move(lb, - lb.size), 2.0 * lb.size); |
217 | 209 |
218 // | 210 _pixelModel = new PixelModel(0.25 * _pixelsPerMillimetre, paddedLayerBounds, viewBounds); |
219 | 211 |
220 // FIXME 0.25 | 212 _grid.zoomChanged(_pixelModel.zoom); |
221 _zoom = 0.25 * _pixelsPerMillimetre; // ie 0.25 pixels represents a millimetre | |
222 | |
223 _canvasBounds = paddedLayerBounds; | |
224 _viewCentre = _canvasBounds.centre; | |
225 | |
226 _grid.zoomChanged(_zoom); | |
227 | 213 |
228 updateAdjustments; | 214 updateAdjustments; |
229 updateRulers; | 215 updateRulers; |
230 } | 216 } |
231 | 217 |
233 Rectangle lb = layerBounds; | 219 Rectangle lb = layerBounds; |
234 | 220 |
235 // FIXME likewise as above | 221 // FIXME likewise as above |
236 Rectangle paddedLayerBounds = expand(move(lb, - lb.size), 2.0 * lb.size); | 222 Rectangle paddedLayerBounds = expand(move(lb, - lb.size), 2.0 * lb.size); |
237 | 223 |
238 Rectangle r = pixelToModel(_viewBounds); | 224 _pixelModel.consolidateCanvasBounds(paddedLayerBounds); |
239 _canvasBounds = r | paddedLayerBounds; | |
240 | 225 |
241 updateAdjustments; | 226 updateAdjustments; |
242 updateRulers; | 227 updateRulers; |
243 } | 228 } |
244 | 229 |
245 bool onConfigure(GdkEventConfigure * event, Widget widget) { | 230 bool onConfigure(GdkEventConfigure * event, Widget widget) { |
246 assert(widget is _drawingArea); | 231 assert(widget is _drawingArea); |
247 | 232 |
248 _viewBounds = Rectangle(Point(0.0, 0.0), Vector(cast(double)event.width, cast(double)event.height)); | 233 Rectangle viewBounds = Rectangle(Point(0.0, 0.0), Vector(cast(double)event.width, cast(double)event.height)); |
249 | 234 |
250 if (!_boundsValid) { | 235 if (_pixelModel is null) { |
251 initialiseBounds; | 236 initialiseBounds(viewBounds); |
252 _boundsValid = true; | |
253 } | 237 } |
254 else { | 238 else { |
255 consolidateBounds; | 239 consolidateBounds; |
256 } | 240 } |
257 | 241 |
269 | 253 |
270 scope modelCr = new Context(dr); | 254 scope modelCr = new Context(dr); |
271 scope pixelCr = new Context(dr); | 255 scope pixelCr = new Context(dr); |
272 | 256 |
273 Rectangle pixelDamage = | 257 Rectangle pixelDamage = |
274 event is null ? | 258 event is null ? _pixelModel.viewBounds : |
275 _viewBounds : // XXX can we do something nice with the next line? | 259 // FIXME next line sucks |
276 Rectangle(_viewBounds.position + Vector(cast(double)event.area.x, _viewBounds.h - cast(double)(event.area.y + event.area.height)), | 260 Rectangle(_pixelModel.viewBounds.position + Vector(cast(double)event.area.x, _pixelModel.viewBounds.h - cast(double)(event.area.y + event.area.height)), |
277 Vector(cast(double)event.area.width, cast(double)event.area.height)); | 261 Vector(cast(double)event.area.width, cast(double)event.area.height)); |
278 | 262 |
279 Rectangle modelDamage = pixelToModel(pixelDamage); | 263 Rectangle modelDamage = _pixelModel.pixelToModel(pixelDamage); |
280 | 264 |
281 //trace("Pixel damage: %s, model damage: %s", pixelDamage, modelDamage); | 265 //trace("Pixel damage: %s, model damage: %s", pixelDamage, modelDamage); |
282 | 266 |
283 modelCr.save; pixelCr.save; { | 267 modelCr.save; pixelCr.save; { |
284 { | 268 { |
285 // Setup model context and clip | 269 // Setup model context and clip |
286 modelCr.translate(0.0, _viewBounds.h); | 270 modelCr.translate(0.0, _pixelModel.viewBounds.h); |
287 modelCr.scale(_zoom, -_zoom); | 271 modelCr.scale(_pixelModel.zoom, -_pixelModel.zoom); |
288 | 272 |
289 // XXX revisit | 273 immutable Point viewLeftBottom = _pixelModel.pixelToModel(Point(0.0, 0.0)); |
290 immutable Vector modelSize = pixelToModel(_viewBounds.size); | |
291 immutable Point viewLeftBottom = _viewCentre - modelSize / 2.0; | |
292 modelCr.translate(-viewLeftBottom.x, -viewLeftBottom.y); | 274 modelCr.translate(-viewLeftBottom.x, -viewLeftBottom.y); |
293 | 275 |
294 rectangle(modelCr, modelDamage); | 276 rectangle(modelCr, modelDamage); |
295 modelCr.clip; | 277 modelCr.clip; |
296 } | 278 } |
297 | 279 |
298 { | 280 { |
299 // Setup pixel context and clip | 281 // Setup pixel context and clip |
300 pixelCr.translate(0.0, _viewBounds.h); | 282 pixelCr.translate(0.0, _pixelModel.viewBounds.h); |
301 pixelCr.scale(1.0, -1.0); | 283 pixelCr.scale(1.0, -1.0); |
302 | 284 |
303 rectangle(pixelCr, pixelDamage); | 285 rectangle(pixelCr, pixelDamage); |
304 pixelCr.clip; | 286 pixelCr.clip; |
305 } | 287 } |
322 | 304 |
323 bool onButtonPress(GdkEventButton * event, Widget widget) { | 305 bool onButtonPress(GdkEventButton * event, Widget widget) { |
324 assert(widget is _drawingArea); | 306 assert(widget is _drawingArea); |
325 //trace("Got button event\n"); | 307 //trace("Got button event\n"); |
326 | 308 |
327 Point pixelPoint = Point(event.x + 0.5, _viewBounds.h - (event.y + 0.5)); | 309 Point pixelPoint = Point(event.x + 0.5, _pixelModel.viewBounds.h - (event.y + 0.5)); |
328 Point modelPoint = pixelToModel(pixelPoint); | 310 Point modelPoint = _pixelModel.pixelToModel(pixelPoint); |
329 | 311 |
330 auto buttonEvent = new ButtonEvent(gtk2tkButtonAction(event.type), | 312 auto buttonEvent = new ButtonEvent(gtk2tkButtonAction(event.type), |
331 gtk2tkButtonName(event.button), | 313 gtk2tkButtonName(event.button), |
332 pixelPoint, | 314 pixelPoint, |
333 modelPoint, | 315 modelPoint, |
341 } | 323 } |
342 | 324 |
343 bool onButtonRelease(GdkEventButton * event, Widget widget) { | 325 bool onButtonRelease(GdkEventButton * event, Widget widget) { |
344 assert(widget is _drawingArea); | 326 assert(widget is _drawingArea); |
345 | 327 |
346 Point pixelPoint = Point(event.x + 0.5, _viewBounds.h - (event.y + 0.5)); | 328 Point pixelPoint = Point(event.x + 0.5, _pixelModel.viewBounds.h - (event.y + 0.5)); |
347 Point modelPoint = pixelToModel(pixelPoint); | 329 Point modelPoint = _pixelModel.pixelToModel(pixelPoint); |
348 | 330 |
349 auto buttonEvent = new ButtonEvent(gtk2tkButtonAction(event.type), | 331 auto buttonEvent = new ButtonEvent(gtk2tkButtonAction(event.type), |
350 gtk2tkButtonName(event.button), | 332 gtk2tkButtonName(event.button), |
351 pixelPoint, | 333 pixelPoint, |
352 modelPoint, | 334 modelPoint, |
407 assert(widget is _drawingArea); | 389 assert(widget is _drawingArea); |
408 //writefln("Got motion notify\n"); | 390 //writefln("Got motion notify\n"); |
409 gtk_widget_event(_hRuler.getWidgetStruct(), cast(GdkEvent *)event); | 391 gtk_widget_event(_hRuler.getWidgetStruct(), cast(GdkEvent *)event); |
410 gtk_widget_event(_vRuler.getWidgetStruct(), cast(GdkEvent *)event); | 392 gtk_widget_event(_vRuler.getWidgetStruct(), cast(GdkEvent *)event); |
411 | 393 |
412 Point pixelPoint = Point(event.x + 0.5, _viewBounds.h - (event.y + 0.5)); | 394 Point pixelPoint = Point(event.x + 0.5, _pixelModel.viewBounds.h - (event.y + 0.5)); |
413 Point modelPoint = pixelToModel(pixelPoint); | 395 Point modelPoint = _pixelModel.pixelToModel(pixelPoint); |
414 | 396 |
415 auto motionEvent = new MotionEvent(pixelPoint, | 397 auto motionEvent = new MotionEvent(pixelPoint, |
416 modelPoint, | 398 modelPoint, |
417 gtk2tkMask(event.state)); | 399 gtk2tkMask(event.state)); |
418 | 400 |
425 | 407 |
426 bool onScroll(GdkEventScroll * event, Widget widget) { | 408 bool onScroll(GdkEventScroll * event, Widget widget) { |
427 assert(widget is _drawingArea); | 409 assert(widget is _drawingArea); |
428 //writefln("Got scroll\n"); | 410 //writefln("Got scroll\n"); |
429 | 411 |
430 Point pixelPoint = Point(event.x + 0.5, _viewBounds.h - (event.y + 0.5)); | 412 Point pixelPoint = Point(event.x + 0.5, _pixelModel.viewBounds.h - (event.y + 0.5)); |
431 Point modelPoint = pixelToModel(pixelPoint); | 413 Point modelPoint = _pixelModel.pixelToModel(pixelPoint); |
432 | 414 |
433 auto scrollEvent = new ScrollEvent(gtk2tkDirection(event.direction), | 415 auto scrollEvent = new ScrollEvent(gtk2tkDirection(event.direction), |
434 pixelPoint, | 416 pixelPoint, |
435 modelPoint, | 417 modelPoint, |
436 gtk2tkMask(event.state)); | 418 gtk2tkMask(event.state)); |
470 */ | 452 */ |
471 | 453 |
472 bool onEnterNotify(GdkEventCrossing * event, Widget widget) { | 454 bool onEnterNotify(GdkEventCrossing * event, Widget widget) { |
473 assert(widget is _drawingArea); | 455 assert(widget is _drawingArea); |
474 | 456 |
475 Point pixelPoint = Point(event.x + 0.5, _viewBounds.h - (event.y + 0.5)); | 457 Point pixelPoint = Point(event.x + 0.5, _pixelModel.viewBounds.h - (event.y + 0.5)); |
476 Point modelPoint = pixelToModel(pixelPoint); | 458 Point modelPoint = _pixelModel.pixelToModel(pixelPoint); |
477 | 459 |
478 auto crossingEvent = new CrossingEvent(gtk2tkCrossingMode(event.mode), | 460 auto crossingEvent = new CrossingEvent(gtk2tkCrossingMode(event.mode), |
479 pixelPoint, | 461 pixelPoint, |
480 modelPoint, | 462 modelPoint, |
481 gtk2tkMask(event.state)); | 463 gtk2tkMask(event.state)); |
490 } | 472 } |
491 | 473 |
492 bool onLeaveNotify(GdkEventCrossing * event, Widget widget) { | 474 bool onLeaveNotify(GdkEventCrossing * event, Widget widget) { |
493 assert(widget is _drawingArea); | 475 assert(widget is _drawingArea); |
494 | 476 |
495 Point pixelPoint = Point(event.x + 0.5, _viewBounds.h - (event.y + 0.5)); | 477 Point pixelPoint = Point(event.x + 0.5, _pixelModel.viewBounds.h - (event.y + 0.5)); |
496 Point modelPoint = pixelToModel(pixelPoint); | 478 Point modelPoint = _pixelModel.pixelToModel(pixelPoint); |
497 | 479 |
498 auto crossingEvent = new CrossingEvent(gtk2tkCrossingMode(event.mode), | 480 auto crossingEvent = new CrossingEvent(gtk2tkCrossingMode(event.mode), |
499 pixelPoint, | 481 pixelPoint, |
500 modelPoint, | 482 modelPoint, |
501 gtk2tkMask(event.state)); | 483 gtk2tkMask(event.state)); |
546 | 528 |
547 void onAdjustmentValueChanged(Adjustment adjustment) { | 529 void onAdjustmentValueChanged(Adjustment adjustment) { |
548 GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct; | 530 GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct; |
549 GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct; | 531 GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct; |
550 | 532 |
551 Point viewLeftBottom = Point(gtk_adjustment_get_value(hGtkAdjustment), | 533 Point oldViewLeftBottom = _pixelModel.pixelToModel(Point(0.0, 0.0)); |
552 gtk_adjustment_get_value(vGtkAdjustment)); | 534 Point newViewLeftBottom = Point(gtk_adjustment_get_value(hGtkAdjustment), |
553 | 535 gtk_adjustment_get_value(vGtkAdjustment)); |
554 Vector modelSize = pixelToModel(_viewBounds.size); // XXX | 536 |
555 | 537 _pixelModel.panRelativeModel(newViewLeftBottom - oldViewLeftBottom); |
556 _viewCentre = viewLeftBottom + modelSize / 2.0; | |
557 | 538 |
558 updateRulers; | 539 updateRulers; |
559 queueDraw; | 540 queueDraw; |
560 } | 541 } |
561 | 542 |
562 void updateRulers() { | 543 void updateRulers() { |
563 immutable Vector modelSize = pixelToModel(_viewBounds.size); // XXX | 544 immutable Point viewLeftBottom = _pixelModel.pixelToModel(Point(0.0, 0.0)); |
564 immutable Point viewLeftBottom = _viewCentre - modelSize / 2.0; | 545 immutable Point viewRightTop = _pixelModel.pixelToModel(_pixelModel.viewBounds.corner1); |
565 immutable Point viewRightTop = _viewCentre + modelSize / 2.0; | |
566 | 546 |
567 // Define these just to obtain the position | 547 // Define these just to obtain the position |
568 // below and we can preserve it | 548 // below and we can preserve it |
569 double lower, upper, position, maxSize; | 549 double lower, upper, position, maxSize; |
570 | 550 |
571 _hRuler.getRange(lower, upper, position, maxSize); | 551 _hRuler.getRange(lower, upper, position, maxSize); |
572 _hRuler.setRange(viewLeftBottom.x, | 552 _hRuler.setRange(viewLeftBottom.x, |
573 viewRightTop.x, | 553 viewRightTop.x, |
574 position, | 554 position, |
575 _zoom * 50.0); | 555 _pixelModel.zoom * 50.0); |
576 | 556 |
577 _vRuler.getRange(lower, upper, position, maxSize); | 557 _vRuler.getRange(lower, upper, position, maxSize); |
578 _vRuler.setRange(viewRightTop.y, | 558 _vRuler.setRange(viewRightTop.y, |
579 viewLeftBottom.y, | 559 viewLeftBottom.y, |
580 position, | 560 position, |
581 _zoom * 50.0); | 561 _pixelModel.zoom * 50.0); |
582 } | 562 } |
583 | 563 |
584 void updateAdjustments() { | 564 void updateAdjustments() { |
585 immutable Vector modelSize = pixelToModel(_viewBounds.size); // XXX | 565 immutable Point viewLeftBottom = _pixelModel.pixelToModel(Point(0.0, 0.0)); |
586 immutable Point viewLeftBottom = _viewCentre - modelSize / 2.0; | 566 immutable Point viewRightTop = _pixelModel.pixelToModel(_pixelModel.viewBounds.corner1); |
587 immutable Point viewRightTop = _viewCentre + modelSize / 2.0; | 567 |
588 | 568 // Adjust the canvas size if necessary FIXME is this required?? |
589 // Adjust the canvas size if necessary | 569 _pixelModel.canvasAccommodate(Rectangle(viewLeftBottom, viewRightTop)); |
590 _canvasBounds = Rectangle(minExtents(_canvasBounds.corner0, viewLeftBottom), | 570 |
591 maxExtents(_canvasBounds.corner1, viewRightTop)); | 571 // FIXME |
572 Rectangle modelSize = _pixelModel.pixelToModel(_pixelModel.viewBounds); | |
592 | 573 |
593 // Update the adjustments | 574 // Update the adjustments |
594 | 575 |
595 GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct; | 576 GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct; |
596 GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct; | 577 GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct; |
597 | 578 |
598 gtk_adjustment_set_lower(hGtkAdjustment, _canvasBounds.corner0.x); | 579 gtk_adjustment_set_lower(hGtkAdjustment, _pixelModel.canvasBounds.x0); |
599 gtk_adjustment_set_upper(hGtkAdjustment, _canvasBounds.corner1.x); | 580 gtk_adjustment_set_upper(hGtkAdjustment, _pixelModel.canvasBounds.x1); |
600 gtk_adjustment_set_value(hGtkAdjustment, viewLeftBottom.x); | 581 gtk_adjustment_set_value(hGtkAdjustment, viewLeftBottom.x); |
601 gtk_adjustment_set_step_increment(hGtkAdjustment, _canvasBounds.size.x / 16.0); | 582 gtk_adjustment_set_step_increment(hGtkAdjustment, _pixelModel.canvasBounds.w / 16.0); |
602 gtk_adjustment_set_page_increment(hGtkAdjustment, _canvasBounds.size.x / 4.0); | 583 gtk_adjustment_set_page_increment(hGtkAdjustment, _pixelModel.canvasBounds.w / 4.0); |
603 gtk_adjustment_set_page_size(hGtkAdjustment, modelSize.x); | 584 gtk_adjustment_set_page_size(hGtkAdjustment, modelSize.w); |
604 | 585 |
605 gtk_adjustment_set_lower(vGtkAdjustment, _canvasBounds.corner0.y); | 586 gtk_adjustment_set_lower(vGtkAdjustment, _pixelModel.canvasBounds.y0); |
606 gtk_adjustment_set_upper(vGtkAdjustment, _canvasBounds.corner1.y); | 587 gtk_adjustment_set_upper(vGtkAdjustment, _pixelModel.canvasBounds.y1); |
607 gtk_adjustment_set_value(vGtkAdjustment, viewLeftBottom.y); | 588 gtk_adjustment_set_value(vGtkAdjustment, viewLeftBottom.y); |
608 gtk_adjustment_set_step_increment(vGtkAdjustment, _canvasBounds.size.y / 16.0); | 589 gtk_adjustment_set_step_increment(vGtkAdjustment, _pixelModel.canvasBounds.h / 16.0); |
609 gtk_adjustment_set_page_increment(vGtkAdjustment, _canvasBounds.size.y / 4.0); | 590 gtk_adjustment_set_page_increment(vGtkAdjustment, _pixelModel.canvasBounds.h / 4.0); |
610 gtk_adjustment_set_page_size(vGtkAdjustment, modelSize.y); | 591 gtk_adjustment_set_page_size(vGtkAdjustment, modelSize.h); |
611 | 592 |
612 _hAdjustment.changed; | 593 _hAdjustment.changed; |
613 _hAdjustment.valueChanged; | 594 _hAdjustment.valueChanged; |
614 _vAdjustment.changed; | 595 _vAdjustment.changed; |
615 _vAdjustment.valueChanged; | 596 _vAdjustment.valueChanged; |
617 | 598 |
618 void fixDamage() { | 599 void fixDamage() { |
619 if (_damage.valid) { | 600 if (_damage.valid) { |
620 int x, y, w, h; | 601 int x, y, w, h; |
621 _damage.getQuantised(x, y, w, h); | 602 _damage.getQuantised(x, y, w, h); |
622 _drawingArea.queueDrawArea(x, cast(int)_viewBounds.h - (y + h), w, h); | 603 _drawingArea.queueDrawArea(x, cast(int)_pixelModel.viewBounds.h - (y + h), w, h); |
623 _damage = Rectangle.DEFAULT; | 604 _damage = Rectangle.DEFAULT; |
624 } | 605 } |
625 } | 606 } |
626 | 607 |
627 static double clampZoom(in double zoom) { return clamp(zoom, 0.2, 10.0); } | |
628 | |
629 Point modelToPixel(in Point model) const { | |
630 return _viewBounds.centre + _zoom * (model - _viewCentre); | |
631 } | |
632 | |
633 Point pixelToModel(in Point pixel) const { | |
634 return _viewCentre + (pixel - _viewBounds.centre) / _zoom; | |
635 } | |
636 | |
637 Vector modelToPixel(in Vector model) const { | |
638 return _zoom * model; | |
639 } | |
640 | |
641 Vector pixelToModel(in Vector pixel) const { | |
642 return pixel / _zoom; | |
643 } | |
644 | |
645 Rectangle modelToPixel(in Rectangle model) const { | |
646 return Rectangle(modelToPixel(model.position), modelToPixel(model.size)); | |
647 } | |
648 | |
649 Rectangle pixelToModel(in Rectangle model) const { | |
650 return Rectangle(pixelToModel(model.position), pixelToModel(model.size)); | |
651 } | |
652 | |
653 void onRealize(Widget widget) { | 608 void onRealize(Widget widget) { |
654 assert(widget is _drawingArea); | 609 assert(widget is _drawingArea); |
655 //writefln("Got realize\n"); | 610 //writefln("Got realize\n"); |
656 _drawingArea.grabFocus(); | 611 _drawingArea.grabFocus(); |
657 } | 612 } |
658 | 613 |
659 bool _boundsValid; | |
660 Rectangle _damage; // pixels | 614 Rectangle _damage; // pixels |
661 | 615 PixelModel _pixelModel; |
662 // Model units are millimetres | |
663 // Screen units are pixels | |
664 double _zoom; // pixels-per-model-unit | |
665 Rectangle _viewBounds; // pixel: bounds of the viewport in pixels | |
666 Point _viewCentre; // model: where in the model is the centre of our view | |
667 Rectangle _canvasBounds; // model: bounds of the canvas in millimetres | |
668 | 616 |
669 // Child widgets: | 617 // Child widgets: |
670 HRuler _hRuler; | 618 HRuler _hRuler; |
671 VRuler _vRuler; | 619 VRuler _vRuler; |
672 DrawingArea _drawingArea; | 620 DrawingArea _drawingArea; |