Mercurial > projects > doodle
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 } |