Mercurial > projects > doodle
comparison doodle/gtk/canvas.d @ 63:20d6327c4a75
Event progress. Got key press/release working and panning via keyboard.
author | daveb |
---|---|
date | Thu, 12 Aug 2010 16:35:24 +0930 |
parents | 6c3993f4c3eb |
children | eb5436b47d13 |
comparison
equal
deleted
inserted
replaced
62:6c3993f4c3eb | 63:20d6327c4a75 |
---|---|
10 import doodle.gtk.conversions; | 10 import doodle.gtk.conversions; |
11 import doodle.tk.misc; | 11 import doodle.tk.misc; |
12 import doodle.cairo.routines; | 12 import doodle.cairo.routines; |
13 | 13 |
14 import cairo.Surface; | 14 import cairo.Surface; |
15 | |
16 import std.math; | |
17 import std.stdio; | |
18 | 15 |
19 import gtk.Widget; | 16 import gtk.Widget; |
20 import gtk.Toolbar; | 17 import gtk.Toolbar; |
21 import gtk.Table; | 18 import gtk.Table; |
22 import gtk.HRuler; | 19 import gtk.HRuler; |
28 import gtk.Adjustment; | 25 import gtk.Adjustment; |
29 | 26 |
30 import gdk.Drawable; | 27 import gdk.Drawable; |
31 | 28 |
32 import gtkc.gtk; | 29 import gtkc.gtk; |
30 import gtkc.gtktypes; | |
31 //import gtkc.gdktypes; | |
32 | |
33 import std.math; | |
34 import std.stdio; | |
35 | |
36 import core.stdc.string : strlen; | |
33 } | 37 } |
34 | 38 |
35 // x and y run right and up respectively | 39 // x and y run right and up respectively |
36 // | 40 // |
37 // Model units are millimetres. | 41 // Model units are millimetres. |
44 // User operations: | 48 // User operations: |
45 // pan (middle click and drag) | 49 // pan (middle click and drag) |
46 // zoom about a point (hold control and move scroll wheel) | 50 // zoom about a point (hold control and move scroll wheel) |
47 // resize the widget | 51 // resize the widget |
48 | 52 |
49 class Canvas : Table, IViewport { | 53 final class Canvas : Table, IViewport { |
50 this(in Layer[] layers, IEventHandler eventHandler, IGrid grid, in double ppi) { | 54 this(in Layer[] layers, IEventHandler eventHandler, IGrid grid, in double ppi) { |
51 super(3, 3, 0); | 55 super(3, 3, 0); |
52 | 56 |
53 _damage = Rectangle.DEFAULT; | 57 _damage = Rectangle.DEFAULT; |
54 | 58 |
83 | 87 |
84 _drawingArea = new DrawingArea; | 88 _drawingArea = new DrawingArea; |
85 _drawingArea.addOnRealize(&onRealize); | 89 _drawingArea.addOnRealize(&onRealize); |
86 _drawingArea.addOnConfigure(&onConfigure); | 90 _drawingArea.addOnConfigure(&onConfigure); |
87 _drawingArea.addOnExpose(&onExpose); | 91 _drawingArea.addOnExpose(&onExpose); |
88 _drawingArea.addOnButtonPress(&onButtonPress); | 92 _drawingArea.addOnButtonPress(&onButtonPress); // FIXME merge delegate with next |
89 _drawingArea.addOnButtonRelease(&onButtonRelease); | 93 _drawingArea.addOnButtonRelease(&onButtonRelease); |
90 _drawingArea.addOnKeyPress(&onKeyEvent); | 94 _drawingArea.addOnKeyPress(&onKeyPressEvent); // FIXME merge delegate with next |
91 _drawingArea.addOnKeyRelease(&onKeyEvent); | 95 _drawingArea.addOnKeyRelease(&onKeyReleaseEvent); |
92 _drawingArea.addOnMotionNotify(&onMotionNotify); | 96 _drawingArea.addOnMotionNotify(&onMotionNotify); |
93 _drawingArea.addOnScroll(&onScroll); | 97 _drawingArea.addOnScroll(&onScroll); |
94 _drawingArea.addOnEnterNotify(&onEnterNotify); | 98 _drawingArea.addOnEnterNotify(&onEnterNotify); // FIXME merge delegate with next |
95 _drawingArea.addOnLeaveNotify(&onLeaveNotify); | 99 _drawingArea.addOnLeaveNotify(&onLeaveNotify); |
100 | |
101 _drawingArea.addOnFocusIn(&onFocusIn); | |
102 _drawingArea.addOnFocusOut(&onFocusOut); | |
103 _drawingArea.addOnMoveFocus(&onMoveFocus); | |
104 /* | |
105 _drawingArea.addOnGrabBroken(&onGrabBroken); | |
106 */ | |
107 _drawingArea.addOnGrabFocus(&onGrabFocus); | |
108 _drawingArea.addOnGrabNotify(&onGrabNotify); | |
109 // addOnPopupMenu | |
110 // addOnQueryTooltip | |
111 // addOnSelection* | |
96 _drawingArea.setEvents(EventMask.EXPOSURE_MASK | | 112 _drawingArea.setEvents(EventMask.EXPOSURE_MASK | |
97 EventMask.POINTER_MOTION_MASK | | 113 EventMask.POINTER_MOTION_MASK | |
98 EventMask.POINTER_MOTION_HINT_MASK | | 114 EventMask.POINTER_MOTION_HINT_MASK | |
99 EventMask.BUTTON_MOTION_MASK | | 115 EventMask.BUTTON_MOTION_MASK | |
100 EventMask.BUTTON_PRESS_MASK | | 116 EventMask.BUTTON_PRESS_MASK | |
104 EventMask.ENTER_NOTIFY_MASK | | 120 EventMask.ENTER_NOTIFY_MASK | |
105 EventMask.LEAVE_NOTIFY_MASK | | 121 EventMask.LEAVE_NOTIFY_MASK | |
106 EventMask.FOCUS_CHANGE_MASK | | 122 EventMask.FOCUS_CHANGE_MASK | |
107 EventMask.SCROLL_MASK); | 123 EventMask.SCROLL_MASK); |
108 | 124 |
125 _drawingArea.setCanFocus(true); | |
126 | |
109 attach(_drawingArea, | 127 attach(_drawingArea, |
110 1, 2, | 128 1, 2, |
111 1, 2, | 129 1, 2, |
112 AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL | AttachOptions.EXPAND, | 130 AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL | AttachOptions.EXPAND, |
113 0, 0); | 131 0, 0); |
119 _hScrollbar = new HScrollbar(_hAdjustment); | 137 _hScrollbar = new HScrollbar(_hAdjustment); |
120 _hScrollbar.setInverted(false); | 138 _hScrollbar.setInverted(false); |
121 attach(_hScrollbar, | 139 attach(_hScrollbar, |
122 1, 2, | 140 1, 2, |
123 2, 3, | 141 2, 3, |
124 AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.SHRINK, | 142 AttachOptions.FILL | AttachOptions.EXPAND, |
143 AttachOptions.SHRINK, | |
125 0, 0); | 144 0, 0); |
126 | 145 |
127 _vAdjustment = new Adjustment(0.0, 0.0, 1.0, 0.2, 0.5, 0.5); | 146 _vAdjustment = new Adjustment(0.0, 0.0, 1.0, 0.2, 0.5, 0.5); |
128 _vAdjustment.addOnValueChanged(&onValueChanged); | 147 _vAdjustment.addOnValueChanged(&onValueChanged); |
129 _vScrollbar = new VScrollbar(_vAdjustment); | 148 _vScrollbar = new VScrollbar(_vAdjustment); |
136 0, 0); | 155 0, 0); |
137 } | 156 } |
138 | 157 |
139 // IViewport overrides: | 158 // IViewport overrides: |
140 | 159 |
141 override void zoomRelative(in Point pixelDatum, in double factor) { | 160 void zoomRelative(in Point pixelDatum, in double factor) { |
142 // Work out pixel distance from current centre to datum, | 161 // Work out pixel distance from current centre to datum, |
143 // Do the zoom, then work out the new centre that keeps the | 162 // Do the zoom, then work out the new centre that keeps the |
144 // pixel distance the same | 163 // pixel distance the same |
145 | 164 |
146 Point oldModelDatum = pixelToModel(pixelDatum); | 165 Point oldModelDatum = pixelToModel(pixelDatum); |
147 Vector pixelDistance = modelToPixel(oldModelDatum - _viewCentre); | 166 Vector pixelDistance = modelToPixel(oldModelDatum - _viewCentre); |
148 _zoom = clampZoom(factor * _zoom); | 167 _zoom = clampZoom(factor * _zoom); |
149 _viewCentre = oldModelDatum - pixelToModel(pixelDistance); | 168 _viewCentre = oldModelDatum - pixelToModel(pixelDistance); |
169 | |
170 consolidateBounds; | |
150 | 171 |
151 updateAdjustments; | 172 updateAdjustments; |
152 updateRulers; | 173 updateRulers; |
153 _grid.zoomChanged(_zoom); | 174 _grid.zoomChanged(_zoom); |
154 queueDraw; | 175 queueDraw; |
155 } | 176 } |
156 | 177 |
157 override void panRelative(in Vector pixelDisplacement) { | 178 void panRelative(in Vector pixelDisplacement) { |
158 _viewCentre = _viewCentre + pixelToModel(pixelDisplacement); | 179 _viewCentre = _viewCentre + pixelToModel(pixelDisplacement); |
180 | |
181 consolidateBounds; | |
159 | 182 |
160 updateAdjustments; | 183 updateAdjustments; |
161 updateRulers; | 184 updateRulers; |
162 queueDraw; | 185 queueDraw; |
163 } | 186 } |
164 | 187 |
165 override void setCursor(in Cursor cursor) { | 188 void setCursor(in Cursor cursor) { |
166 CursorType cursor_type; | 189 CursorType cursorType; |
167 | 190 |
168 switch (cursor) { | 191 switch (cursor) { |
169 case Cursor.DEFAULT: | 192 case Cursor.DEFAULT: |
170 cursor_type = CursorType.ARROW; | 193 cursorType = CursorType.ARROW; |
171 break; | 194 break; |
172 case Cursor.HAND: | 195 case Cursor.HAND: |
173 cursor_type = CursorType.HAND1; | 196 cursorType = CursorType.HAND1; |
174 break; | 197 break; |
175 case Cursor.CROSSHAIR: | 198 case Cursor.CROSSHAIR: |
176 cursor_type = CursorType.CROSSHAIR; | 199 cursorType = CursorType.CROSSHAIR; |
200 break; | |
201 case Cursor.PENCIL: | |
202 cursorType = CursorType.PENCIL; | |
177 break; | 203 break; |
178 default: | 204 default: |
179 assert(0); | 205 assert(0); |
180 } | 206 } |
181 | 207 |
182 _drawingArea.setCursor(new gdk.Cursor.Cursor(cursor_type)); | 208 _drawingArea.setCursor(new gdk.Cursor.Cursor(cursorType)); |
183 } | 209 } |
184 | 210 |
185 override void damageModel(in Rectangle area) { | 211 void damageModel(in Rectangle area) { |
186 _damage = _damage | modelToPixel(area); | 212 _damage = _damage | modelToPixel(area); |
187 } | 213 } |
188 | 214 |
189 override void damagePixel(in Rectangle area) { | 215 void damagePixel(in Rectangle area) { |
190 _damage = _damage | area; | 216 _damage = _damage | area; |
191 } | 217 } |
192 | 218 |
193 private { | 219 private { |
194 | 220 |
195 void initialise() { | 221 void initialiseBounds() { |
196 Rectangle layerBounds = Rectangle.DEFAULT; | 222 Rectangle layerBounds = Rectangle.DEFAULT; |
197 | 223 |
198 foreach (ref layer; _layers) { | 224 foreach (ref layer; _layers) { |
199 layerBounds = layerBounds | layer.bounds; | 225 layerBounds = layerBounds | layer.bounds; |
200 } | 226 } |
201 | 227 |
202 assert(layerBounds.valid); | 228 assert(layerBounds.valid); |
203 | 229 |
230 // FIXME use a function that grows a rectangle about its centre | |
231 // and change 2.0 to a class-level constant | |
204 Rectangle paddedLayerBounds = expand(move(layerBounds, - layerBounds.size), 2.0 * layerBounds.size); | 232 Rectangle paddedLayerBounds = expand(move(layerBounds, - layerBounds.size), 2.0 * layerBounds.size); |
205 | 233 |
206 // | 234 // |
207 | 235 |
208 const double MM_PER_INCH = 25.4; | |
209 _zoom = 0.25 * _ppi / MM_PER_INCH; | 236 _zoom = 0.25 * _ppi / MM_PER_INCH; |
210 | 237 |
211 _canvasBounds = paddedLayerBounds; | 238 _canvasBounds = paddedLayerBounds; |
212 _viewCentre = _canvasBounds.centre; | 239 _viewCentre = _canvasBounds.centre; |
213 | 240 |
239 bool onConfigure(GdkEventConfigure * event, Widget widget) { | 266 bool onConfigure(GdkEventConfigure * event, Widget widget) { |
240 assert(widget is _drawingArea); | 267 assert(widget is _drawingArea); |
241 | 268 |
242 _viewSize = Vector(cast(double)event.width, cast(double)event.height); | 269 _viewSize = Vector(cast(double)event.width, cast(double)event.height); |
243 | 270 |
244 | 271 if (!_boundsValid) { |
245 if (!_hadConfigure) { | 272 initialiseBounds; |
246 initialise; | 273 _boundsValid = true; |
247 _hadConfigure = true; | |
248 } | 274 } |
249 else { | 275 else { |
250 consolidateBounds; | 276 consolidateBounds; |
251 } | 277 } |
252 | 278 |
258 | 284 |
259 Drawable dr = _drawingArea.getWindow; | 285 Drawable dr = _drawingArea.getWindow; |
260 | 286 |
261 int width, height; | 287 int width, height; |
262 dr.getSize(width, height); | 288 dr.getSize(width, height); |
263 trace("Got expose %dx%d\n", width, height); | 289 //trace("Got expose %dx%d\n", width, height); |
264 | 290 |
265 scope modelCr = new Context(dr); | 291 scope modelCr = new Context(dr); |
266 scope pixelCr = new Context(dr); | 292 scope pixelCr = new Context(dr); |
267 | 293 |
268 Rectangle pixel_damage = | 294 Rectangle pixelDamage = |
269 event is null ? | 295 event is null ? |
270 Rectangle(Point(0.0, 0.0), _viewSize) : | 296 Rectangle(Point(0.0, 0.0), _viewSize) : |
271 Rectangle(Point(cast(double)event.area.x, _viewSize.y - cast(double)(event.area.y + event.area.height)), | 297 Rectangle(Point(cast(double)event.area.x, _viewSize.y - cast(double)(event.area.y + event.area.height)), |
272 Vector(cast(double)event.area.width, cast(double)event.area.height)); | 298 Vector(cast(double)event.area.width, cast(double)event.area.height)); |
273 | 299 |
274 Rectangle model_damage = pixelToModel(pixel_damage); | 300 Rectangle modelDamage = pixelToModel(pixelDamage); |
275 | 301 |
276 //trace("Pixel damage: %s, model damage: %s", pixel_damage, model_damage); | 302 //trace("Pixel damage: %s, model damage: %s", pixelDamage, modelDamage); |
277 | 303 |
278 modelCr.save; pixelCr.save; { | 304 modelCr.save; pixelCr.save; { |
279 // Setup model context and clip | 305 // Setup model context and clip |
280 | 306 |
281 GtkAdjustment * h_gtkAdjustment = _hAdjustment.getAdjustmentStruct; | 307 GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct; |
282 GtkAdjustment * v_gtkAdjustment = _vAdjustment.getAdjustmentStruct; | 308 GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct; |
283 | 309 |
284 modelCr.scale(_zoom, -_zoom); | 310 modelCr.scale(_zoom, -_zoom); |
285 modelCr.translate(-gtk_adjustment_get_value(h_gtkAdjustment), | 311 modelCr.translate(-gtk_adjustment_get_value(hGtkAdjustment), |
286 -gtk_adjustment_get_value(v_gtkAdjustment) - gtk_adjustment_get_page_size(v_gtkAdjustment)); | 312 -gtk_adjustment_get_value(vGtkAdjustment) - gtk_adjustment_get_page_size(vGtkAdjustment)); |
287 | 313 |
288 rectangle(modelCr, model_damage); | 314 rectangle(modelCr, modelDamage); |
289 modelCr.clip; | 315 modelCr.clip; |
290 | 316 |
291 // Setup pixel context and clip | 317 // Setup pixel context and clip |
292 | 318 |
293 pixelCr.translate(0.0, _viewSize.y); | 319 pixelCr.translate(0.0, _viewSize.y); |
294 pixelCr.scale(1.0, -1.0); | 320 pixelCr.scale(1.0, -1.0); |
295 | 321 |
296 rectangle(pixelCr, pixel_damage); | 322 rectangle(pixelCr, pixelDamage); |
297 pixelCr.clip; | 323 pixelCr.clip; |
298 | 324 |
299 // Fill the background | 325 // Fill the background |
300 | 326 |
301 pixelCr.save; { | 327 pixelCr.save; { |
302 // Make the window light grey | 328 // Make the window light grey |
303 pixelCr.setSourceRgba(0.9, 0.9, 0.9, 1.0); | 329 pixelCr.setSourceRgba(0.9, 0.9, 0.9, 1.0); |
304 rectangle(pixelCr, pixel_damage); | 330 rectangle(pixelCr, pixelDamage); |
305 pixelCr.fill; | 331 pixelCr.fill; |
306 } pixelCr.restore; | 332 } pixelCr.restore; |
307 | 333 |
308 // Draw each layer | 334 // Draw each layer |
309 | 335 |
310 foreach(ref layer; _layers) { | 336 foreach(ref layer; _layers) { |
311 modelCr.save; pixelCr.save; { | 337 modelCr.save; pixelCr.save; { |
312 layer.draw(this, pixel_damage, pixelCr, model_damage, modelCr); | 338 layer.draw(this, pixelDamage, pixelCr, modelDamage, modelCr); |
313 } pixelCr.restore; modelCr.restore; | 339 } pixelCr.restore; modelCr.restore; |
314 } | 340 } |
315 } pixelCr.restore; modelCr.restore; | 341 } pixelCr.restore; modelCr.restore; |
316 | 342 |
317 return true; | 343 return true; |
318 } | 344 } |
319 | 345 |
320 bool onButtonPress(GdkEventButton * event, Widget widget) { | 346 bool onButtonPress(GdkEventButton * event, Widget widget) { |
321 assert(widget is _drawingArea); | 347 assert(widget is _drawingArea); |
322 trace("Got button event\n"); | 348 //trace("Got button event\n"); |
323 | 349 |
324 Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5)); | 350 Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5)); |
325 Point modelPoint = pixelToModel(pixelPoint); | 351 Point modelPoint = pixelToModel(pixelPoint); |
326 | 352 |
327 auto buttonEvent = new ButtonEvent(gtk2tkButtonAction(event.type), | 353 auto buttonEvent = new ButtonEvent(gtk2tkButtonAction(event.type), |
354 fixDamage; | 380 fixDamage; |
355 | 381 |
356 return true; | 382 return true; |
357 } | 383 } |
358 | 384 |
359 bool onKeyEvent(GdkEventKey * event, Widget widget) { | 385 /* |
360 assert(widget is _drawingArea); | 386 public struct GdkEventKey { |
361 //writefln("Got key event\n"); | 387 GdkEventType type; |
362 | 388 GdkWindow *window; |
363 //auto key_event = new KeyEvent("", | 389 byte sendEvent; |
364 // mEventHandle.handle_key(key_event); | 390 uint time; |
391 uint state; | |
392 uint keyval; | |
393 int length; | |
394 char *string; | |
395 ushort hardwareKeycode; | |
396 ubyte group; | |
397 uint bitfield0; | |
398 //uint isModifier : 1; | |
399 } | |
400 */ | |
401 bool onKeyPressEvent(GdkEventKey * event, Widget widget) { | |
402 assert(widget is _drawingArea); | |
403 message("Got key event"); | |
404 | |
405 auto keyEvent = new KeyEvent(event.string[0..strlen(event.string)].idup, | |
406 event.keyval, | |
407 gtk2tkMask(event.state)); | |
408 message("Got key press %s", keyEvent); | |
409 _eventHandler.handleKeyPress(this, keyEvent); | |
410 | |
411 fixDamage; | |
412 | |
413 return true; | |
414 } | |
415 | |
416 bool onKeyReleaseEvent(GdkEventKey * event, Widget widget) { | |
417 assert(widget is _drawingArea); | |
418 | |
419 auto keyEvent = new KeyEvent(event.string[0..strlen(event.string)].idup, | |
420 event.keyval, | |
421 gtk2tkMask(event.state)); | |
422 message("Got key release %s", keyEvent); | |
423 _eventHandler.handleKeyRelease(this, keyEvent); | |
365 | 424 |
366 fixDamage; | 425 fixDamage; |
367 | 426 |
368 return true; | 427 return true; |
369 } | 428 } |
375 gtk_widget_event(_vRuler.getWidgetStruct(), cast(GdkEvent *)event); | 434 gtk_widget_event(_vRuler.getWidgetStruct(), cast(GdkEvent *)event); |
376 | 435 |
377 Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5)); | 436 Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5)); |
378 Point modelPoint = pixelToModel(pixelPoint); | 437 Point modelPoint = pixelToModel(pixelPoint); |
379 | 438 |
380 auto motion_event = new MotionEvent(pixelPoint, | 439 auto motionEvent = new MotionEvent(pixelPoint, |
381 modelPoint, | 440 modelPoint, |
382 gtk2tkMask(event.state)); | 441 gtk2tkMask(event.state)); |
383 | 442 |
384 _eventHandler.handleMotion(this, motion_event); | 443 _eventHandler.handleMotion(this, motionEvent); |
385 | 444 |
386 fixDamage; | 445 fixDamage; |
387 | 446 |
388 return true; | 447 return true; |
389 } | 448 } |
393 //writefln("Got scroll\n"); | 452 //writefln("Got scroll\n"); |
394 | 453 |
395 Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5)); | 454 Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5)); |
396 Point modelPoint = pixelToModel(pixelPoint); | 455 Point modelPoint = pixelToModel(pixelPoint); |
397 | 456 |
398 auto scroll_event = new ScrollEvent(gtk2tkDirection(event.direction), | 457 auto scrollEvent = new ScrollEvent(gtk2tkDirection(event.direction), |
399 pixelPoint, | 458 pixelPoint, |
400 modelPoint, | 459 modelPoint, |
401 gtk2tkMask(event.state)); | 460 gtk2tkMask(event.state)); |
402 | 461 |
403 _eventHandler.handleScroll(this, scroll_event); | 462 _eventHandler.handleScroll(this, scrollEvent); |
404 | 463 |
405 fixDamage; | 464 fixDamage; |
406 | 465 |
407 return true; | 466 return true; |
408 } | 467 } |
434 } | 493 } |
435 */ | 494 */ |
436 | 495 |
437 bool onEnterNotify(GdkEventCrossing * event, Widget widget) { | 496 bool onEnterNotify(GdkEventCrossing * event, Widget widget) { |
438 assert(widget is _drawingArea); | 497 assert(widget is _drawingArea); |
439 //writefln("Enter %d %d %d", cast(int)event.mode, event.focus, event.state); | 498 message("Enter %d %d %d", cast(int)event.mode, event.focus, event.state); |
440 // TODO | 499 // TODO |
441 return true; | 500 return true; |
442 } | 501 } |
443 | 502 |
444 bool onLeaveNotify(GdkEventCrossing * event, Widget widget) { | 503 bool onLeaveNotify(GdkEventCrossing * event, Widget widget) { |
445 assert(widget is _drawingArea); | 504 assert(widget is _drawingArea); |
446 //writefln("Leave %d %d %d", cast(int)event.mode, event.focus, event.state); | 505 message("Leave %d %d %d", cast(int)event.mode, event.focus, event.state); |
447 // TODO | 506 // TODO |
448 return true; | 507 return true; |
449 } | 508 } |
450 | 509 |
510 /* | |
511 public struct GdkEventFocus { | |
512 GdkEventType type; | |
513 GdkWindow *window; | |
514 byte sendEvent; | |
515 short inn; | |
516 } | |
517 */ | |
518 bool onFocusIn(GdkEventFocus * event, Widget widget) { | |
519 trace("onFocusIn"); | |
520 return true; | |
521 } | |
522 | |
523 bool onFocusOut(GdkEventFocus * event, Widget widget) { | |
524 trace("onFocusOut"); | |
525 return true; | |
526 } | |
527 | |
528 void onMoveFocus(GtkDirectionType direction, Widget widget) { | |
529 trace("onMoveFocus"); | |
530 } | |
531 | |
532 /* | |
533 bool onGrabBroken(Event event, Widget widget) { | |
534 trace("onGrabBroken"); | |
535 return true; | |
536 } | |
537 */ | |
538 | |
539 void onGrabFocus(Widget widget) { | |
540 trace("onGrabFocus"); | |
541 } | |
542 | |
543 void onGrabNotify(gboolean what, Widget widget){ | |
544 trace("onGrabNotify"); | |
545 } | |
546 | |
451 void onValueChanged(Adjustment adjustment) { | 547 void onValueChanged(Adjustment adjustment) { |
452 GtkAdjustment * h_gtkAdjustment = _hAdjustment.getAdjustmentStruct; | 548 GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct; |
453 GtkAdjustment * v_gtkAdjustment = _vAdjustment.getAdjustmentStruct; | 549 GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct; |
454 | 550 |
455 Point viewLeftTop = Point(gtk_adjustment_get_value(h_gtkAdjustment), | 551 Point viewLeftTop = Point(gtk_adjustment_get_value(hGtkAdjustment), |
456 gtk_adjustment_get_value(v_gtkAdjustment)); | 552 gtk_adjustment_get_value(vGtkAdjustment)); |
457 | 553 |
458 Vector modelSize = pixelToModel(_viewSize); | 554 Vector modelSize = pixelToModel(_viewSize); |
459 | 555 |
460 //writefln("%s", viewLeftBottom); | 556 //writefln("%s", viewLeftBottom); |
461 _viewCentre = viewLeftTop + modelSize / 2.0; | 557 _viewCentre = viewLeftTop + modelSize / 2.0; |
499 _canvasBounds = Rectangle(minExtents(_canvasBounds.minCorner, viewLeftBottom), | 595 _canvasBounds = Rectangle(minExtents(_canvasBounds.minCorner, viewLeftBottom), |
500 maxExtents(_canvasBounds.maxCorner, viewRightTop)); | 596 maxExtents(_canvasBounds.maxCorner, viewRightTop)); |
501 | 597 |
502 // Update the adjustments | 598 // Update the adjustments |
503 | 599 |
504 GtkAdjustment * h_gtkAdjustment = _hAdjustment.getAdjustmentStruct; | 600 GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct; |
505 GtkAdjustment * v_gtkAdjustment = _vAdjustment.getAdjustmentStruct; | 601 GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct; |
506 | 602 |
507 gtk_adjustment_set_lower(h_gtkAdjustment, _canvasBounds.minCorner.x); | 603 gtk_adjustment_set_lower(hGtkAdjustment, _canvasBounds.minCorner.x); |
508 gtk_adjustment_set_upper(h_gtkAdjustment, _canvasBounds.maxCorner.x); | 604 gtk_adjustment_set_upper(hGtkAdjustment, _canvasBounds.maxCorner.x); |
509 gtk_adjustment_set_value(h_gtkAdjustment, viewLeftBottom.x); | 605 gtk_adjustment_set_value(hGtkAdjustment, viewLeftBottom.x); |
510 gtk_adjustment_set_step_increment(h_gtkAdjustment, _canvasBounds.size.x / 16.0); | 606 gtk_adjustment_set_step_increment(hGtkAdjustment, _canvasBounds.size.x / 16.0); |
511 gtk_adjustment_set_page_increment(h_gtkAdjustment, _canvasBounds.size.x / 4.0); | 607 gtk_adjustment_set_page_increment(hGtkAdjustment, _canvasBounds.size.x / 4.0); |
512 gtk_adjustment_set_page_size(h_gtkAdjustment, modelSize.x); | 608 gtk_adjustment_set_page_size(hGtkAdjustment, modelSize.x); |
513 | 609 |
514 gtk_adjustment_set_lower(v_gtkAdjustment, _canvasBounds.minCorner.y); | 610 gtk_adjustment_set_lower(vGtkAdjustment, _canvasBounds.minCorner.y); |
515 gtk_adjustment_set_upper(v_gtkAdjustment, _canvasBounds.maxCorner.y); | 611 gtk_adjustment_set_upper(vGtkAdjustment, _canvasBounds.maxCorner.y); |
516 gtk_adjustment_set_value(v_gtkAdjustment, viewLeftBottom.y); | 612 gtk_adjustment_set_value(vGtkAdjustment, viewLeftBottom.y); |
517 gtk_adjustment_set_step_increment(v_gtkAdjustment, _canvasBounds.size.y / 16.0); | 613 gtk_adjustment_set_step_increment(vGtkAdjustment, _canvasBounds.size.y / 16.0); |
518 gtk_adjustment_set_page_increment(v_gtkAdjustment, _canvasBounds.size.y / 4.0); | 614 gtk_adjustment_set_page_increment(vGtkAdjustment, _canvasBounds.size.y / 4.0); |
519 gtk_adjustment_set_page_size(v_gtkAdjustment, modelSize.y); | 615 gtk_adjustment_set_page_size(vGtkAdjustment, modelSize.y); |
520 | 616 |
521 _hAdjustment.changed; | 617 _hAdjustment.changed; |
522 _hAdjustment.valueChanged; | 618 _hAdjustment.valueChanged; |
523 _vAdjustment.changed; | 619 _vAdjustment.changed; |
524 _vAdjustment.valueChanged; | 620 _vAdjustment.valueChanged; |
525 } | 621 } |
526 | 622 |
527 void fixDamage() { | 623 void fixDamage() { |
528 if (_damage.valid) { | 624 if (_damage.valid) { |
529 //writefln("Damage: %s", _damage); | |
530 int x, y, w, h; | 625 int x, y, w, h; |
531 _damage.getQuantised(x, y, w, h); | 626 _damage.getQuantised(x, y, w, h); |
532 _drawingArea.queueDrawArea(x, cast(int)_viewSize.y - (y + h), w, h); | 627 _drawingArea.queueDrawArea(x, cast(int)_viewSize.y - (y + h), w, h); |
533 _damage = Rectangle.DEFAULT; | 628 _damage = Rectangle.DEFAULT; |
534 } | 629 } |
535 else { | 630 } |
536 //writefln("No damage"); | 631 |
537 } | 632 static double clampZoom(in double zoom) { return clamp(zoom, 0.2, 10.0); } |
538 } | |
539 | |
540 double clampZoom(in double zoom) { return clamp(zoom, 0.2, 10.0); } | |
541 | 633 |
542 Point modelToPixel(in Point model) const { | 634 Point modelToPixel(in Point model) const { |
543 return Point.DEFAULT + _viewSize / 2.0 + _zoom * (model - _viewCentre); | 635 return Point.DEFAULT + _viewSize / 2.0 + _zoom * (model - _viewCentre); |
544 } | 636 } |
545 | 637 |
564 } | 656 } |
565 | 657 |
566 void onRealize(Widget widget) { | 658 void onRealize(Widget widget) { |
567 assert(widget is _drawingArea); | 659 assert(widget is _drawingArea); |
568 //writefln("Got realize\n"); | 660 //writefln("Got realize\n"); |
569 } | 661 _drawingArea.grabFocus(); |
570 | 662 } |
571 bool _hadConfigure; | 663 |
664 bool _boundsValid; | |
572 Rectangle _damage; // pixels | 665 Rectangle _damage; // pixels |
573 | 666 |
574 // Model units are in millimetres | 667 // Model units are in millimetres |
575 // Screen units are in pixels | 668 // Screen units are in pixels |
576 double _zoom; // pixels-per-model-unit | 669 double _zoom; // pixels-per-model-unit |
589 | 682 |
590 Layer[] _layers; | 683 Layer[] _layers; |
591 IEventHandler _eventHandler; | 684 IEventHandler _eventHandler; |
592 IGrid _grid; | 685 IGrid _grid; |
593 double _ppi; | 686 double _ppi; |
687 | |
688 static immutable MM_PER_INCH = 25.4; | |
594 } | 689 } |
595 } | 690 } |