comparison doodle/gtk/cairo_canvas.d @ 83:06b4504cbcb0

Checkpoint of trying to get a different renderer going (OpenGL)
author daveb
date Mon, 16 Aug 2010 17:16:36 +0930
parents doodle/gtk/canvas.d@0314b2e03f9b
children cdd4fc728d94
comparison
equal deleted inserted replaced
82:0314b2e03f9b 83:06b4504cbcb0
1 module doodle.gtk.cairo_canvas;
2
3 public {
4 import doodle.dia.icanvas;
5 import doodle.gtk.events;
6 }
7
8 private {
9 import doodle.core.logging;
10 import doodle.tk.screen_model;
11 import doodle.dia.layer_stack;
12 import doodle.gtk.cairo;
13
14 import cairo.Surface;
15 import cairo.Context;
16
17 import gtk.Widget;
18 import gtk.Toolbar;
19 import gtk.Table;
20 import gtk.HRuler;
21 import gtk.VRuler;
22 import gtk.Range;
23 import gtk.HScrollbar;
24 import gtk.VScrollbar;
25 import gtk.DrawingArea;
26 import gtk.Adjustment;
27
28 import gdk.Drawable;
29
30 import gtkc.gtk;
31 import gtkc.gtktypes;
32 //import gtkc.gdktypes;
33
34 import std.math;
35 import std.stdio;
36 }
37
38 final class Canvas : Table, private IViewport {
39 this(in Layer[] layers, IEventHandler eventHandler, IGrid grid, in double pixelsPerMillimetre) {
40 super(3, 3, 0);
41
42 _damageScreen = Rectangle.DEFAULT;
43
44 _eventHandler = eventHandler;
45 _grid = grid;
46 _pixelsPerMillimetre = pixelsPerMillimetre;
47
48 _layerStack = new LayerStack(layers);
49
50 // Create our child widgets and register callbacks
51
52 _hRuler = new HRuler;
53 attach(_hRuler,
54 1, 2,
55 0, 1,
56 AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.SHRINK,
57 0, 0);
58 _hRuler.setMetric(MetricType.PIXELS);
59
60 _vRuler = new VRuler;
61 attach(_vRuler,
62 0, 1,
63 1, 2,
64 AttachOptions.SHRINK, AttachOptions.FILL | AttachOptions.EXPAND,
65 0, 0);
66 _vRuler.setMetric(MetricType.PIXELS);
67
68 _drawingArea = new DrawingArea;
69 _drawingArea.addOnRealize(&onRealize);
70 _drawingArea.addOnConfigure(&onConfigure);
71 _drawingArea.addOnExpose(&onExpose);
72 _drawingArea.addOnButtonPress(&onButtonPress);
73 _drawingArea.addOnButtonRelease(&onButtonRelease);
74 _drawingArea.addOnKeyPress(&onKeyPressEvent);
75 _drawingArea.addOnKeyRelease(&onKeyReleaseEvent);
76 _drawingArea.addOnMotionNotify(&onMotionNotify);
77 _drawingArea.addOnScroll(&onScroll);
78 _drawingArea.addOnEnterNotify(&onEnterNotify);
79 _drawingArea.addOnLeaveNotify(&onLeaveNotify);
80
81 _drawingArea.addOnFocusIn(&onFocusIn);
82 _drawingArea.addOnFocusOut(&onFocusOut);
83 _drawingArea.addOnMoveFocus(&onMoveFocus);
84 _drawingArea.addOnGrabBroken(&onGrabBroken);
85 _drawingArea.addOnGrabFocus(&onGrabFocus);
86 _drawingArea.addOnGrabNotify(&onGrabNotify);
87 // addOnPopupMenu
88 // addOnQueryTooltip
89 // addOnSelection*
90 _drawingArea.setEvents(EventMask.EXPOSURE_MASK |
91 EventMask.POINTER_MOTION_MASK |
92 EventMask.POINTER_MOTION_HINT_MASK |
93 EventMask.BUTTON_MOTION_MASK |
94 EventMask.BUTTON_PRESS_MASK |
95 EventMask.BUTTON_RELEASE_MASK |
96 EventMask.KEY_PRESS_MASK |
97 EventMask.KEY_RELEASE_MASK |
98 EventMask.ENTER_NOTIFY_MASK |
99 EventMask.LEAVE_NOTIFY_MASK |
100 EventMask.FOCUS_CHANGE_MASK |
101 EventMask.SCROLL_MASK);
102
103 _drawingArea.setCanFocus(true);
104
105 attach(_drawingArea,
106 1, 2,
107 1, 2,
108 AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL | AttachOptions.EXPAND,
109 0, 0);
110
111 // value, lower, upper, step-inc, page-inc, page-size
112 // Give the adjustments dummy values until we receive a configure
113 _hAdjustment = new Adjustment(0.0, 0.0, 1.0, 0.2, 0.5, 0.5);
114 _hAdjustment.addOnValueChanged(&onAdjustmentValueChanged);
115 _hScrollbar = new HScrollbar(_hAdjustment);
116 _hScrollbar.setInverted(false);
117 attach(_hScrollbar,
118 1, 2,
119 2, 3,
120 AttachOptions.FILL | AttachOptions.EXPAND,
121 AttachOptions.SHRINK,
122 0, 0);
123
124 _vAdjustment = new Adjustment(0.0, 0.0, 1.0, 0.2, 0.5, 0.5);
125 _vAdjustment.addOnValueChanged(&onAdjustmentValueChanged);
126 _vScrollbar = new VScrollbar(_vAdjustment);
127 _vScrollbar.setInverted(true);
128 attach(_vScrollbar,
129 2, 3,
130 1, 2,
131 AttachOptions.SHRINK,
132 AttachOptions.FILL | AttachOptions.EXPAND,
133 0, 0);
134
135 _cursors = [
136 Cursor.DEFAULT : CursorType.ARROW,
137 Cursor.HAND : CursorType.HAND1,
138 Cursor.CROSSHAIR : CursorType.CROSSHAIR,
139 Cursor.PENCIL : CursorType.PENCIL
140 ];
141 }
142
143 protected { // XXX the compiler complains about unimplemented methods if this is private
144
145 // IViewport overrides:
146
147 void zoomRelative(in Point screenDatum, in double factor) {
148 _screenModel.zoomRelative(factor, screenDatum);
149 consolidateBounds;
150 updateAdjustments;
151 updateRulers;
152 _grid.zoomChanged(_screenModel.zoom);
153 queueDraw;
154 }
155
156 void panRelative(in Vector screenDisplacement) {
157 _screenModel.panRelativeScreen(screenDisplacement);
158 consolidateBounds;
159 updateAdjustments;
160 updateRulers;
161 queueDraw;
162 }
163
164 void setCursor(in Cursor cursor) {
165 _drawingArea.setCursor(new gdk.Cursor.Cursor(_cursors[cursor]));
166 }
167
168 void damageModel(in Rectangle area) {
169 _damageScreen = _damageScreen | _screenModel.modelToScreen(area);
170 }
171
172 void damageScreen(in Rectangle area) {
173 _damageScreen = _damageScreen | area;
174 }
175 }
176
177 private {
178
179 void initialiseBounds(in Rectangle viewBoundsScreen) {
180 Rectangle layerBounds = _layerStack.bounds;
181 Rectangle paddedLayerBounds = growCentre(layerBounds, 2 * layerBounds.size);
182 _screenModel = new ScreenModel(0.25 * _pixelsPerMillimetre, paddedLayerBounds, viewBoundsScreen);
183 _grid.zoomChanged(_screenModel.zoom);
184
185 updateAdjustments;
186 updateRulers;
187 }
188
189 void consolidateBounds() {
190 Rectangle layerBounds = _layerStack.bounds;
191 Rectangle paddedLayerBounds = growCentre(layerBounds, 2 * layerBounds.size);
192 _screenModel.consolidateCanvasBounds(paddedLayerBounds);
193
194 updateAdjustments;
195 updateRulers;
196 }
197
198 bool onConfigure(GdkEventConfigure * event, Widget widget) {
199 assert(widget is _drawingArea);
200
201 Rectangle viewBoundsScreen = Rectangle(Point(0.0, 0.0), Vector(cast(double)event.width, cast(double)event.height));
202 if (_screenModel is null) { initialiseBounds(viewBoundsScreen); }
203 else { consolidateBounds; }
204
205 return true;
206 }
207
208 bool onExpose(GdkEventExpose * event, Widget widget) {
209 assert(widget is _drawingArea);
210
211 gdk.Drawable.Drawable dr = _drawingArea.getWindow;
212
213 int width, height;
214 dr.getSize(width, height);
215 //trace("Got expose %dx%d\n", width, height);
216
217 scope modelCr = new Context(dr);
218 scope screenCr = new Context(dr);
219
220 Rectangle screenDamage =
221 event is null ? _screenModel.viewBoundsScreen :
222 Rectangle(_screenModel.viewBoundsScreen.position + Vector(cast(double)event.area.x, _screenModel.viewBoundsScreen.h - cast(double)(event.area.y + event.area.height)),
223 Vector(cast(double)event.area.width, cast(double)event.area.height));
224
225 Rectangle modelDamage = _screenModel.screenToModel(screenDamage);
226
227 modelCr.save; screenCr.save; {
228 {
229 // Setup model context and clip
230 modelCr.translate(0.0, _screenModel.viewBoundsScreen.h);
231 modelCr.scale(_screenModel.zoom, -_screenModel.zoom);
232
233 immutable Point viewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0));
234 modelCr.translate(-viewLeftBottom.x, -viewLeftBottom.y);
235
236 modelCr.rectangle(modelDamage.x0, modelDamage.y0, modelDamage.w, modelDamage.h);
237 modelCr.clip;
238 }
239
240 {
241 // Setup screen context and clip
242 screenCr.translate(0.0, _screenModel.viewBoundsScreen.h);
243 screenCr.scale(1.0, -1.0);
244
245 screenCr.rectangle(screenDamage.x0, screenDamage.y0, screenDamage.w, screenDamage.h);
246 screenCr.clip;
247 }
248
249 screenCr.save; {
250 // Fill the background with light grey
251 screenCr.setSourceRgba(0.9, 0.9, 0.9, 1.0);
252 screenCr.rectangle(screenDamage.x0, screenDamage.y0, screenDamage.w, screenDamage.h);
253 screenCr.fill;
254 } screenCr.restore;
255
256 _layerStack.draw(screenDamage, new CairoDrawable(screenCr),
257 modelDamage, new CairoDrawable(modelCr));
258 } screenCr.restore; modelCr.restore;
259
260 return true;
261 }
262
263 bool onButtonPress(GdkEventButton * event, Widget widget) {
264 assert(widget is _drawingArea);
265 _eventHandler.handleButtonPress(this, makeButtonEvent(event, _screenModel));
266 fixDamage;
267 return true;
268 }
269
270 bool onButtonRelease(GdkEventButton * event, Widget widget) {
271 assert(widget is _drawingArea);
272 _eventHandler.handleButtonRelease(this, makeButtonEvent(event, _screenModel));
273 fixDamage;
274 return true;
275 }
276
277 bool onKeyPressEvent(GdkEventKey * event, Widget widget) {
278 assert(widget is _drawingArea);
279 _eventHandler.handleKeyPress(this, makeKeyEvent(event, _screenModel));
280 fixDamage;
281 return true;
282 }
283
284 bool onKeyReleaseEvent(GdkEventKey * event, Widget widget) {
285 assert(widget is _drawingArea);
286 _eventHandler.handleKeyRelease(this, makeKeyEvent(event, _screenModel));
287 fixDamage;
288 return true;
289 }
290
291 bool onMotionNotify(GdkEventMotion * event, Widget widget) {
292 assert(widget is _drawingArea);
293
294 // Pass the events on to the rulers so that they update
295 gtk_widget_event(_hRuler.getWidgetStruct(), cast(GdkEvent *)event);
296 gtk_widget_event(_vRuler.getWidgetStruct(), cast(GdkEvent *)event);
297
298 _eventHandler.handleMotion(this, makeMotionEvent(event, _screenModel));
299 fixDamage;
300 return true;
301 }
302
303 bool onScroll(GdkEventScroll * event, Widget widget) {
304 assert(widget is _drawingArea);
305 _eventHandler.handleScroll(this, makeScrollEvent(event, _screenModel));
306 fixDamage;
307 return true;
308 }
309
310 bool onEnterNotify(GdkEventCrossing * event, Widget widget) {
311 assert(widget is _drawingArea);
312 _eventHandler.handleEnter(this, makeCrossingEvent(event, _screenModel));
313 fixDamage;
314 return true;
315 }
316
317 bool onLeaveNotify(GdkEventCrossing * event, Widget widget) {
318 assert(widget is _drawingArea);
319 _eventHandler.handleLeave(this, makeCrossingEvent(event, _screenModel));
320 fixDamage;
321 return true;
322 }
323
324 bool onFocusIn(GdkEventFocus * event, Widget widget) {
325 trace("onFocusIn");
326 return true;
327 }
328
329 bool onFocusOut(GdkEventFocus * event, Widget widget) {
330 trace("onFocusOut");
331 return true;
332 }
333
334 void onMoveFocus(GtkDirectionType direction, Widget widget) {
335 trace("onMoveFocus");
336 }
337
338 bool onGrabBroken(gdk.Event.Event event, Widget widget) {
339 trace("onGrabBroken");
340 return true;
341 }
342
343 void onGrabFocus(Widget widget) {
344 //trace("onGrabFocus");
345 }
346
347 void onGrabNotify(gboolean what, Widget widget){
348 trace("onGrabNotify");
349 }
350
351 void onAdjustmentValueChanged(Adjustment adjustment) {
352 GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct;
353 GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct;
354
355 Point oldViewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0));
356 Point newViewLeftBottom = Point(gtk_adjustment_get_value(hGtkAdjustment),
357 gtk_adjustment_get_value(vGtkAdjustment));
358
359 _screenModel.panRelativeModel(newViewLeftBottom - oldViewLeftBottom);
360
361 updateRulers;
362 queueDraw;
363 }
364
365 void updateRulers() {
366 immutable Point viewLeftBottom = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner0);
367 immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1);
368
369 // Define these just to obtain the position
370 // below so we can preserve it
371 double lower, upper, position, maxSize;
372
373 _hRuler.getRange(lower, upper, position, maxSize);
374 _hRuler.setRange(viewLeftBottom.x,
375 viewRightTop.x,
376 position,
377 _screenModel.zoom * 50.0);
378
379 _vRuler.getRange(lower, upper, position, maxSize);
380 _vRuler.setRange(viewRightTop.y,
381 viewLeftBottom.y,
382 position,
383 _screenModel.zoom * 50.0);
384 }
385
386 void updateAdjustments() {
387 immutable Point viewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0));
388 immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1);
389
390 // Adjust the canvas size if necessary
391 _screenModel.canvasAccommodate(Rectangle(viewLeftBottom, viewRightTop));
392
393 Rectangle viewBoundsModel = _screenModel.viewBoundsModel;
394
395 // Update the adjustments
396
397 GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct;
398 GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct;
399
400 gtk_adjustment_set_lower(hGtkAdjustment, _screenModel.canvasBoundsModel.x0);
401 gtk_adjustment_set_upper(hGtkAdjustment, _screenModel.canvasBoundsModel.x1);
402 gtk_adjustment_set_value(hGtkAdjustment, viewLeftBottom.x);
403 gtk_adjustment_set_step_increment(hGtkAdjustment, _screenModel.canvasBoundsModel.w / 16.0);
404 gtk_adjustment_set_page_increment(hGtkAdjustment, _screenModel.canvasBoundsModel.w / 4.0);
405 gtk_adjustment_set_page_size(hGtkAdjustment, viewBoundsModel.w);
406
407 gtk_adjustment_set_lower(vGtkAdjustment, _screenModel.canvasBoundsModel.y0);
408 gtk_adjustment_set_upper(vGtkAdjustment, _screenModel.canvasBoundsModel.y1);
409 gtk_adjustment_set_value(vGtkAdjustment, viewLeftBottom.y);
410 gtk_adjustment_set_step_increment(vGtkAdjustment, _screenModel.canvasBoundsModel.h / 16.0);
411 gtk_adjustment_set_page_increment(vGtkAdjustment, _screenModel.canvasBoundsModel.h / 4.0);
412 gtk_adjustment_set_page_size(vGtkAdjustment, viewBoundsModel.h);
413
414 _hAdjustment.changed;
415 _hAdjustment.valueChanged;
416 _vAdjustment.changed;
417 _vAdjustment.valueChanged;
418 }
419
420 void fixDamage() {
421 if (_damageScreen.valid) {
422 int x, y, w, h;
423 _damageScreen.getQuantised(x, y, w, h);
424 _drawingArea.queueDrawArea(x, cast(int)_screenModel.viewBoundsScreen.h - (y + h), w, h);
425 _damageScreen = Rectangle.DEFAULT;
426 }
427 }
428
429 void onRealize(Widget widget) {
430 assert(widget is _drawingArea);
431 _drawingArea.grabFocus();
432 }
433
434 IEventHandler _eventHandler;
435 IGrid _grid;
436 double _pixelsPerMillimetre;
437 LayerStack _layerStack;
438
439 // Child widgets:
440 HRuler _hRuler;
441 VRuler _vRuler;
442 DrawingArea _drawingArea;
443 Adjustment _hAdjustment;
444 HScrollbar _hScrollbar;
445 Adjustment _vAdjustment;
446 VScrollbar _vScrollbar;
447
448 Rectangle _damageScreen;
449 ScreenModel _screenModel;
450
451 immutable CursorType[Cursor] _cursors;
452 }
453 }