changeset 70:0e61702c6ea6

Checkpoint
author "David Bryant <bagnose@gmail.com>"
date Sat, 14 Aug 2010 20:05:55 +0930
parents d540f7e4af9e
children 0f7cf6c6f206
files doodle/dia/grid_layer.d doodle/gtk/canvas.d doodle/tk/geometry.d doodle/tk/pixel_model.d
diffstat 4 files changed, 102 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/doodle/dia/grid_layer.d	Sat Aug 14 19:39:58 2010 +0930
+++ b/doodle/dia/grid_layer.d	Sat Aug 14 20:05:55 2010 +0930
@@ -46,10 +46,10 @@
 
             {
                 // vertical grid lines
-                double x = start(modelDamage.minCorner.x, _spacing);
+                double x = start(modelDamage.corner0.x, _spacing);
 
                 for (;;) {
-                    vline(modelCr, x, modelDamage.minCorner.y, modelDamage.maxCorner.y);
+                    vline(modelCr, x, modelDamage.corner0.y, modelDamage.corner1.y);
 
                     // Ensure 1 pixel wide FIXME is this naughty? We are sneaking
                     // through cairo to mix model and pixel coordinates...
@@ -58,7 +58,7 @@
                         modelCr.stroke();
                     } modelCr.restore();
 
-                    if (x > modelDamage.maxCorner.x) {
+                    if (x > modelDamage.corner1.x) {
                         break;
                     }
 
@@ -68,10 +68,10 @@
 
             {
                 // horizontal grid lines
-                double y = start(modelDamage.minCorner.y, _spacing);
+                double y = start(modelDamage.corner0.y, _spacing);
 
                 for (;;) {
-                    hline(modelCr, y, modelDamage.minCorner.x, modelDamage.maxCorner.x);
+                    hline(modelCr, y, modelDamage.corner0.x, modelDamage.corner1.x);
 
                     // FIXME?
                     modelCr.save(); {
@@ -79,7 +79,7 @@
                         modelCr.stroke();
                     } modelCr.restore();
 
-                    if (y > modelDamage.maxCorner.y) {
+                    if (y > modelDamage.corner1.y) {
                         break;
                     }
 
--- a/doodle/gtk/canvas.d	Sat Aug 14 19:39:58 2010 +0930
+++ b/doodle/gtk/canvas.d	Sat Aug 14 20:05:55 2010 +0930
@@ -37,18 +37,6 @@
 }
 
 // x and y run right and up respectively
-//
-// Model units are millimetres.
-//
-// _zoom         -> pixels-per-model-unit
-// _viewSize     -> size of view window in pixels
-// _viewCentre   -> location in model corresponding to centre of view
-// _canvasBounds -> size of the virtual canvas in model coordinates
-//
-// User operations:
-//   pan (middle click and drag)
-//   zoom about a point (hold control and move scroll wheel)
-//   resize the widget
 
 final class Canvas : Table, private IViewport {
     this(in Layer[] layers, IEventHandler eventHandler, IGrid grid, in double pixelsPerMillimetre) {
@@ -213,21 +201,23 @@
 
     private {
 
-        void initialiseBounds() {
-            Rectangle layerBounds = Rectangle.DEFAULT;
+        Rectangle layerBounds() {
+            Rectangle bounds = Rectangle.DEFAULT;
+            foreach (layer; _layers) { bounds = bounds | layer.bounds; }
+            assert(bounds.valid);
+            return bounds;
+        }
 
-            foreach (layer; _layers) {
-                layerBounds = layerBounds | layer.bounds;
-            }
-
-            assert(layerBounds.valid);
+        void initialiseBounds() {
+            Rectangle lb = layerBounds;
 
             // FIXME use a function that grows a rectangle about its centre
             // and change 2.0 to a class-level constant
-            Rectangle paddedLayerBounds = expand(move(layerBounds, - layerBounds.size), 2.0 * layerBounds.size);
+            Rectangle paddedLayerBounds = expand(move(lb, - lb.size), 2.0 * lb.size);
 
             //
 
+            // FIXME 0.25
             _zoom = 0.25 * _pixelsPerMillimetre;       // ie 0.25 pixels represents a millimetre
 
             _canvasBounds = paddedLayerBounds;
@@ -240,18 +230,12 @@
         }
 
         void consolidateBounds() {
-            Rectangle layerBounds = Rectangle.DEFAULT;
-
-            foreach (layer; _layers) {
-                layerBounds = layerBounds | layer.bounds;
-            }
+            Rectangle lb = layerBounds;
 
-            assert(layerBounds.valid);
+            // FIXME likewise as above
+            Rectangle paddedLayerBounds = expand(move(lb, - lb.size), 2.0 * lb.size);
 
-            Rectangle paddedLayerBounds = expand(move(layerBounds, - layerBounds.size), 2.0 * layerBounds.size);
-
-            Vector z = _viewSize / _zoom;
-            Rectangle r = Rectangle(_viewCentre - z / 2.0, z);
+            Rectangle r = pixelToModel(_viewBounds);
             _canvasBounds = r | paddedLayerBounds;
 
             updateAdjustments;
@@ -261,7 +245,7 @@
         bool onConfigure(GdkEventConfigure * event, Widget widget) {
             assert(widget is _drawingArea);
 
-            _viewSize = Vector(cast(double)event.width, cast(double)event.height);
+            _viewBounds = Rectangle(Point(0.0, 0.0), Vector(cast(double)event.width, cast(double)event.height));
 
             if (!_boundsValid) {
                 initialiseBounds;
@@ -288,8 +272,8 @@
 
             Rectangle pixelDamage =
                 event is null ?
-                Rectangle(Point(0.0, 0.0), _viewSize) :
-                Rectangle(Point(cast(double)event.area.x, _viewSize.y - cast(double)(event.area.y + event.area.height)),
+                _viewBounds :       // XXX can we do something nice with the next line?
+                Rectangle(_viewBounds.position + Vector(cast(double)event.area.x, _viewBounds.h - cast(double)(event.area.y + event.area.height)),
                           Vector(cast(double)event.area.width, cast(double)event.area.height));
 
             Rectangle modelDamage = pixelToModel(pixelDamage);
@@ -299,10 +283,11 @@
             modelCr.save; pixelCr.save; {
                 {
                     // Setup model context and clip
-                    modelCr.translate(0.0, _viewSize.y);
+                    modelCr.translate(0.0, _viewBounds.h);
                     modelCr.scale(_zoom, -_zoom);
 
-                    immutable Vector modelSize = pixelToModel(_viewSize);
+                    // XXX revisit
+                    immutable Vector modelSize = pixelToModel(_viewBounds.size);
                     immutable Point viewLeftBottom = _viewCentre - modelSize / 2.0;
                     modelCr.translate(-viewLeftBottom.x, -viewLeftBottom.y);
 
@@ -312,7 +297,7 @@
 
                 {
                     // Setup pixel context and clip
-                    pixelCr.translate(0.0, _viewSize.y);
+                    pixelCr.translate(0.0, _viewBounds.h);
                     pixelCr.scale(1.0, -1.0);
 
                     rectangle(pixelCr, pixelDamage);
@@ -339,7 +324,7 @@
             assert(widget is _drawingArea);
             //trace("Got button event\n");
 
-            Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5));
+            Point pixelPoint = Point(event.x + 0.5, _viewBounds.h - (event.y + 0.5));
             Point modelPoint = pixelToModel(pixelPoint);
 
             auto buttonEvent = new ButtonEvent(gtk2tkButtonAction(event.type),
@@ -358,7 +343,7 @@
         bool onButtonRelease(GdkEventButton * event, Widget widget) {
             assert(widget is _drawingArea);
 
-            Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5));
+            Point pixelPoint = Point(event.x + 0.5, _viewBounds.h - (event.y + 0.5));
             Point modelPoint = pixelToModel(pixelPoint);
 
             auto buttonEvent = new ButtonEvent(gtk2tkButtonAction(event.type),
@@ -424,7 +409,7 @@
             gtk_widget_event(_hRuler.getWidgetStruct(), cast(GdkEvent *)event);
             gtk_widget_event(_vRuler.getWidgetStruct(), cast(GdkEvent *)event);
 
-            Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5));
+            Point pixelPoint = Point(event.x + 0.5, _viewBounds.h - (event.y + 0.5));
             Point modelPoint = pixelToModel(pixelPoint);
 
             auto motionEvent = new MotionEvent(pixelPoint,
@@ -442,7 +427,7 @@
             assert(widget is _drawingArea);
             //writefln("Got scroll\n");
 
-            Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5));
+            Point pixelPoint = Point(event.x + 0.5, _viewBounds.h - (event.y + 0.5));
             Point modelPoint = pixelToModel(pixelPoint);
 
             auto scrollEvent = new ScrollEvent(gtk2tkDirection(event.direction),
@@ -487,7 +472,7 @@
         bool onEnterNotify(GdkEventCrossing * event, Widget widget) {
             assert(widget is _drawingArea);
 
-            Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5));
+            Point pixelPoint = Point(event.x + 0.5, _viewBounds.h - (event.y + 0.5));
             Point modelPoint = pixelToModel(pixelPoint);
 
             auto crossingEvent = new CrossingEvent(gtk2tkCrossingMode(event.mode),
@@ -507,7 +492,7 @@
         bool onLeaveNotify(GdkEventCrossing * event, Widget widget) {
             assert(widget is _drawingArea);
 
-            Point pixelPoint = Point(event.x + 0.5, _viewSize.y - (event.y + 0.5));
+            Point pixelPoint = Point(event.x + 0.5, _viewBounds.h - (event.y + 0.5));
             Point modelPoint = pixelToModel(pixelPoint);
 
             auto crossingEvent = new CrossingEvent(gtk2tkCrossingMode(event.mode),
@@ -566,7 +551,7 @@
             Point viewLeftBottom = Point(gtk_adjustment_get_value(hGtkAdjustment),
                                          gtk_adjustment_get_value(vGtkAdjustment));
 
-            Vector modelSize = pixelToModel(_viewSize);
+            Vector modelSize = pixelToModel(_viewBounds.size);      // XXX
 
             _viewCentre = viewLeftBottom + modelSize / 2.0;
 
@@ -575,7 +560,7 @@
         }
 
         void updateRulers() {
-            immutable Vector modelSize = pixelToModel(_viewSize);
+            immutable Vector modelSize = pixelToModel(_viewBounds.size);        // XXX
             immutable Point viewLeftBottom = _viewCentre - modelSize / 2.0;
             immutable Point viewRightTop = _viewCentre + modelSize / 2.0;
 
@@ -597,28 +582,28 @@
         }
 
         void updateAdjustments() {
-            immutable Vector modelSize = pixelToModel(_viewSize);
+            immutable Vector modelSize = pixelToModel(_viewBounds.size);        // XXX
             immutable Point viewLeftBottom = _viewCentre - modelSize / 2.0;
             immutable Point viewRightTop = _viewCentre + modelSize / 2.0;
 
             // Adjust the canvas size if necessary
-            _canvasBounds = Rectangle(minExtents(_canvasBounds.minCorner, viewLeftBottom),
-                                      maxExtents(_canvasBounds.maxCorner, viewRightTop));
+            _canvasBounds = Rectangle(minExtents(_canvasBounds.corner0, viewLeftBottom),
+                                      maxExtents(_canvasBounds.corner1, viewRightTop));
 
             // Update the adjustments
 
             GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct;
             GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct;
 
-            gtk_adjustment_set_lower(hGtkAdjustment, _canvasBounds.minCorner.x);
-            gtk_adjustment_set_upper(hGtkAdjustment, _canvasBounds.maxCorner.x);
+            gtk_adjustment_set_lower(hGtkAdjustment, _canvasBounds.corner0.x);
+            gtk_adjustment_set_upper(hGtkAdjustment, _canvasBounds.corner1.x);
             gtk_adjustment_set_value(hGtkAdjustment, viewLeftBottom.x);
             gtk_adjustment_set_step_increment(hGtkAdjustment, _canvasBounds.size.x / 16.0);
             gtk_adjustment_set_page_increment(hGtkAdjustment, _canvasBounds.size.x / 4.0);
             gtk_adjustment_set_page_size(hGtkAdjustment, modelSize.x);
 
-            gtk_adjustment_set_lower(vGtkAdjustment, _canvasBounds.minCorner.y);
-            gtk_adjustment_set_upper(vGtkAdjustment, _canvasBounds.maxCorner.y);
+            gtk_adjustment_set_lower(vGtkAdjustment, _canvasBounds.corner0.y);
+            gtk_adjustment_set_upper(vGtkAdjustment, _canvasBounds.corner1.y);
             gtk_adjustment_set_value(vGtkAdjustment, viewLeftBottom.y);
             gtk_adjustment_set_step_increment(vGtkAdjustment, _canvasBounds.size.y / 16.0);
             gtk_adjustment_set_page_increment(vGtkAdjustment, _canvasBounds.size.y / 4.0);
@@ -634,7 +619,7 @@
             if (_damage.valid) {
                 int x, y, w, h;
                 _damage.getQuantised(x, y, w, h);
-                _drawingArea.queueDrawArea(x, cast(int)_viewSize.y - (y + h), w, h);
+                _drawingArea.queueDrawArea(x, cast(int)_viewBounds.h - (y + h), w, h);
                 _damage = Rectangle.DEFAULT;
             }
         }
@@ -642,11 +627,11 @@
         static double clampZoom(in double zoom) { return clamp(zoom, 0.2, 10.0); }
 
         Point modelToPixel(in Point model) const {
-            return Point.DEFAULT + _viewSize / 2.0 + _zoom * (model - _viewCentre);
+            return _viewBounds.centre + _zoom * (model - _viewCentre);
         }
 
         Point pixelToModel(in Point pixel) const {
-            return _viewCentre + (pixel - _viewSize / 2.0 - Point.DEFAULT) / _zoom;
+            return _viewCentre + (pixel - _viewBounds.centre) / _zoom;
         }
 
         Vector modelToPixel(in Vector model) const {
@@ -677,9 +662,9 @@
         // Model units are millimetres
         // Screen units are pixels
         double _zoom;               // pixels-per-model-unit
-        Vector _viewSize;           // pixel: size of view window in pixels
+        Rectangle _viewBounds;      // pixel: bounds of the viewport in pixels
         Point _viewCentre;          // model: where in the model is the centre of our view
-        Rectangle _canvasBounds;    // model:
+        Rectangle _canvasBounds;    // model: bounds of the canvas in millimetres
 
         // Child widgets:
         HRuler _hRuler;
--- a/doodle/tk/geometry.d	Sat Aug 14 19:39:58 2010 +0930
+++ b/doodle/tk/geometry.d	Sat Aug 14 20:05:55 2010 +0930
@@ -152,12 +152,19 @@
         this(corner1.x, corner1.y, corner.x - corner1.x, corner.y - corner1.y);
     }
 
-    alias position minCorner;
+    double x0() { return _position.x; }
+    double y0() { return _position.y; }
+    double w()  { return _size.x; }
+    double h()  { return _size.y; }
+    double x1() { return x0 + w; }
+    double y1() { return y0 + h; }
+
+    alias position corner0;
     Point position() const { return _position; }
 
     Vector size() const { return _size; }
 
-    Point maxCorner() const { return _position + _size; }
+    Point corner1() const { return _position + _size; }
 
     bool valid() const { return _size.x > 0.0 && _size.y > 0.0; }
 
@@ -171,8 +178,8 @@
             return DEFAULT;
         }
         else {
-            Point max = minExtents(maxCorner(), r.maxCorner());
-            Point min = maxExtents(minCorner(), r.minCorner());
+            Point max = minExtents(corner1(), r.corner1());
+            Point min = maxExtents(corner0(), r.corner0());
 
             if (max.x < min.x || max.y < min.y) {
                 return DEFAULT;
@@ -192,8 +199,8 @@
             return this;
         }
         else {
-            return Rectangle(minExtents(minCorner(), r.minCorner()),
-                             maxExtents(maxCorner(), r.maxCorner()));
+            return Rectangle(minExtents(corner0(), r.corner0()),
+                             maxExtents(corner1(), r.corner1()));
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doodle/tk/pixel_model.d	Sat Aug 14 20:05:55 2010 +0930
@@ -0,0 +1,42 @@
+module doodle.tk.pixel_model;
+
+public {
+    import doodle.tk.geometry;
+}
+
+// FIXME consider using the term Screen instead of Pixel...
+
+class PixelModel {
+    this(in double zoom, in Rectangle canvasBounds, in Rectangle viewBounds) {
+        _zoom = zoom;
+        _viewBounds = viewBounds;
+        _canvasBounds = canvasBounds;
+
+        _viewCentre = _canvasBounds.centre;
+    }
+
+    void consolidateCanvasBounds(in Rectangle requiredCanvasBounds) {
+        Rectangle r = pixelToModel(_viewBounds);
+        _canvasBounds = r | requiredCanvasBounds;
+    }
+
+    // For normalZoom 1.0 -> 100% means the presentation on the screen is
+    // one-to-one with real-life
+    double normalZoom(in double pixelsPerMillimetre) { return _zoom / pixelsPerMillimetre; }
+
+    Point modelToPixel(in Point model) const { return _viewBounds.centre + _zoom * (model - _viewCentre); }
+    Point pixelToModel(in Point pixel) const { return _viewCentre + (pixel - _viewBounds.centre) / _zoom; }
+    Vector modelToPixel(in Vector model) const { return _zoom * model; }
+    Vector pixelToModel(in Vector pixel) const { return pixel / _zoom; }
+    Rectangle modelToPixel(in Rectangle model) const { return Rectangle(modelToPixel(model.position), modelToPixel(model.size)); }
+    Rectangle pixelToModel(in Rectangle model) const { return Rectangle(pixelToModel(model.position), pixelToModel(model.size)); }
+
+    private {
+        // Screen units are pixels
+        // Model units are millimetres
+        double _zoom;               // pixels-per-millimetre
+        Rectangle _viewBounds;      // pixel: bounds of the viewport in pixels
+        Point _viewCentre;          // model: where in the model is the centre of our view
+        Rectangle _canvasBounds;    // model: the bounds of the canvas in millimetres
+    }
+}