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 }