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