annotate canvas.d @ 18:df8d81d9f499

Lasso fiddling
author David Bryant <daveb@acres.com.au>
date Mon, 13 Jul 2009 17:08:32 +0930
parents c643c04e3f5e
children 22abbf4cde96
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
1 module canvas;
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
2
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
3 public {
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
4 import icanvas;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
5 import tk.geometry;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
6 import tk.events;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
7 }
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
8
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
9 private {
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
10 import tk.gtk_support;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
11 import tk.misc;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
12
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
13 import cairo.Surface;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
14 import cairo_support;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
15
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
16 import std.math;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
17 import std.stdio;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
18
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
19 import gtk.Widget;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
20 import gtk.Toolbar;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
21 import gtk.Table;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
22 import gtk.HRuler;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
23 import gtk.VRuler;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
24 import gtk.Range;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
25 import gtk.HScrollbar;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
26 import gtk.VScrollbar;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
27 import gtk.DrawingArea;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
28 import gtk.Adjustment;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
29
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
30 import gdk.Drawable;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
31
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
32 import gtkc.gtk;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
33 }
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
34
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
35 // x and y run right and up respectively
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
36
10
71ca82e0eb76 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 9
diff changeset
37 class Canvas : Table, Viewport {
11
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
38 this(in Layer[] layers, EventHandler event_handler, in double ppi) {
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
39 super(3, 3, 0);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
40
17
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
41 mDamage = Rectangle.DEFAULT;
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
42
11
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
43 mLayers = layers.dup;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
44 mEventHandler = event_handler;
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
45 mPPI = ppi;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
46
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
47 /*
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
48 writefln("Layer bounds: %s", layer_bounds);
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
49 writefln("Canvas bounds: %s", mCanvasBounds);
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
50 writefln("View centre: %s", mViewCentre);
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
51 */
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
52
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
53 // Create our child widgets and register callbacks
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
54
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
55 mHRuler = new HRuler;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
56 attach(mHRuler,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
57 1, 2,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
58 0, 1,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
59 AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.SHRINK,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
60 0, 0);
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
61 mHRuler.setMetric(GtkMetricType.PIXELS);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
62
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
63 mVRuler = new VRuler;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
64 attach(mVRuler,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
65 0, 1,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
66 1, 2,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
67 AttachOptions.SHRINK, AttachOptions.FILL | AttachOptions.EXPAND,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
68 0, 0);
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
69 mVRuler.setMetric(GtkMetricType.PIXELS);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
70
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
71 mDrawingArea = new DrawingArea;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
72 mDrawingArea.addOnRealize(&onRealize);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
73 mDrawingArea.addOnConfigure(&onConfigure);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
74 mDrawingArea.addOnExpose(&onExpose);
5
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
75 mDrawingArea.addOnButtonPress(&onButtonPress);
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
76 mDrawingArea.addOnButtonRelease(&onButtonRelease);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
77 mDrawingArea.addOnKeyPress(&onKeyEvent);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
78 mDrawingArea.addOnKeyRelease(&onKeyEvent);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
79 mDrawingArea.addOnMotionNotify(&onMotionNotify);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
80 mDrawingArea.addOnScroll(&onScroll);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
81 attach(mDrawingArea,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
82 1, 2,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
83 1, 2,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
84 AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL | AttachOptions.EXPAND,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
85 0, 0);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
86
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
87 // value, lower, upper, step-inc, page-inc, page-size
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
88 // Give the adjustments dummy values until we receive a configure
12
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
89 mHAdjustment = new Adjustment(0.0, 0.0, 1.0, 0.2, 0.5, 0.5);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
90 mHAdjustment.addOnValueChanged(&onValueChanged);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
91 mHScrollbar = new HScrollbar(mHAdjustment);
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
92 mHScrollbar.setInverted(false);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
93 attach(mHScrollbar,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
94 1, 2,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
95 2, 3,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
96 AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.SHRINK,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
97 0, 0);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
98
2
d6f44347373d * Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents: 0
diff changeset
99 mVAdjustment = new Adjustment(0.0, 0.0, 1.0, 0.2, 0.5, 0.5);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
100 mVAdjustment.addOnValueChanged(&onValueChanged);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
101 mVScrollbar = new VScrollbar(mVAdjustment);
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
102 mVScrollbar.setInverted(true);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
103 attach(mVScrollbar,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
104 2, 3,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
105 1, 2,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
106 AttachOptions.SHRINK,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
107 AttachOptions.FILL | AttachOptions.EXPAND,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
108 0, 0);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
109 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
110
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
111 override void rel_zoom(Point pixel_datum, double factor) {
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
112 // Work out pixel distance from current centre to datum,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
113 // Do the zoom, then work out the new centre that keeps the
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
114 // pixel distance the same
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
115
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
116 Point old_model_datum = pixel_to_model(pixel_datum);
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
117 Vector pixel_distance = model_to_pixel(old_model_datum - mViewCentre);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
118 mZoom = clamp_zoom(factor * mZoom);
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
119 mViewCentre = old_model_datum - pixel_to_model(pixel_distance);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
120
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
121 update_adjustments;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
122 update_rulers;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
123 queueDraw;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
124 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
125
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
126 override void rel_pan(Vector pixel_displacement) {
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
127 mViewCentre = mViewCentre + pixel_to_model(pixel_displacement);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
128
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
129 update_adjustments;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
130 update_rulers;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
131 queueDraw;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
132 }
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
133
17
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
134 override void damage_model(Rectangle area) {
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
135 mDamage = mDamage | model_to_pixel(area);
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
136 }
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
137
18
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
138 override void damage_pixel(Rectangle area) {
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
139 mDamage = mDamage | area;
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
140 }
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
141
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
142 override double zoom() const {
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
143 return mZoom;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
144 }
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
145
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
146 override Point model_to_pixel(Point model) const {
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
147 return Point.DEFAULT + mViewSize / 2.0 + mZoom * (model - mViewCentre);
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
148 }
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
149
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
150 override Point pixel_to_model(Point pixel) const {
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
151 return mViewCentre + (pixel - mViewSize / 2.0 - Point.DEFAULT) / mZoom;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
152 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
153
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
154 override Vector model_to_pixel(Vector model) const {
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
155 return mZoom * model;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
156 }
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
157
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
158 override Vector pixel_to_model(Vector pixel) const {
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
159 return pixel / mZoom;
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
160 }
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
161
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
162 override double model_to_pixel(double model) const {
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
163 return mZoom * model;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
164 }
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
165
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
166 override double pixel_to_model(double pixel) const {
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
167 return pixel / mZoom;
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
168 }
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
169
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
170 override Rectangle model_to_pixel(Rectangle model) const {
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
171 return Rectangle(model_to_pixel(model.position), model_to_pixel(model.size));
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
172 }
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
173
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
174 override Rectangle pixel_to_model(Rectangle model) const {
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
175 return Rectangle(pixel_to_model(model.position), pixel_to_model(model.size));
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
176 }
10
71ca82e0eb76 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 9
diff changeset
177
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
178 private {
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
179
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
180 void onRealize(Widget widget) {
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
181 assert(widget is mDrawingArea);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
182 //writefln("Got realize\n");
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
183 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
184
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
185 bool onConfigure(GdkEventConfigure * event, Widget widget) {
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
186 assert(widget is mDrawingArea);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
187
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
188 if (!mHadConfigure) {
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
189 const double MM_PER_INCH = 25.4;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
190 mZoom = 0.25 * mPPI / MM_PER_INCH;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
191
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
192 // Take the union of the bounds of each layer to
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
193 // determine the canvas size
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
194
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
195 Rectangle layer_bounds = Rectangle.DEFAULT;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
196
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
197 foreach (ref layer; mLayers) {
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
198 layer_bounds = layer_bounds | layer.bounds;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
199 }
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
200
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
201 assert(layer_bounds.valid);
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
202
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
203 mCanvasBounds = layer_bounds.moved(-layer_bounds.size).expanded(2.0 * layer_bounds.size);
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
204 mViewCentre = mCanvasBounds.centre;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
205
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
206 mHadConfigure = true;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
207 }
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
208
3
7d57cae10805 Renamed geometry2 to geometry
David Bryant <daveb@acres.com.au>
parents: 2
diff changeset
209 mViewSize = Vector(cast(double)event.width, cast(double)event.height);
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
210 update_adjustments;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
211 update_rulers;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
212
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
213 //writefln("Canvas bounds: %s", mCanvasBounds);
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
214 //writefln("View centre: %s", mViewCentre);
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
215
2
d6f44347373d * Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents: 0
diff changeset
216 return true;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
217 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
218
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
219 bool onExpose(GdkEventExpose * event, Widget widget) {
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
220 assert(widget is mDrawingArea);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
221
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
222 Drawable dr = mDrawingArea.getWindow;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
223
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
224 int width, height;
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
225 dr.getSize(width, height);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
226 //writefln("Got expose %dx%d\n", width, height);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
227
12
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
228 scope model_cr = new Context(dr);
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
229 scope pixel_cr = new Context(dr);
12
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
230
11
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
231 Rectangle damage =
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
232 event is null ?
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
233 Rectangle(Point(0.0, 0.0), Vector(cast(double)width, cast(double)height)) :
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
234 Rectangle(Point(cast(double)event.area.x, cast(double)event.area.y),
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
235 Vector(cast(double)event.area.width, cast(double)event.area.height));
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
236
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
237 model_cr.save; pixel_cr.save; {
18
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
238 // FIXME restore clipping
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
239
12
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
240 // Setup model context
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
241
18
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
242 //rectangle(model_cr, damage);
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
243 //model_cr.clip;
12
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
244
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
245 GtkAdjustment * h_gtkAdjustment = mHAdjustment.getAdjustmentStruct;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
246 GtkAdjustment * v_gtkAdjustment = mVAdjustment.getAdjustmentStruct;
12
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
247
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
248 model_cr.scale(mZoom, -mZoom);
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
249 model_cr.translate(-gtk_adjustment_get_value(h_gtkAdjustment),
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
250 -gtk_adjustment_get_value(v_gtkAdjustment) - gtk_adjustment_get_page_size(v_gtkAdjustment));
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
251
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
252 // Setup pixel context
12
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
253
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
254 pixel_cr.translate(0.0, mViewSize.y);
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
255 pixel_cr.scale(1.0, -1.0);
18
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
256 //rectangle(pixel_cr, damage);
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
257 //pixel_cr.clip;
12
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
258
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
259 // Fill the background
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
260
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
261 pixel_cr.save; {
11
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
262 // Make the window light grey
18
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
263 pixel_cr.setSourceRgba(0.6, 0.6, 0.6, 1.0);
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
264 rectangle(pixel_cr, damage);
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
265 pixel_cr.fill;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
266 } pixel_cr.restore;
12
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
267
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
268 // Draw each layer
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
269
11
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
270 foreach(ref layer; mLayers) {
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
271 model_cr.save; pixel_cr.save; {
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
272 layer.draw(this, damage, model_cr, pixel_cr);
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
273 } pixel_cr.restore; model_cr.restore;
11
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
274 }
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
275 } pixel_cr.restore; model_cr.restore;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
276
2
d6f44347373d * Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents: 0
diff changeset
277 return true;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
278 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
279
5
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
280 bool onButtonPress(GdkEventButton * event, Widget widget) {
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
281 assert(widget is mDrawingArea);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
282 //writefln("Got button event\n");
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
283
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
284 Point pixel_point = Point(event.x + 0.5, mViewSize.y - (event.y + 0.5));
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
285 Point model_point = pixel_to_model(pixel_point);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
286
7
936feb16eed4 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 5
diff changeset
287 auto button_event = new ButtonEvent(gtk2tk_button_action(event.type),
936feb16eed4 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 5
diff changeset
288 gtk2tk_button_name(event.button),
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
289 pixel_point,
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
290 model_point,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
291 gtk2tk_mask(event.state));
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
292
5
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
293 mEventHandler.handle_button_press(this, button_event);
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
294
17
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
295 process_damage;
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
296
5
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
297 return true;
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
298 }
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
299
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
300 bool onButtonRelease(GdkEventButton * event, Widget widget) {
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
301 assert(widget is mDrawingArea);
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
302 //writefln("Got button event\n");
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
303
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
304 Point pixel_point = Point(event.x + 0.5, mViewSize.y - (event.y + 0.5));
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
305 Point model_point = pixel_to_model(pixel_point);
5
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
306
7
936feb16eed4 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 5
diff changeset
307 auto button_event = new ButtonEvent(gtk2tk_button_action(event.type),
936feb16eed4 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 5
diff changeset
308 gtk2tk_button_name(event.button),
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
309 pixel_point,
5
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
310 model_point,
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
311 gtk2tk_mask(event.state));
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
312
8a39b13cd3e6 Checkpoint
David Bryant <daveb@acres.com.au>
parents: 3
diff changeset
313 mEventHandler.handle_button_release(this, button_event);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
314
17
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
315 process_damage;
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
316
2
d6f44347373d * Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents: 0
diff changeset
317 return true;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
318 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
319
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
320 bool onKeyEvent(GdkEventKey * event, Widget widget) {
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
321 assert(widget is mDrawingArea);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
322 //writefln("Got key event\n");
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
323
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
324 //auto key_event = new KeyEvent("",
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
325 // mEventHandle.handle_key(key_event);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
326
17
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
327 process_damage;
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
328
2
d6f44347373d * Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents: 0
diff changeset
329 return true;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
330 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
331
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
332 bool onMotionNotify(GdkEventMotion * event, Widget widget) {
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
333 assert(widget is mDrawingArea);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
334 //writefln("Got motion notify\n");
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
335 gtk_widget_event(mHRuler.getWidgetStruct(), cast(GdkEvent *)event);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
336 gtk_widget_event(mVRuler.getWidgetStruct(), cast(GdkEvent *)event);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
337
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
338 Point pixel_point = Point(event.x + 0.5, mViewSize.y - (event.y + 0.5));
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
339 Point model_point = pixel_to_model(pixel_point);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
340
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
341 auto motion_event = new MotionEvent(pixel_point,
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
342 model_point,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
343 gtk2tk_mask(event.state));
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
344
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
345 mEventHandler.handle_motion(this, motion_event);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
346
17
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
347 process_damage;
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
348
2
d6f44347373d * Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents: 0
diff changeset
349 return true;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
350 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
351
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
352 bool onScroll(GdkEventScroll * event, Widget widget) {
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
353 assert(widget is mDrawingArea);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
354 //writefln("Got scroll\n");
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
355
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
356 Point pixel_point = Point(event.x + 0.5, mViewSize.y - (event.y + 0.5));
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
357 Point model_point = pixel_to_model(pixel_point);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
358
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
359 auto scroll_event = new ScrollEvent(gtk2tk_direction(event.direction),
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
360 pixel_point,
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
361 model_point,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
362 gtk2tk_mask(event.state));
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
363
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
364 mEventHandler.handle_scroll(this, scroll_event);
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
365
17
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
366 process_damage;
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
367
2
d6f44347373d * Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents: 0
diff changeset
368 return true;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
369 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
370
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
371 void onValueChanged(Adjustment adjustment) {
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
372 GtkAdjustment * h_gtkAdjustment = mHAdjustment.getAdjustmentStruct;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
373 GtkAdjustment * v_gtkAdjustment = mVAdjustment.getAdjustmentStruct;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
374
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
375 Point view_left_top = Point(gtk_adjustment_get_value(h_gtkAdjustment),
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
376 gtk_adjustment_get_value(v_gtkAdjustment));
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
377
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
378 Vector model_size = pixel_to_model(mViewSize);
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
379
9
66b47e122b31 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 7
diff changeset
380 //writefln("%s", view_left_bottom);
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
381 mViewCentre = view_left_top + model_size / 2.0;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
382 writefln("onValueChanged mViewCentre: %s", mViewCentre);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
383
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
384 update_rulers;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
385
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
386 queueDraw;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
387 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
388
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
389 void update_rulers() {
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
390 Vector model_size = pixel_to_model(mViewSize);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
391
3
7d57cae10805 Renamed geometry2 to geometry
David Bryant <daveb@acres.com.au>
parents: 2
diff changeset
392 Point view_left_bottom = mViewCentre - model_size / 2.0;
7d57cae10805 Renamed geometry2 to geometry
David Bryant <daveb@acres.com.au>
parents: 2
diff changeset
393 Point view_right_top = mViewCentre + model_size / 2.0;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
394
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
395 // Define these just to obtain the position
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
396 // below and we can preserve it
12
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
397 double lower, upper, position, max_size;
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
398
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
399
12
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
400 mHRuler.getRange(lower, upper, position, max_size);
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
401 writefln("HRuler: %f %f %f", view_left_bottom.x, view_right_top.x, position);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
402 mHRuler.setRange(view_left_bottom.x,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
403 view_right_top.x,
12
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
404 position,
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
405 mZoom * 50.0);
12
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
406
a093c4fbdd43 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 11
diff changeset
407 mVRuler.getRange(lower, upper, position, max_size);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
408 mVRuler.setRange(view_right_top.y,
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
409 view_left_bottom.y,
14
0b7e7d43a79d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 13
diff changeset
410 position,
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
411 mZoom * 50.0);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
412 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
413
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
414 void update_adjustments() {
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
415 Vector model_size = pixel_to_model(mViewSize);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
416
3
7d57cae10805 Renamed geometry2 to geometry
David Bryant <daveb@acres.com.au>
parents: 2
diff changeset
417 Point view_left_bottom = mViewCentre - model_size / 2.0;
7d57cae10805 Renamed geometry2 to geometry
David Bryant <daveb@acres.com.au>
parents: 2
diff changeset
418 Point view_right_top = mViewCentre + model_size / 2.0;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
419
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
420 // Adjust the canvas size if necessary
15
2f79aab4d385 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 14
diff changeset
421 mCanvasBounds = Rectangle(min_extents(mCanvasBounds.min_corner, view_left_bottom),
2f79aab4d385 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 14
diff changeset
422 max_extents(mCanvasBounds.max_corner, view_right_top));
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
423
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
424 // Update the adjustments
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
425
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
426 GtkAdjustment * h_gtkAdjustment = mHAdjustment.getAdjustmentStruct;
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
427 GtkAdjustment * v_gtkAdjustment = mVAdjustment.getAdjustmentStruct;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
428
15
2f79aab4d385 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 14
diff changeset
429 gtk_adjustment_set_lower(h_gtkAdjustment, mCanvasBounds.min_corner.x);
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
430 gtk_adjustment_set_upper(h_gtkAdjustment, mCanvasBounds.max_corner.x);
2
d6f44347373d * Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents: 0
diff changeset
431 gtk_adjustment_set_value(h_gtkAdjustment, view_left_bottom.x);
15
2f79aab4d385 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 14
diff changeset
432 gtk_adjustment_set_step_increment(h_gtkAdjustment, mCanvasBounds.size.x / 16.0);
2f79aab4d385 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 14
diff changeset
433 gtk_adjustment_set_page_increment(h_gtkAdjustment, mCanvasBounds.size.x / 4.0);
2
d6f44347373d * Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents: 0
diff changeset
434 gtk_adjustment_set_page_size(h_gtkAdjustment, model_size.x);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
435
15
2f79aab4d385 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 14
diff changeset
436 gtk_adjustment_set_lower(v_gtkAdjustment, mCanvasBounds.min_corner.y);
2f79aab4d385 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 14
diff changeset
437 gtk_adjustment_set_upper(v_gtkAdjustment, mCanvasBounds.max_corner.y);
2
d6f44347373d * Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents: 0
diff changeset
438 gtk_adjustment_set_value(v_gtkAdjustment, view_left_bottom.y);
15
2f79aab4d385 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 14
diff changeset
439 gtk_adjustment_set_step_increment(v_gtkAdjustment, mCanvasBounds.size.y / 16.0);
2f79aab4d385 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 14
diff changeset
440 gtk_adjustment_set_page_increment(v_gtkAdjustment, mCanvasBounds.size.y / 4.0);
2
d6f44347373d * Switched over to geometry done with structs instead of classes.
David Bryant <daveb@acres.com.au>
parents: 0
diff changeset
441 gtk_adjustment_set_page_size(v_gtkAdjustment, model_size.y);
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
442
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
443 mHAdjustment.changed;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
444 mHAdjustment.valueChanged;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
445 mVAdjustment.changed;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
446 mVAdjustment.valueChanged;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
447 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
448
17
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
449 void process_damage() {
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
450 if (mDamage.valid) {
18
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
451 //writefln("Damage: %s", mDamage);
17
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
452 int x, y, w, h;
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
453 mDamage.get_quantised(x, y, w, h);
18
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
454 //writefln("Quantised damage: %d %d %d %d", x, y, w, h);
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
455 y = cast(int)mViewSize.y - (y + h);
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
456 //writefln("Flipped Quantised damage: %d %d %d %d", x, y, w, h);
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
457 // FIXME only redraw the damaged area
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
458 //mDrawingArea.queueDrawArea(x, y, w, h);
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
459 mDrawingArea.queueDraw();
17
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
460 mDamage = Rectangle.DEFAULT;
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
461 }
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
462 else {
18
df8d81d9f499 Lasso fiddling
David Bryant <daveb@acres.com.au>
parents: 17
diff changeset
463 //writefln("No damage");
17
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
464 }
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
465 }
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
466
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
467 double clamp_zoom(double zoom) { return clamp(zoom, 0.2, 10.0); }
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
468
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
469 bool mHadConfigure;
17
c643c04e3f5e Checkpoint
David Bryant <daveb@acres.com.au>
parents: 16
diff changeset
470 Rectangle mDamage; // pixels
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
471
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
472 // Model units are in millimetres
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
473 // Screen units are in pixels
11
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
474 double mZoom; // pixels-per-model-unit (mm)
16
9e63308b749c * Fix up public/private includes
David Bryant <daveb@acres.com.au>
parents: 15
diff changeset
475 Vector mViewSize; // pixel: size of view window in pixels
3
7d57cae10805 Renamed geometry2 to geometry
David Bryant <daveb@acres.com.au>
parents: 2
diff changeset
476 Point mViewCentre; // model: where in the model is the centre of our view
15
2f79aab4d385 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 14
diff changeset
477 Rectangle mCanvasBounds; // model:
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
478
10
71ca82e0eb76 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 9
diff changeset
479 // Child widgets:
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
480 HRuler mHRuler;
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
481 VRuler mVRuler;
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
482 DrawingArea mDrawingArea;
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
483 Adjustment mHAdjustment;
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
484 HScrollbar mHScrollbar;
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
485 Adjustment mVAdjustment;
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
486 VScrollbar mVScrollbar;
11
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
487
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
488 // Layers:
fb571a3b1f0d Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 10
diff changeset
489 Layer[] mLayers;
13
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
490 EventHandler mEventHandler;
f0ade1b49fe7 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents: 12
diff changeset
491 double mPPI;
0
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
492 }
e907d2c54ec3 Initial import
David Bryant <daveb@acres.com.au>
parents:
diff changeset
493 }