Mercurial > projects > doodle
annotate doodle/gtk/canvas.d @ 48:1b4c9ba58673
Stylistic overhaul.
author | daveb |
---|---|
date | Tue, 03 Aug 2010 17:37:21 +0930 |
parents | f2e4e1d29b98 |
children | 30ecedfe2ce2 |
rev | line source |
---|---|
28
1754cb773d41
Part-way through getting to compile with configure/builder.
Graham St Jack <graham.stjack@internode.on.net>
parents:
27
diff
changeset
|
1 module doodle.gtk.canvas; |
0 | 2 |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
3 public { |
28
1754cb773d41
Part-way through getting to compile with configure/builder.
Graham St Jack <graham.stjack@internode.on.net>
parents:
27
diff
changeset
|
4 import doodle.dia.icanvas; |
1754cb773d41
Part-way through getting to compile with configure/builder.
Graham St Jack <graham.stjack@internode.on.net>
parents:
27
diff
changeset
|
5 import doodle.tk.events; |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
6 } |
0 | 7 |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
8 private { |
40 | 9 import doodle.core.logging; |
28
1754cb773d41
Part-way through getting to compile with configure/builder.
Graham St Jack <graham.stjack@internode.on.net>
parents:
27
diff
changeset
|
10 import doodle.gtk.conversions; |
1754cb773d41
Part-way through getting to compile with configure/builder.
Graham St Jack <graham.stjack@internode.on.net>
parents:
27
diff
changeset
|
11 import doodle.tk.misc; |
1754cb773d41
Part-way through getting to compile with configure/builder.
Graham St Jack <graham.stjack@internode.on.net>
parents:
27
diff
changeset
|
12 import doodle.cairo.routines; |
0 | 13 |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
14 import cairo.Surface; |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
15 |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
16 import std.math; |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
17 import std.stdio; |
0 | 18 |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
19 import gtk.Widget; |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
20 import gtk.Toolbar; |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
21 import gtk.Table; |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
22 import gtk.HRuler; |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
23 import gtk.VRuler; |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
24 import gtk.Range; |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
25 import gtk.HScrollbar; |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
26 import gtk.VScrollbar; |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
27 import gtk.DrawingArea; |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
28 import gtk.Adjustment; |
0 | 29 |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
30 import gdk.Drawable; |
0 | 31 |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
32 import gtkc.gtk; |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
33 } |
0 | 34 |
35 // x and y run right and up respectively | |
41 | 36 // |
37 // Model units are millimetres. | |
38 // | |
48 | 39 // _zoom -> pixels-per-model-unit |
40 // _viewSize -> size of view window in pixels | |
41 // _viewCentre -> location in model corresponding to centre of view | |
42 // _canvasBounds -> size of the virtual canvas in model coordinates | |
41 | 43 // |
44 // User operations: | |
45 // pan (middle click and drag) | |
46 // zoom about a point (hold control and move scroll wheel) | |
47 // resize the widget | |
0 | 48 |
10 | 49 class Canvas : Table, Viewport { |
48 | 50 this(in Layer[] layers, EventHandler eventHandler, Grid grid, in double ppi) { |
0 | 51 super(3, 3, 0); |
52 | |
48 | 53 _damage = Rectangle.DEFAULT; |
17 | 54 |
48 | 55 _layers = layers.dup; |
56 _eventHandler = eventHandler; | |
57 _grid = grid; | |
58 _ppi = ppi; | |
0 | 59 |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
60 /* |
48 | 61 writefln("Layer bounds: %s", layerBounds); |
62 writefln("Canvas bounds: %s", _canvasBounds); | |
63 writefln("View centre: %s", _viewCentre); | |
64 */ | |
0 | 65 |
13 | 66 // Create our child widgets and register callbacks |
67 | |
40 | 68 info("B1"); |
48 | 69 _hRuler = new HRuler; |
70 attach(_hRuler, | |
0 | 71 1, 2, |
72 0, 1, | |
73 AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.SHRINK, | |
74 0, 0); | |
48 | 75 _hRuler.setMetric(MetricType.PIXELS); |
0 | 76 |
40 | 77 info("B2"); |
48 | 78 _vRuler = new VRuler; |
79 attach(_vRuler, | |
0 | 80 0, 1, |
81 1, 2, | |
82 AttachOptions.SHRINK, AttachOptions.FILL | AttachOptions.EXPAND, | |
83 0, 0); | |
40 | 84 info("B3"); |
48 | 85 _vRuler.setMetric(MetricType.PIXELS); |
40 | 86 info("J"); |
0 | 87 |
48 | 88 _drawingArea = new DrawingArea; |
89 _drawingArea.addOnRealize(&onRealize); | |
90 _drawingArea.addOnConfigure(&onConfigure); | |
91 _drawingArea.addOnExpose(&onExpose); | |
92 _drawingArea.addOnButtonPress(&onButtonPress); | |
93 _drawingArea.addOnButtonRelease(&onButtonRelease); | |
94 _drawingArea.addOnKeyPress(&onKeyEvent); | |
95 _drawingArea.addOnKeyRelease(&onKeyEvent); | |
96 _drawingArea.addOnMotionNotify(&onMotionNotify); | |
97 _drawingArea.addOnScroll(&onScroll); | |
98 _drawingArea.addOnEnterNotify(&onEnterNotify); | |
99 _drawingArea.addOnLeaveNotify(&onLeaveNotify); | |
100 _drawingArea.setEvents(EventMask.EXPOSURE_MASK | | |
20 | 101 EventMask.POINTER_MOTION_MASK | |
102 EventMask.POINTER_MOTION_HINT_MASK | | |
103 EventMask.BUTTON_MOTION_MASK | | |
104 EventMask.BUTTON_PRESS_MASK | | |
105 EventMask.BUTTON_RELEASE_MASK | | |
106 EventMask.KEY_PRESS_MASK | | |
107 EventMask.KEY_RELEASE_MASK | | |
108 EventMask.ENTER_NOTIFY_MASK | | |
109 EventMask.LEAVE_NOTIFY_MASK | | |
110 EventMask.FOCUS_CHANGE_MASK | | |
111 EventMask.SCROLL_MASK); | |
40 | 112 info("M"); |
20 | 113 |
48 | 114 attach(_drawingArea, |
0 | 115 1, 2, |
116 1, 2, | |
117 AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL | AttachOptions.EXPAND, | |
118 0, 0); | |
119 | |
120 // value, lower, upper, step-inc, page-inc, page-size | |
121 // Give the adjustments dummy values until we receive a configure | |
48 | 122 _hAdjustment = new Adjustment(0.0, 0.0, 1.0, 0.2, 0.5, 0.5); |
123 _hAdjustment.addOnValueChanged(&onValueChanged); | |
124 _hScrollbar = new HScrollbar(_hAdjustment); | |
125 _hScrollbar.setInverted(false); | |
126 attach(_hScrollbar, | |
0 | 127 1, 2, |
128 2, 3, | |
129 AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.SHRINK, | |
130 0, 0); | |
40 | 131 info("Q"); |
0 | 132 |
48 | 133 _vAdjustment = new Adjustment(0.0, 0.0, 1.0, 0.2, 0.5, 0.5); |
134 _vAdjustment.addOnValueChanged(&onValueChanged); | |
135 _vScrollbar = new VScrollbar(_vAdjustment); | |
136 _vScrollbar.setInverted(true); | |
137 attach(_vScrollbar, | |
0 | 138 2, 3, |
139 1, 2, | |
140 AttachOptions.SHRINK, | |
141 AttachOptions.FILL | AttachOptions.EXPAND, | |
142 0, 0); | |
143 } | |
144 | |
48 | 145 override void zoomRelative(in Point pixelDatum, in double factor) { |
0 | 146 // Work out pixel distance from current centre to datum, |
147 // Do the zoom, then work out the new centre that keeps the | |
148 // pixel distance the same | |
149 | |
48 | 150 Point oldModelDatum = pixelToModel(pixelDatum); |
151 Vector pixelDistance = modelToPixel(oldModelDatum - _viewCentre); | |
152 _zoom = clampZoom(factor * _zoom); | |
153 _viewCentre = oldModelDatum - pixelToModel(pixelDistance); | |
0 | 154 |
48 | 155 updateAdjustments; |
156 updateRulers; | |
157 _grid.zoomChanged(_zoom); | |
13 | 158 queueDraw; |
0 | 159 } |
160 | |
48 | 161 override void panRelative(in Vector pixelDisplacement) { |
162 _viewCentre = _viewCentre + pixelToModel(pixelDisplacement); | |
0 | 163 |
48 | 164 updateAdjustments; |
165 updateRulers; | |
13 | 166 queueDraw; |
167 } | |
168 | |
48 | 169 override void setCursor(in Cursor cursor) { |
27 | 170 CursorType cursor_type; |
171 | |
172 switch (cursor) { | |
173 case Cursor.DEFAULT: | |
174 cursor_type = CursorType.ARROW; | |
175 break; | |
176 case Cursor.HAND: | |
177 cursor_type = CursorType.HAND1; | |
178 break; | |
179 case Cursor.CROSSHAIR: | |
180 cursor_type = CursorType.CROSSHAIR; | |
181 break; | |
40 | 182 default: |
183 assert(0); | |
27 | 184 } |
185 | |
48 | 186 _drawingArea.setCursor(new gdk.Cursor.Cursor(cursor_type)); |
27 | 187 } |
188 | |
48 | 189 override void damageModel(in Rectangle area) { |
190 _damage = _damage | modelToPixel(area); | |
17 | 191 } |
192 | |
48 | 193 override void damagePixel(in Rectangle area) { |
194 _damage = _damage | area; | |
18 | 195 } |
196 | |
0 | 197 private { |
198 | |
41 | 199 void update_bounds() { |
200 } | |
201 | |
202 | |
48 | 203 bool onConfigure(GdkEventConfigure * event, Widget widget) { |
204 assert(widget is _drawingArea); | |
0 | 205 |
48 | 206 _viewSize = Vector(cast(double)event.width, cast(double)event.height); |
41 | 207 |
48 | 208 Rectangle layerBounds = Rectangle.DEFAULT; |
41 | 209 |
48 | 210 foreach (ref layer; _layers) { |
211 layerBounds = layerBounds | layer.bounds; | |
41 | 212 } |
213 | |
48 | 214 assert(layerBounds.valid); |
41 | 215 |
48 | 216 Rectangle paddedLayerBounds = expand(move(layerBounds, - layerBounds.size), 2.0 * layerBounds.size); |
41 | 217 |
48 | 218 if (!_hadConfigure) { |
41 | 219 info("1"); |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
220 const double MM_PER_INCH = 25.4; |
48 | 221 _zoom = 0.25 * _ppi / MM_PER_INCH; |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
222 |
48 | 223 _canvasBounds = paddedLayerBounds; |
224 _viewCentre = _canvasBounds.centre; | |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
225 |
48 | 226 _grid.zoomChanged(_zoom); |
35 | 227 |
48 | 228 _hadConfigure = true; |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
229 } |
41 | 230 else { |
231 // Use configure events as an opportunity | |
232 // to consolidate the canvas-bounds | |
233 // XXX nasty code. | |
48 | 234 Vector z = _viewSize / _zoom; |
235 Rectangle r = Rectangle(_viewCentre - z / 2.0, z); | |
236 _canvasBounds = r | paddedLayerBounds; | |
41 | 237 } |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
238 |
48 | 239 updateAdjustments; |
240 updateRulers; | |
0 | 241 |
48 | 242 //writefln("Canvas bounds: %s", _canvasBounds); |
243 //writefln("View centre: %s", _viewCentre); | |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
244 |
2
d6f44347373d
* Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents:
0
diff
changeset
|
245 return true; |
0 | 246 } |
247 | |
48 | 248 bool onExpose(GdkEventExpose * event, Widget widget) { |
249 assert(widget is _drawingArea); | |
0 | 250 |
48 | 251 Drawable dr = _drawingArea.getWindow; |
0 | 252 |
253 int width, height; | |
254 dr.getSize(width, height); | |
255 //writefln("Got expose %dx%d\n", width, height); | |
256 | |
48 | 257 scope modelCr = new Context(dr); |
258 scope pixelCr = new Context(dr); | |
12 | 259 |
19 | 260 Rectangle pixel_damage = |
11 | 261 event is null ? |
48 | 262 Rectangle(Point(0.0, 0.0), _viewSize) : |
263 Rectangle(Point(cast(double)event.area.x, _viewSize.y - cast(double)(event.area.y + event.area.height)), | |
11 | 264 Vector(cast(double)event.area.width, cast(double)event.area.height)); |
0 | 265 |
48 | 266 Rectangle model_damage = pixelToModel(pixel_damage); |
19 | 267 |
268 //writefln("Pixel damage: %s, model damage: %s", pixel_damage, model_damage); | |
269 | |
48 | 270 modelCr.save; pixelCr.save; { |
19 | 271 // Setup model context and clip |
12 | 272 |
48 | 273 GtkAdjustment * h_gtkAdjustment = _hAdjustment.getAdjustmentStruct; |
274 GtkAdjustment * v_gtkAdjustment = _vAdjustment.getAdjustmentStruct; | |
12 | 275 |
48 | 276 modelCr.scale(_zoom, -_zoom); |
277 modelCr.translate(-gtk_adjustment_get_value(h_gtkAdjustment), | |
278 -gtk_adjustment_get_value(v_gtkAdjustment) - gtk_adjustment_get_page_size(v_gtkAdjustment)); | |
0 | 279 |
48 | 280 rectangle(modelCr, model_damage); |
281 modelCr.clip; | |
19 | 282 |
283 // Setup pixel context and clip | |
12 | 284 |
48 | 285 pixelCr.translate(0.0, _viewSize.y); |
286 pixelCr.scale(1.0, -1.0); | |
19 | 287 |
48 | 288 rectangle(pixelCr, pixel_damage); |
289 pixelCr.clip; | |
12 | 290 |
291 // Fill the background | |
292 | |
48 | 293 pixelCr.save; { |
11 | 294 // Make the window light grey |
48 | 295 pixelCr.setSourceRgba(0.9, 0.9, 0.9, 1.0); |
296 rectangle(pixelCr, pixel_damage); | |
297 pixelCr.fill; | |
298 } pixelCr.restore; | |
12 | 299 |
300 // Draw each layer | |
0 | 301 |
48 | 302 foreach(ref layer; _layers) { |
303 modelCr.save; pixelCr.save; { | |
304 layer.draw(this, pixel_damage, pixelCr, model_damage, modelCr); | |
305 } pixelCr.restore; modelCr.restore; | |
11 | 306 } |
48 | 307 } pixelCr.restore; modelCr.restore; |
0 | 308 |
2
d6f44347373d
* Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents:
0
diff
changeset
|
309 return true; |
0 | 310 } |
311 | |
48 | 312 bool onButtonPress(GdkEventButton * event, Widget widget) { |
313 assert(widget is _drawingArea); | |
0 | 314 //writefln("Got button event\n"); |
315 | |
48 | 316 Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5)); |
317 Point modelPoint = pixelToModel(pixelPoint); | |
0 | 318 |
48 | 319 auto buttonEvent = new ButtonEvent(gtk2tkButtonAction(event.type), |
320 gtk2tkButtonName(event.button), | |
321 pixelPoint, | |
322 modelPoint, | |
323 gtk2tkMask(event.state)); | |
0 | 324 |
48 | 325 _eventHandler.handleButtonPress(this, buttonEvent); |
5 | 326 |
48 | 327 fixDamage; |
17 | 328 |
5 | 329 return true; |
330 } | |
331 | |
48 | 332 bool onButtonRelease(GdkEventButton * event, Widget widget) { |
333 assert(widget is _drawingArea); | |
5 | 334 //writefln("Got button event\n"); |
335 | |
48 | 336 Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5)); |
337 Point modelPoint = pixelToModel(pixelPoint); | |
5 | 338 |
48 | 339 auto buttonEvent = new ButtonEvent(gtk2tkButtonAction(event.type), |
340 gtk2tkButtonName(event.button), | |
341 pixelPoint, | |
342 modelPoint, | |
343 gtk2tkMask(event.state)); | |
5 | 344 |
48 | 345 _eventHandler.handleButtonRelease(this, buttonEvent); |
0 | 346 |
48 | 347 fixDamage; |
17 | 348 |
2
d6f44347373d
* Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents:
0
diff
changeset
|
349 return true; |
0 | 350 } |
351 | |
48 | 352 bool onKeyEvent(GdkEventKey * event, Widget widget) { |
353 assert(widget is _drawingArea); | |
0 | 354 //writefln("Got key event\n"); |
355 | |
356 //auto key_event = new KeyEvent("", | |
357 // mEventHandle.handle_key(key_event); | |
358 | |
48 | 359 fixDamage; |
17 | 360 |
2
d6f44347373d
* Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents:
0
diff
changeset
|
361 return true; |
0 | 362 } |
363 | |
48 | 364 bool onMotionNotify(GdkEventMotion * event, Widget widget) { |
365 assert(widget is _drawingArea); | |
0 | 366 //writefln("Got motion notify\n"); |
48 | 367 gtk_widget_event(_hRuler.getWidgetStruct(), cast(GdkEvent *)event); |
368 gtk_widget_event(_vRuler.getWidgetStruct(), cast(GdkEvent *)event); | |
0 | 369 |
48 | 370 Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5)); |
371 Point modelPoint = pixelToModel(pixelPoint); | |
0 | 372 |
48 | 373 auto motion_event = new MotionEvent(pixelPoint, |
374 modelPoint, | |
375 gtk2tkMask(event.state)); | |
0 | 376 |
48 | 377 _eventHandler.handleMotion(this, motion_event); |
0 | 378 |
48 | 379 fixDamage; |
17 | 380 |
2
d6f44347373d
* Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents:
0
diff
changeset
|
381 return true; |
0 | 382 } |
383 | |
48 | 384 bool onScroll(GdkEventScroll * event, Widget widget) { |
385 assert(widget is _drawingArea); | |
0 | 386 //writefln("Got scroll\n"); |
387 | |
48 | 388 Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5)); |
389 Point modelPoint = pixelToModel(pixelPoint); | |
0 | 390 |
48 | 391 auto scroll_event = new ScrollEvent(gtk2tkDirection(event.direction), |
392 pixelPoint, | |
393 modelPoint, | |
394 gtk2tkMask(event.state)); | |
0 | 395 |
48 | 396 _eventHandler.handleScroll(this, scroll_event); |
0 | 397 |
48 | 398 fixDamage; |
17 | 399 |
2
d6f44347373d
* Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents:
0
diff
changeset
|
400 return true; |
0 | 401 } |
402 | |
20 | 403 /* |
48 | 404 public enum GdkCrossingMode { |
405 NORMAL, | |
406 GRAB, | |
407 UNGRAB, | |
408 GTK_GRAB, | |
409 GTK_UNGRAB, | |
410 STATE_CHANGED | |
411 } | |
20 | 412 |
48 | 413 public struct GdkEventCrossing { |
414 GdkEventType type; | |
415 GdkWindow *window; | |
416 byte sendEvent; | |
417 GdkWindow *subwindow; | |
418 uint time; | |
419 double x; | |
420 double y; | |
421 double xRoot; | |
422 double yRoot; | |
423 GdkCrossingMode mode; | |
424 GdkNotifyType detail; | |
425 int focus; | |
426 uint state; | |
427 } | |
428 */ | |
20 | 429 |
48 | 430 bool onEnterNotify(GdkEventCrossing * event, Widget widget) { |
431 assert(widget is _drawingArea); | |
27 | 432 //writefln("Enter %d %d %d", cast(int)event.mode, event.focus, event.state); |
433 // TODO | |
20 | 434 return true; |
435 } | |
436 | |
48 | 437 bool onLeaveNotify(GdkEventCrossing * event, Widget widget) { |
438 assert(widget is _drawingArea); | |
27 | 439 //writefln("Leave %d %d %d", cast(int)event.mode, event.focus, event.state); |
440 // TODO | |
20 | 441 return true; |
442 } | |
443 | |
0 | 444 void onValueChanged(Adjustment adjustment) { |
48 | 445 GtkAdjustment * h_gtkAdjustment = _hAdjustment.getAdjustmentStruct; |
446 GtkAdjustment * v_gtkAdjustment = _vAdjustment.getAdjustmentStruct; | |
0 | 447 |
48 | 448 Point viewLeftTop = Point(gtk_adjustment_get_value(h_gtkAdjustment), |
449 gtk_adjustment_get_value(v_gtkAdjustment)); | |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
450 |
48 | 451 Vector modelSize = pixelToModel(_viewSize); |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
452 |
48 | 453 //writefln("%s", viewLeftBottom); |
454 _viewCentre = viewLeftTop + modelSize / 2.0; | |
455 //writefln("onValueChanged _viewCentre: %s", _viewCentre); | |
0 | 456 |
48 | 457 updateRulers; |
0 | 458 |
13 | 459 queueDraw; |
0 | 460 } |
461 | |
48 | 462 void updateRulers() { |
463 invariant Vector modelSize = pixelToModel(_viewSize); | |
0 | 464 |
48 | 465 invariant Point viewLeftBottom = _viewCentre - modelSize / 2.0; |
466 invariant Point viewRightTop = _viewCentre + modelSize / 2.0; | |
0 | 467 |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
468 // Define these just to obtain the position |
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
469 // below and we can preserve it |
48 | 470 double lower, upper, position, maxSize; |
12 | 471 |
48 | 472 _hRuler.getRange(lower, upper, position, maxSize); |
473 _hRuler.setRange(viewLeftBottom.x, | |
474 viewRightTop.x, | |
12 | 475 position, |
48 | 476 _zoom * 50.0); |
12 | 477 |
48 | 478 _vRuler.getRange(lower, upper, position, maxSize); |
479 _vRuler.setRange(viewRightTop.y, | |
480 viewLeftBottom.y, | |
14 | 481 position, |
48 | 482 _zoom * 50.0); |
0 | 483 } |
484 | |
48 | 485 void updateAdjustments() { |
486 invariant Vector modelSize = pixelToModel(_viewSize); | |
0 | 487 |
48 | 488 invariant Point viewLeftBottom = _viewCentre - modelSize / 2.0; |
489 invariant Point viewRightTop = _viewCentre + modelSize / 2.0; | |
0 | 490 |
491 // Adjust the canvas size if necessary | |
48 | 492 _canvasBounds = Rectangle(minExtents(_canvasBounds.minCorner, viewLeftBottom), |
493 maxExtents(_canvasBounds.maxCorner, viewRightTop)); | |
0 | 494 |
495 // Update the adjustments | |
496 | |
48 | 497 GtkAdjustment * h_gtkAdjustment = _hAdjustment.getAdjustmentStruct; |
498 GtkAdjustment * v_gtkAdjustment = _vAdjustment.getAdjustmentStruct; | |
0 | 499 |
48 | 500 gtk_adjustment_set_lower(h_gtkAdjustment, _canvasBounds.minCorner.x); |
501 gtk_adjustment_set_upper(h_gtkAdjustment, _canvasBounds.maxCorner.x); | |
502 gtk_adjustment_set_value(h_gtkAdjustment, viewLeftBottom.x); | |
503 gtk_adjustment_set_step_increment(h_gtkAdjustment, _canvasBounds.size.x / 16.0); | |
504 gtk_adjustment_set_page_increment(h_gtkAdjustment, _canvasBounds.size.x / 4.0); | |
505 gtk_adjustment_set_page_size(h_gtkAdjustment, modelSize.x); | |
0 | 506 |
48 | 507 gtk_adjustment_set_lower(v_gtkAdjustment, _canvasBounds.minCorner.y); |
508 gtk_adjustment_set_upper(v_gtkAdjustment, _canvasBounds.maxCorner.y); | |
509 gtk_adjustment_set_value(v_gtkAdjustment, viewLeftBottom.y); | |
510 gtk_adjustment_set_step_increment(v_gtkAdjustment, _canvasBounds.size.y / 16.0); | |
511 gtk_adjustment_set_page_increment(v_gtkAdjustment, _canvasBounds.size.y / 4.0); | |
512 gtk_adjustment_set_page_size(v_gtkAdjustment, modelSize.y); | |
0 | 513 |
48 | 514 _hAdjustment.changed; |
515 _hAdjustment.valueChanged; | |
516 _vAdjustment.changed; | |
517 _vAdjustment.valueChanged; | |
0 | 518 } |
519 | |
48 | 520 void fixDamage() { |
521 if (_damage.valid) { | |
522 //writefln("Damage: %s", _damage); | |
17 | 523 int x, y, w, h; |
48 | 524 _damage.getQuantised(x, y, w, h); |
525 _drawingArea.queueDrawArea(x, cast(int)_viewSize.y - (y + h), w, h); | |
526 _damage = Rectangle.DEFAULT; | |
17 | 527 } |
528 else { | |
18 | 529 //writefln("No damage"); |
17 | 530 } |
531 } | |
532 | |
48 | 533 double clampZoom(in double zoom) { return clamp(zoom, 0.2, 10.0); } |
16
9e63308b749c
* Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents:
15
diff
changeset
|
534 |
48 | 535 Point modelToPixel(in Point model) const { |
536 return Point.DEFAULT + _viewSize / 2.0 + _zoom * (model - _viewCentre); | |
27 | 537 } |
538 | |
48 | 539 Point pixelToModel(in Point pixel) const { |
540 return _viewCentre + (pixel - _viewSize / 2.0 - Point.DEFAULT) / _zoom; | |
27 | 541 } |
542 | |
48 | 543 Vector modelToPixel(in Vector model) const { |
544 return _zoom * model; | |
27 | 545 } |
546 | |
48 | 547 Vector pixelToModel(in Vector pixel) const { |
548 return pixel / _zoom; | |
27 | 549 } |
550 | |
48 | 551 Rectangle modelToPixel(in Rectangle model) const { |
552 return Rectangle(modelToPixel(model.position), modelToPixel(model.size)); | |
27 | 553 } |
554 | |
48 | 555 Rectangle pixelToModel(in Rectangle model) const { |
556 return Rectangle(pixelToModel(model.position), pixelToModel(model.size)); | |
27 | 557 } |
558 | |
48 | 559 void onRealize(Widget widget) { |
560 assert(widget is _drawingArea); | |
27 | 561 //writefln("Got realize\n"); |
562 } | |
563 | |
48 | 564 bool _hadConfigure; |
565 Rectangle _damage; // pixels | |
0 | 566 |
567 // Model units are in millimetres | |
568 // Screen units are in pixels | |
48 | 569 double _zoom; // pixels-per-model-unit |
570 Vector _viewSize; // pixel: size of view window in pixels | |
571 Point _viewCentre; // model: where in the model is the centre of our view | |
572 Rectangle _canvasBounds; // model: | |
0 | 573 |
10 | 574 // Child widgets: |
48 | 575 HRuler _hRuler; |
576 VRuler _vRuler; | |
577 DrawingArea _drawingArea; | |
578 Adjustment _hAdjustment; | |
579 HScrollbar _hScrollbar; | |
580 Adjustment _vAdjustment; | |
581 VScrollbar _vScrollbar; | |
11 | 582 |
48 | 583 Layer[] _layers; |
584 EventHandler _eventHandler; | |
585 Grid _grid; | |
586 double _ppi; | |
0 | 587 } |
588 } |