Mercurial > projects > doodle
comparison doodle/gtk/cairo_canvas.d @ 136:752676232e4b
Port to GtkD-2.0 (gtk+3)
author | David Bryant <bagnose@gmail.com> |
---|---|
date | Wed, 26 Sep 2012 17:36:31 +0930 |
parents | bc5baa585b32 |
children |
comparison
equal
deleted
inserted
replaced
135:be50d20643a1 | 136:752676232e4b |
---|---|
15 import cairo.Context; | 15 import cairo.Context; |
16 | 16 |
17 import gtk.Widget; | 17 import gtk.Widget; |
18 import gtk.Toolbar; | 18 import gtk.Toolbar; |
19 import gtk.Table; | 19 import gtk.Table; |
20 import gtk.HRuler; | 20 import gtk.Label; |
21 import gtk.VRuler; | 21 alias gtk.Label.Label HRuler; |
22 alias gtk.Label.Label VRuler; | |
22 import gtk.Range; | 23 import gtk.Range; |
23 import gtk.HScrollbar; | 24 import gtk.HScrollbar; |
24 import gtk.VScrollbar; | 25 import gtk.VScrollbar; |
25 import gtk.DrawingArea; | 26 import gtk.DrawingArea; |
26 import gtk.Adjustment; | 27 import gtk.Adjustment; |
27 | 28 |
28 import gdk.Drawable; | |
29 | |
30 import gtkc.gtk; | 29 import gtkc.gtk; |
31 import gtkc.gtktypes; | 30 import gtkc.gtktypes; |
32 //import gtkc.gdktypes; | 31 //import gtkc.gdktypes; |
33 | 32 |
34 import std.math; | 33 import std.math; |
35 import std.stdio; | 34 import std.stdio; |
35 import core.thread; | |
36 } | 36 } |
37 | |
38 // Bring doodle.tk.geometry.Rectangle into local namespace so we | |
39 // get it instead of gdk.Rectangle.Rectangle | |
40 alias doodle.tk.geometry.Rectangle Rectangle; | |
37 | 41 |
38 final class CairoCanvas : Table, IViewport { | 42 final class CairoCanvas : Table, IViewport { |
39 static this() { | 43 static this() { |
40 _cursors = [ | 44 _cursors = [ |
41 Cursor.DEFAULT : CursorType.ARROW, | 45 Cursor.DEFAULT : CursorType.ARROW, |
54 | 58 |
55 _layerStack = new LayerStack(layers); | 59 _layerStack = new LayerStack(layers); |
56 | 60 |
57 // Create our child widgets and register callbacks | 61 // Create our child widgets and register callbacks |
58 | 62 |
59 _hRuler = new HRuler; | 63 _hRuler = new HRuler("horizontal"); |
60 attach(_hRuler, | 64 attach(_hRuler, |
61 1, 2, | 65 1, 2, |
62 0, 1, | 66 0, 1, |
63 AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.SHRINK, | 67 AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.SHRINK, |
64 0, 0); | 68 0, 0); |
65 _hRuler.setMetric(MetricType.PIXELS); | 69 //_hRuler.setMetric(MetricType.PIXELS); |
66 | 70 |
67 _vRuler = new VRuler; | 71 _vRuler = new VRuler("vertical"); |
68 attach(_vRuler, | 72 attach(_vRuler, |
69 0, 1, | 73 0, 1, |
70 1, 2, | 74 1, 2, |
71 AttachOptions.SHRINK, AttachOptions.FILL | AttachOptions.EXPAND, | 75 AttachOptions.SHRINK, AttachOptions.FILL | AttachOptions.EXPAND, |
72 0, 0); | 76 0, 0); |
73 _vRuler.setMetric(MetricType.PIXELS); | 77 //_vRuler.setMetric(MetricType.PIXELS); |
74 | 78 |
75 _drawingArea = new DrawingArea; | 79 _drawingArea = new DrawingArea; |
76 _drawingArea.addOnRealize(&onRealize); | 80 _drawingArea.addOnRealize(&onRealize); |
77 _drawingArea.addOnConfigure(&onConfigure); | 81 _drawingArea.addOnConfigure(&onConfigure); |
78 _drawingArea.addOnExpose(&onExpose); | 82 _drawingArea.addOnDraw(&onDraw); |
79 _drawingArea.addOnButtonPress(&onButtonPress); | 83 _drawingArea.addOnButtonPress(&onButtonPress); |
80 _drawingArea.addOnButtonRelease(&onButtonRelease); | 84 _drawingArea.addOnButtonRelease(&onButtonRelease); |
81 _drawingArea.addOnKeyPress(&onKeyPressEvent); | 85 _drawingArea.addOnKeyPress(&onKeyPressEvent); |
82 _drawingArea.addOnKeyRelease(&onKeyReleaseEvent); | 86 _drawingArea.addOnKeyRelease(&onKeyReleaseEvent); |
83 _drawingArea.addOnMotionNotify(&onMotionNotify); | 87 _drawingArea.addOnMotionNotify(&onMotionNotify); |
92 _drawingArea.addOnGrabFocus(&onGrabFocus); | 96 _drawingArea.addOnGrabFocus(&onGrabFocus); |
93 _drawingArea.addOnGrabNotify(&onGrabNotify); | 97 _drawingArea.addOnGrabNotify(&onGrabNotify); |
94 // addOnPopupMenu | 98 // addOnPopupMenu |
95 // addOnQueryTooltip | 99 // addOnQueryTooltip |
96 // addOnSelection* | 100 // addOnSelection* |
97 _drawingArea.setEvents(EventMask.EXPOSURE_MASK | | 101 _drawingArea.setEvents(EventMask.POINTER_MOTION_MASK | |
98 EventMask.POINTER_MOTION_MASK | | |
99 EventMask.POINTER_MOTION_HINT_MASK | | 102 EventMask.POINTER_MOTION_HINT_MASK | |
100 EventMask.BUTTON_MOTION_MASK | | 103 EventMask.BUTTON_MOTION_MASK | |
101 EventMask.BUTTON_PRESS_MASK | | 104 EventMask.BUTTON_PRESS_MASK | |
102 EventMask.BUTTON_RELEASE_MASK | | 105 EventMask.BUTTON_RELEASE_MASK | |
103 EventMask.KEY_PRESS_MASK | | 106 EventMask.KEY_PRESS_MASK | |
164 void setCursor(in Cursor cursor) { | 167 void setCursor(in Cursor cursor) { |
165 _drawingArea.setCursor(new gdk.Cursor.Cursor(_cursors[cursor])); | 168 _drawingArea.setCursor(new gdk.Cursor.Cursor(_cursors[cursor])); |
166 } | 169 } |
167 | 170 |
168 void damageModel(in Rectangle area) { | 171 void damageModel(in Rectangle area) { |
169 _damageScreen = _damageScreen | _screenModel.modelToScreen(area); | 172 _tmpDamageScreen = _tmpDamageScreen | _screenModel.modelToScreen(area); |
170 } | 173 } |
171 | 174 |
172 void damageScreen(in Rectangle area) { | 175 void damageScreen(in Rectangle area) { |
173 _damageScreen = _damageScreen | area; | 176 _tmpDamageScreen = _tmpDamageScreen | area; |
174 } | 177 } |
175 } | 178 } |
176 | 179 |
177 private { | 180 private { |
178 | 181 |
183 | 186 |
184 updateAdjustments(); | 187 updateAdjustments(); |
185 updateRulers(); | 188 updateRulers(); |
186 } | 189 } |
187 | 190 |
188 bool onConfigure(GdkEventConfigure * event, Widget widget) { | 191 bool onConfigure(gdk.Event.Event event, Widget widget) { |
189 assert(widget is _drawingArea); | 192 assert(widget is _drawingArea); |
190 | 193 |
191 auto viewBoundsScreen = Rectangle(Point(0.0, 0.0), Vector(cast(double)event.width, cast(double)event.height)); | 194 //_surface = ImageSurface.create(CairoFormat.ARGB32, event.configure().width, event.configure().height); |
195 | |
196 auto viewBoundsScreen = Rectangle(Point(0.0, 0.0), Vector(cast(double)event.configure().width, cast(double)event.configure().height)); | |
192 | 197 |
193 if (_screenModel is null) { | 198 if (_screenModel is null) { |
194 Rectangle layerBounds = _layerStack.bounds; | 199 Rectangle layerBounds = _layerStack.bounds; |
195 Rectangle paddedLayerBounds = growCentre(layerBounds, 2 * layerBounds.size); | 200 Rectangle paddedLayerBounds = growCentre(layerBounds, 2 * layerBounds.size); |
196 _screenModel = new ScreenModel(0.25 * _pixelsPerMillimetre, paddedLayerBounds, viewBoundsScreen); | 201 _screenModel = new ScreenModel(0.25 * _pixelsPerMillimetre, paddedLayerBounds, viewBoundsScreen); |
205 } | 210 } |
206 | 211 |
207 return true; | 212 return true; |
208 } | 213 } |
209 | 214 |
210 bool onExpose(GdkEventExpose * event, Widget widget) { | 215 bool onDraw(Context context, Widget widget) { |
211 assert(widget is _drawingArea); | 216 assert(widget is _drawingArea); |
212 | 217 |
213 auto dr = _drawingArea.getWindow(); | 218 double x0, y0, x1, y1; |
214 scope modelCr = new Context(dr); // Causing a memory leak! | 219 context.clipExtents(x0, y0, x1, y1); |
215 scope screenCr = new Context(dr); // Causing a memory leak! | |
216 | |
217 Rectangle screenDamage = | 220 Rectangle screenDamage = |
218 event is null ? _screenModel.viewBoundsScreen : | 221 Rectangle(_screenModel.viewBoundsScreen.position + |
219 Rectangle(_screenModel.viewBoundsScreen.position + Vector(cast(double)event.area.x, _screenModel.viewBoundsScreen.h - cast(double)(event.area.y + event.area.height)), | 222 Vector(x0, _screenModel.viewBoundsScreen.h - y1), |
220 Vector(cast(double)event.area.width, cast(double)event.area.height)); | 223 Vector(x1 - x0, y1 - y0)); |
224 assert(screenDamage.valid); | |
225 | |
226 writefln("External screen damage: %s", screenDamage); | |
227 writefln("Internal screen damage: %s", _internalDamageScreen); | |
228 assert(screenDamage.contains(_internalDamageScreen)); | |
221 | 229 |
222 Rectangle modelDamage = _screenModel.screenToModel(screenDamage); | 230 Rectangle modelDamage = _screenModel.screenToModel(screenDamage); |
231 | |
232 scope Context modelCr = Context.create(context.getTarget()); | |
233 scope Context screenCr = Context.create(context.getTarget()); | |
223 | 234 |
224 modelCr.save(); screenCr.save(); { | 235 modelCr.save(); screenCr.save(); { |
225 { | 236 { |
226 // Setup model context and clip | 237 // Setup model context and clip |
227 modelCr.translate(0.0, _screenModel.viewBoundsScreen.h); | 238 modelCr.translate(0.0, _screenModel.viewBoundsScreen.h); |
249 screenCr.rectangle(screenDamage.x0, screenDamage.y0, screenDamage.w, screenDamage.h); | 260 screenCr.rectangle(screenDamage.x0, screenDamage.y0, screenDamage.w, screenDamage.h); |
250 screenCr.fill(); | 261 screenCr.fill(); |
251 } screenCr.restore(); | 262 } screenCr.restore(); |
252 | 263 |
253 _layerStack.draw(screenDamage, new CairoRenderer(screenCr), | 264 _layerStack.draw(screenDamage, new CairoRenderer(screenCr), |
254 modelDamage, new CairoRenderer(modelCr), | 265 modelDamage, new CairoRenderer(modelCr), |
255 _screenModel); | 266 _screenModel); |
256 } screenCr.restore(); modelCr.restore(); | 267 } screenCr.restore(); screenCr.restore(); |
257 | 268 |
258 return true; | 269 _internalDamageScreen = Rectangle(); |
259 } | 270 |
260 | 271 return true; |
261 bool onButtonPress(GdkEventButton * event, Widget widget) { | 272 } |
262 assert(widget is _drawingArea); | 273 |
263 _eventHandler.handleButtonPress(this, makeButtonEvent(event, _screenModel)); | 274 bool onButtonPress(gdk.Event.Event event, Widget widget) { |
264 fixDamage(); | 275 assert(widget is _drawingArea); |
265 return true; | 276 _eventHandler.handleButtonPress(this, makeButtonEvent(event.button(), _screenModel)); |
266 } | 277 reportDamage(); |
267 | 278 return true; |
268 bool onButtonRelease(GdkEventButton * event, Widget widget) { | 279 } |
269 assert(widget is _drawingArea); | 280 |
270 _eventHandler.handleButtonRelease(this, makeButtonEvent(event, _screenModel)); | 281 bool onButtonRelease(gdk.Event.Event event, Widget widget) { |
271 fixDamage(); | 282 assert(widget is _drawingArea); |
272 return true; | 283 _eventHandler.handleButtonRelease(this, makeButtonEvent(event.button(), _screenModel)); |
273 } | 284 reportDamage(); |
274 | 285 return true; |
275 bool onKeyPressEvent(GdkEventKey * event, Widget widget) { | 286 } |
276 assert(widget is _drawingArea); | 287 |
277 _eventHandler.handleKeyPress(this, makeKeyEvent(event, _screenModel)); | 288 bool onKeyPressEvent(gdk.Event.Event event, Widget widget) { |
278 fixDamage(); | 289 assert(widget is _drawingArea); |
279 return true; | 290 _eventHandler.handleKeyPress(this, makeKeyEvent(event.key(), _screenModel)); |
280 } | 291 reportDamage(); |
281 | 292 return true; |
282 bool onKeyReleaseEvent(GdkEventKey * event, Widget widget) { | 293 } |
283 assert(widget is _drawingArea); | 294 |
284 _eventHandler.handleKeyRelease(this, makeKeyEvent(event, _screenModel)); | 295 bool onKeyReleaseEvent(gdk.Event.Event event, Widget widget) { |
285 fixDamage(); | 296 assert(widget is _drawingArea); |
286 return true; | 297 _eventHandler.handleKeyRelease(this, makeKeyEvent(event.key(), _screenModel)); |
287 } | 298 reportDamage(); |
288 | 299 return true; |
289 bool onMotionNotify(GdkEventMotion * event, Widget widget) { | 300 } |
290 assert(widget is _drawingArea); | 301 |
302 bool onMotionNotify(gdk.Event.Event event, Widget widget) { | |
303 assert(widget is _drawingArea); | |
304 | |
305 if (event.motion().isHint) { | |
306 int x, y; | |
307 GdkModifierType mask; | |
308 _drawingArea.getWindow().getPointer(x, y, mask); | |
309 _eventHandler.handleMotion(this, makeMotionEventHint(x, y, mask, _screenModel)); | |
310 } | |
311 else { | |
312 _eventHandler.handleMotion(this, makeMotionEvent(event.motion(), _screenModel)); | |
313 } | |
314 | |
315 reportDamage(); | |
291 | 316 |
292 // Pass the events on to the rulers so that they update | 317 // Pass the events on to the rulers so that they update |
293 gtk_widget_event(_hRuler.getWidgetStruct(), cast(GdkEvent *)event); | 318 _hRuler.event(event); |
294 gtk_widget_event(_vRuler.getWidgetStruct(), cast(GdkEvent *)event); | 319 _vRuler.event(event); |
295 | 320 |
296 _eventHandler.handleMotion(this, makeMotionEvent(event, _screenModel)); | 321 // Simulate delay in case we were slow to handle the event. |
297 fixDamage(); | 322 // This is really only relevant if we were to do the drawing from inside |
298 return true; | 323 // the handler. ??? |
299 } | 324 Thread.sleep(dur!("msecs")(50)); |
300 | 325 |
301 bool onScroll(GdkEventScroll * event, Widget widget) { | 326 return true; |
302 assert(widget is _drawingArea); | 327 } |
303 _eventHandler.handleScroll(this, makeScrollEvent(event, _screenModel)); | 328 |
304 fixDamage(); | 329 bool onScroll(gdk.Event.Event event, Widget widget) { |
305 return true; | 330 assert(widget is _drawingArea); |
306 } | 331 _eventHandler.handleScroll(this, makeScrollEvent(event.scroll(), _screenModel)); |
307 | 332 reportDamage(); |
308 bool onEnterNotify(GdkEventCrossing * event, Widget widget) { | 333 return true; |
309 assert(widget is _drawingArea); | 334 } |
310 _eventHandler.handleEnter(this, makeCrossingEvent(event, _screenModel)); | 335 |
311 fixDamage(); | 336 bool onEnterNotify(gdk.Event.Event event, Widget widget) { |
312 return true; | 337 assert(widget is _drawingArea); |
313 } | 338 _eventHandler.handleEnter(this, makeCrossingEvent(event.crossing(), _screenModel)); |
314 | 339 reportDamage(); |
315 bool onLeaveNotify(GdkEventCrossing * event, Widget widget) { | 340 return true; |
316 assert(widget is _drawingArea); | 341 } |
317 _eventHandler.handleLeave(this, makeCrossingEvent(event, _screenModel)); | 342 |
318 fixDamage(); | 343 bool onLeaveNotify(gdk.Event.Event event, Widget widget) { |
319 return true; | 344 assert(widget is _drawingArea); |
320 } | 345 _eventHandler.handleLeave(this, makeCrossingEvent(event.crossing(), _screenModel)); |
321 | 346 reportDamage(); |
322 bool onFocusIn(GdkEventFocus * event, Widget widget) { | 347 return true; |
348 } | |
349 | |
350 bool onFocusIn(gdk.Event.Event event, Widget widget) { | |
323 trace("onFocusIn"); | 351 trace("onFocusIn"); |
324 return true; | 352 return true; |
325 } | 353 } |
326 | 354 |
327 bool onFocusOut(GdkEventFocus * event, Widget widget) { | 355 bool onFocusOut(gdk.Event.Event event, Widget widget) { |
328 trace("onFocusOut"); | 356 trace("onFocusOut"); |
329 return true; | 357 return true; |
330 } | 358 } |
331 | 359 |
332 void onMoveFocus(GtkDirectionType direction, Widget widget) { | 360 void onMoveFocus(GtkDirectionType direction, Widget widget) { |
366 | 394 |
367 // Define these just to obtain the position | 395 // Define these just to obtain the position |
368 // below so we can preserve it | 396 // below so we can preserve it |
369 double lower, upper, position, maxSize; | 397 double lower, upper, position, maxSize; |
370 | 398 |
399 /+ | |
371 _hRuler.getRange(lower, upper, position, maxSize); | 400 _hRuler.getRange(lower, upper, position, maxSize); |
372 _hRuler.setRange(viewLeftBottom.x, | 401 _hRuler.setRange(viewLeftBottom.x, |
373 viewRightTop.x, | 402 viewRightTop.x, |
374 position, | 403 position, |
375 _screenModel.zoom * 50.0); | 404 _screenModel.zoom * 50.0); |
377 _vRuler.getRange(lower, upper, position, maxSize); | 406 _vRuler.getRange(lower, upper, position, maxSize); |
378 _vRuler.setRange(viewRightTop.y, | 407 _vRuler.setRange(viewRightTop.y, |
379 viewLeftBottom.y, | 408 viewLeftBottom.y, |
380 position, | 409 position, |
381 _screenModel.zoom * 50.0); | 410 _screenModel.zoom * 50.0); |
411 +/ | |
382 } | 412 } |
383 | 413 |
384 void updateAdjustments() { | 414 void updateAdjustments() { |
385 immutable Point viewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0)); | 415 immutable Point viewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0)); |
386 immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1); | 416 immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1); |
403 _screenModel.canvasBoundsModel.h / 16.0, | 433 _screenModel.canvasBoundsModel.h / 16.0, |
404 _screenModel.canvasBoundsModel.h / 4.0, | 434 _screenModel.canvasBoundsModel.h / 4.0, |
405 _screenModel.viewBoundsModel.h); | 435 _screenModel.viewBoundsModel.h); |
406 } | 436 } |
407 | 437 |
408 void fixDamage() { | 438 void reportDamage() { |
409 if (_damageScreen.valid) { | 439 if (_tmpDamageScreen.valid) { |
410 int x, y, w, h; | 440 int x, y, w, h; |
411 _damageScreen.getQuantised(x, y, w, h); | 441 _tmpDamageScreen.getQuantised(x, y, w, h); |
412 _drawingArea.queueDrawArea(x, cast(int)_screenModel.viewBoundsScreen.h - (y + h), w, h); | 442 _drawingArea.queueDrawArea(x, cast(int)_screenModel.viewBoundsScreen.h - (y + h), w, h); |
413 _damageScreen = Rectangle(); | 443 _internalDamageScreen = _internalDamageScreen | _tmpDamageScreen; |
444 _tmpDamageScreen = Rectangle(); | |
414 } | 445 } |
446 assert(!_tmpDamageScreen.valid); | |
415 } | 447 } |
416 | 448 |
417 void onRealize(Widget widget) { | 449 void onRealize(Widget widget) { |
418 assert(widget is _drawingArea); | 450 assert(widget is _drawingArea); |
419 _drawingArea.grabFocus(); | 451 _drawingArea.grabFocus(); |
431 Adjustment _hAdjustment; | 463 Adjustment _hAdjustment; |
432 HScrollbar _hScrollbar; | 464 HScrollbar _hScrollbar; |
433 Adjustment _vAdjustment; | 465 Adjustment _vAdjustment; |
434 VScrollbar _vScrollbar; | 466 VScrollbar _vScrollbar; |
435 | 467 |
436 Rectangle _damageScreen; | 468 Rectangle _tmpDamageScreen; // accumulated from damageModel and damageScreen calls |
469 Rectangle _internalDamageScreen; // aggregated from _tmpDamageScreen in reportDamage calls | |
437 ScreenModel _screenModel; | 470 ScreenModel _screenModel; |
438 | 471 |
439 static immutable CursorType[Cursor] _cursors; | 472 static immutable CursorType[Cursor] _cursors; |
440 } | 473 } |
441 } | 474 } |