Mercurial > projects > doodle
changeset 79:535bae7a7305
Checkpoint
author | "David Bryant <bagnose@gmail.com>" |
---|---|
date | Sun, 15 Aug 2010 23:18:05 +0930 |
parents | 024a5608087f |
children | b759414d2b72 |
files | doodle/fig/select_tool.d doodle/gtk/cairo.d doodle/gtk/canvas.d doodle/gtk/opengl.d doodle/tk/color.d doodle/tk/drawing.d doodle/tk/geometry.d doodle/tk/pixel_model.d |
diffstat | 8 files changed, 169 insertions(+), 107 deletions(-) [+] |
line wrap: on
line diff
--- a/doodle/fig/select_tool.d Sun Aug 15 15:19:14 2010 +0930 +++ b/doodle/fig/select_tool.d Sun Aug 15 23:18:05 2010 +0930 @@ -28,7 +28,7 @@ override bool handleButtonRelease(scope IViewport viewport, in ButtonEvent event) { if (event.buttonName == ButtonName.LEFT && _active) { _active = false; - viewport.damageScreen(feather(Rectangle(_anchorPoint, _currentPoint), LINE_WIDTH / 2.0)); + viewport.damageScreen(growCentre(Rectangle(_anchorPoint, _currentPoint), LINE_WIDTH)); viewport.setCursor(Cursor.DEFAULT); return true; } @@ -39,9 +39,9 @@ override bool handleMotion(scope IViewport viewport, in MotionEvent event) { if (_active) { - viewport.damageScreen(feather(Rectangle(_anchorPoint, _currentPoint), LINE_WIDTH / 2.0)); + viewport.damageScreen(growCentre(Rectangle(_anchorPoint, _currentPoint), LINE_WIDTH)); _currentPoint = event.pixelPoint; - viewport.damageScreen(feather(Rectangle(_anchorPoint, _currentPoint), LINE_WIDTH / 2.0)); + viewport.damageScreen(growCentre(Rectangle(_anchorPoint, _currentPoint), LINE_WIDTH)); } return false;
--- a/doodle/gtk/cairo.d Sun Aug 15 15:19:14 2010 +0930 +++ b/doodle/gtk/cairo.d Sun Aug 15 23:18:05 2010 +0930 @@ -2,9 +2,9 @@ public { import doodle.tk.drawing; + import cairo.Context; } -/* final class CairoDrawable : Drawable { this(Context cr) { assert(cr); @@ -13,11 +13,84 @@ // Drawing overrides: + void setLineStyle(LineStyle style) { + switch (style) { + case LineStyle.SOLID: + _cr.setDash([ 4.0, 4.0 ], 0.0); + break; + case LineStyle.DASHED: + _cr.setDash([ 4.0, 4.0 ], 0.0); + break; + case LineStyle.DOTTED: + _cr.setDash([ 4.0, 4.0 ], 0.0); + break; + default: + assert(0); + } + } + + void setLineWidth(in double width) { _cr.setLineWidth(width); } + + void setColor(in Color color) { _cr.setSourceRgba(color.r, color.g, color.b, color.a); } + + void translate(in Point p) { _cr.translate(p.x, p.y); } + void scale(in double s) { _cr.scale(s, s); } + void pushState() { _cr.save; } void popState() { _cr.restore; } + void drawRectangle(in Rectangle rectangle, bool fill) { + _cr.rectangle(rectangle.position.x, rectangle.position.y, + rectangle.size.x, rectangle.size.y); + } + + void drawEllipse(in Rectangle rectangle, bool fill) { + // NYI + } + + void drawSegment(in Segment segment) { + _cr.moveTo(segment.begin.x, segment.begin.y); + _cr.lineTo(segment.end.x, segment.end.y); + _cr.stroke; + } + + void drawHLine(in double y, in double x0, in double x1) { + _cr.moveTo(x0, y); + _cr.lineTo(x1, y); + _cr.stroke; + } + + void drawVLine(in double x, in double y0, in double y1) { + _cr.moveTo(x, y0); + _cr.lineTo(x, y1); + } + + void drawPoly(in Point[] points, bool fill) { + assert(points.length >= 2); + foreach(i, p; points) { + if (i == 0) { _cr.moveTo(p.x, p.y); } + else { _cr.lineTo(p.x, p.y); } + } + if (fill) { _cr.fill; } else { _cr.stroke; } + } + + void setFontFace(in FontFace face) { + // NYI + } + + void setFontSize(in double size) { + // NYI + } + + void drawText(in string text) { + // NYI + } + + void measureText(in string text, out Rectangle logicalBounds, out Rectangle totalBounds) const { + // NYI + } + private { Context _cr; } } -*/
--- a/doodle/gtk/canvas.d Sun Aug 15 15:19:14 2010 +0930 +++ b/doodle/gtk/canvas.d Sun Aug 15 23:18:05 2010 +0930 @@ -35,23 +35,18 @@ import std.stdio; } -// -// TODO -// Pass out a scope Drawing reference to the layers for drawing on instead of cairo context. -// Create a class called LayerStack so we don't have to provide that non-gtk behaviour here. -// - final class Canvas : Table, private IViewport { this(in Layer[] layers, IEventHandler eventHandler, IGrid grid, in double pixelsPerMillimetre) { super(3, 3, 0); _damageScreen = Rectangle.DEFAULT; - _layerStack = new LayerStack(layers); _eventHandler = eventHandler; _grid = grid; _pixelsPerMillimetre = pixelsPerMillimetre; + _layerStack = new LayerStack(layers); + // Create our child widgets and register callbacks _hRuler = new HRuler; @@ -136,6 +131,13 @@ AttachOptions.SHRINK, AttachOptions.FILL | AttachOptions.EXPAND, 0, 0); + + _cursors = [ + Cursor.DEFAULT : CursorType.ARROW, + Cursor.HAND : CursorType.HAND1, + Cursor.CROSSHAIR : CursorType.CROSSHAIR, + Cursor.PENCIL : CursorType.PENCIL + ]; } protected { // XXX the compiler complains about unimplemented methods if this is private @@ -144,9 +146,7 @@ void zoomRelative(in Point screenDatum, in double factor) { _screenModel.zoomRelative(factor, screenDatum); - consolidateBounds; - updateAdjustments; updateRulers; _grid.zoomChanged(_screenModel.zoom); @@ -155,36 +155,14 @@ void panRelative(in Vector screenDisplacement) { _screenModel.panRelativeScreen(screenDisplacement); - consolidateBounds; - updateAdjustments; updateRulers; queueDraw; } void setCursor(in Cursor cursor) { - // FIXME how about an associative array instead of a switch statement? - CursorType cursorType; - - switch (cursor) { - case Cursor.DEFAULT: - cursorType = CursorType.ARROW; - break; - case Cursor.HAND: - cursorType = CursorType.HAND1; - break; - case Cursor.CROSSHAIR: - cursorType = CursorType.CROSSHAIR; - break; - case Cursor.PENCIL: - cursorType = CursorType.PENCIL; - break; - default: - assert(0); - } - - _drawingArea.setCursor(new gdk.Cursor.Cursor(cursorType)); + _drawingArea.setCursor(new gdk.Cursor.Cursor(_cursors[cursor])); } void damageModel(in Rectangle area) { @@ -199,14 +177,9 @@ private { void initialiseBounds(in Rectangle viewBoundsScreen) { - Rectangle lb = _layerStack.bounds; - - // FIXME use a function that grows a rectangle about its centre - // and change 2.0 to a class-level constant - Rectangle paddedLayerBounds = expand(move(lb, - lb.size), 2.0 * lb.size); - + Rectangle layerBounds = _layerStack.bounds; + Rectangle paddedLayerBounds = growCentre(layerBounds, 2 * layerBounds.size); _screenModel = new ScreenModel(0.25 * _pixelsPerMillimetre, paddedLayerBounds, viewBoundsScreen); - _grid.zoomChanged(_screenModel.zoom); updateAdjustments; @@ -214,11 +187,8 @@ } void consolidateBounds() { - Rectangle lb = _layerStack.bounds; - - // FIXME likewise as above - Rectangle paddedLayerBounds = expand(move(lb, - lb.size), 2.0 * lb.size); - + Rectangle layerBounds = _layerStack.bounds; + Rectangle paddedLayerBounds = growCentre(layerBounds, 2 * layerBounds.size); _screenModel.consolidateCanvasBounds(paddedLayerBounds); updateAdjustments; @@ -229,13 +199,8 @@ assert(widget is _drawingArea); Rectangle viewBoundsScreen = Rectangle(Point(0.0, 0.0), Vector(cast(double)event.width, cast(double)event.height)); - - if (_screenModel is null) { - initialiseBounds(viewBoundsScreen); - } - else { - consolidateBounds; - } + if (_screenModel is null) { initialiseBounds(viewBoundsScreen); } + else { consolidateBounds; } return true; } @@ -254,14 +219,11 @@ Rectangle screenDamage = event is null ? _screenModel.viewBoundsScreen : - // FIXME next line sucks Rectangle(_screenModel.viewBoundsScreen.position + Vector(cast(double)event.area.x, _screenModel.viewBoundsScreen.h - cast(double)(event.area.y + event.area.height)), Vector(cast(double)event.area.width, cast(double)event.area.height)); Rectangle modelDamage = _screenModel.screenToModel(screenDamage); - //trace("Screen damage: %s, model damage: %s", screenDamage, modelDamage); - modelCr.save; screenCr.save; { { // Setup model context and clip @@ -400,7 +362,7 @@ } void updateRulers() { - immutable Point viewLeftBottom = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1); + immutable Point viewLeftBottom = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner0); immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1); // Define these just to obtain the position @@ -424,11 +386,10 @@ immutable Point viewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0)); immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1); - // Adjust the canvas size if necessary FIXME is this required?? + // Adjust the canvas size if necessary _screenModel.canvasAccommodate(Rectangle(viewLeftBottom, viewRightTop)); - // FIXME - Rectangle modelSize = _screenModel.screenToModel(_screenModel.viewBoundsScreen); + Rectangle viewBoundsModel = _screenModel.viewBoundsModel; // Update the adjustments @@ -440,14 +401,14 @@ gtk_adjustment_set_value(hGtkAdjustment, viewLeftBottom.x); gtk_adjustment_set_step_increment(hGtkAdjustment, _screenModel.canvasBoundsModel.w / 16.0); gtk_adjustment_set_page_increment(hGtkAdjustment, _screenModel.canvasBoundsModel.w / 4.0); - gtk_adjustment_set_page_size(hGtkAdjustment, modelSize.w); + gtk_adjustment_set_page_size(hGtkAdjustment, viewBoundsModel.w); gtk_adjustment_set_lower(vGtkAdjustment, _screenModel.canvasBoundsModel.y0); gtk_adjustment_set_upper(vGtkAdjustment, _screenModel.canvasBoundsModel.y1); gtk_adjustment_set_value(vGtkAdjustment, viewLeftBottom.y); gtk_adjustment_set_step_increment(vGtkAdjustment, _screenModel.canvasBoundsModel.h / 16.0); gtk_adjustment_set_page_increment(vGtkAdjustment, _screenModel.canvasBoundsModel.h / 4.0); - gtk_adjustment_set_page_size(vGtkAdjustment, modelSize.h); + gtk_adjustment_set_page_size(vGtkAdjustment, viewBoundsModel.h); _hAdjustment.changed; _hAdjustment.valueChanged; @@ -466,14 +427,15 @@ void onRealize(Widget widget) { assert(widget is _drawingArea); - //writefln("Got realize\n"); _drawingArea.grabFocus(); } - LayerStack _layerStack; IEventHandler _eventHandler; IGrid _grid; double _pixelsPerMillimetre; + LayerStack _layerStack; + + immutable CursorType[Cursor] _cursors; // Child widgets: HRuler _hRuler; @@ -484,7 +446,7 @@ Adjustment _vAdjustment; VScrollbar _vScrollbar; - Rectangle _damageScreen; // in screens + Rectangle _damageScreen; ScreenModel _screenModel; } }
--- a/doodle/gtk/opengl.d Sun Aug 15 15:19:14 2010 +0930 +++ b/doodle/gtk/opengl.d Sun Aug 15 23:18:05 2010 +0930 @@ -5,6 +5,11 @@ } /* -final class OpenGLDrawing : Drawing { +final class OpenGLDrawing : Drawable { + + // Drawing overrides: + + void setLineStyle(LineStyle style) { + } } */
--- a/doodle/tk/color.d Sun Aug 15 15:19:14 2010 +0930 +++ b/doodle/tk/color.d Sun Aug 15 23:18:05 2010 +0930 @@ -14,6 +14,11 @@ // TODO // hsv, grey, etc. + double r() const { return _r; } + double g() const { return _g; } + double b() const { return _b; } + double a() const { return _a; } + private { double _r, _g, _b, _a; }
--- a/doodle/tk/drawing.d Sun Aug 15 15:19:14 2010 +0930 +++ b/doodle/tk/drawing.d Sun Aug 15 23:18:05 2010 +0930 @@ -2,6 +2,7 @@ public { import doodle.tk.geometry; + import doodle.tk.color; } interface Drawable { @@ -11,32 +12,36 @@ DOTTED } - void setLineStyle(LineStyle style); - void setLineThickness(in double thickness); - //void setLineColor(in Color color); - //void setFillColor(in Color color); + enum FontFace { + NORMAL + } + + // Low-level state manipulation - void drawRectangle(in Rectangle rectangle, bool fill); - void drawEllipse(in Rectangle rectangle, bool fill); - void drawSegment(in Segment segment); - void drawHLine(in double y0, in double x0, in double x1); - void drawVLine(in double x0, in double y0, in double y1); - void drawPoly(in Point[] points, bool fill); + void setLineStyle(LineStyle style); + void setLineWidth(in double width); + void setColor(in Color color); + + void translate(in Point p); + void scale(in double s); void pushState(); // Copies all of current state void popState(); // Restores all of previous state - void translate(in Vector v); - void translate(in Point p); - void scale(in Vector v); - void zoom(in double z); + // High-level drawing routines - //void setFontFace; - //void setFontSize; + void drawRectangle(in Rectangle rectangle, bool fill); + void drawEllipse(in Rectangle rectangle, bool fill); + void drawSegment(in Segment segment); + void drawHLine(in double y, in double x0, in double x1); + void drawVLine(in double x, in double y0, in double y1); + void drawPoly(in Point[] points, bool fill); + + // Text routines + + void setFontFace(in FontFace face); + void setFontSize(in double size); void drawText(in string text); - void measureText(in string text, out Rectangle logicalBounds, out Rectangle totalBounds); - - // How to fit fonts, metrics, etc in here? - // Initially let's just support one font + void measureText(in string text, out Rectangle logicalBounds, out Rectangle totalBounds) const; }
--- a/doodle/tk/geometry.d Sun Aug 15 15:19:14 2010 +0930 +++ b/doodle/tk/geometry.d Sun Aug 15 23:18:05 2010 +0930 @@ -113,7 +113,8 @@ } } -Vector normalise(in Vector v) { +/* +Vector normal(in Vector v) { double l = v.length; if (l < 1e-9) { // TODO consolidate numerical stability constants @@ -124,6 +125,7 @@ return v / l; } } +*/ // // A rectangle in 2D space. @@ -152,12 +154,12 @@ this(corner1.x, corner1.y, corner.x - corner1.x, corner.y - corner1.y); } - 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; } + double x0() const { return _position.x; } + double y0() const { return _position.y; } + double w() const { return _size.x; } + double h() const { return _size.y; } + double x1() const { return x0 + w; } + double y1() const { return y0 + h; } alias position corner0; Point position() const { return _position; } @@ -236,9 +238,18 @@ } } +Rectangle growCentre(in Rectangle r, in Vector amount) { + return Rectangle(r.x0 - amount.x / 2, r.y0 - amount.y / 2, r.w + amount.x, r.h + amount.y); +} + +Rectangle growCentre(in Rectangle r, in double amount) { + return Rectangle(r.x0 - amount / 2, r.y0 - amount / 2, r.w + amount, r.h + amount); +} + // TODO review these functions. // Want a clear and simple set. +/+ Rectangle move(in Rectangle r, in Vector displacement) { return Rectangle(r.position + displacement, r.size); } @@ -260,15 +271,18 @@ Rectangle shrink(in Rectangle r, in Vector shrink_amount) { return Rectangle(r.position, r.size - shrink_amount); } ++/ // Operations about the centre +/+ Rectangle feather(in Rectangle r, double amount) { // feather isn't the right name assert(amount >= 0.0); assert(!isnan(amount)); return Rectangle(Point(r.position.x - amount, r.position.y - amount), Vector(r.size.x + 2.0 * amount, r.size.y + 2.0 * amount)); } ++/ private { // This function computes the intersection of two lines. @@ -388,9 +402,11 @@ } } +/* Segment reverse(in Segment s) { return Segment(s.end, s.begin); } +*/ bool intersection(in Segment a, in Segment b, out Point p) { Point pa1 = a.begin;
--- a/doodle/tk/pixel_model.d Sun Aug 15 15:19:14 2010 +0930 +++ b/doodle/tk/pixel_model.d Sun Aug 15 23:18:05 2010 +0930 @@ -24,13 +24,8 @@ _viewCentreModel = _canvasBoundsModel.centre; } - void consolidateCanvasBounds(in Rectangle requiredCanvasBounds) { - _canvasBoundsModel = screenToModel(_viewBoundsScreen) | requiredCanvasBounds; - } - - void canvasAccommodate(in Rectangle bounds) { - _canvasBoundsModel = _canvasBoundsModel | bounds; - } + void consolidateCanvasBounds(in Rectangle requiredCanvasBounds) { _canvasBoundsModel = screenToModel(_viewBoundsScreen) | requiredCanvasBounds; } + void canvasAccommodate(in Rectangle bounds) { _canvasBoundsModel = _canvasBoundsModel | bounds; } void zoomRelative(in double factor, in Point screenDatum) { // Work out screen distance from current centre to datum, @@ -46,12 +41,13 @@ void panRelativeScreen(in Vector screenDisplacement) { _viewCentreModel = _viewCentreModel + screenToModel(screenDisplacement); } void panRelativeModel(in Vector modelDisplacement) { _viewCentreModel = _viewCentreModel + modelDisplacement; } - // For userZoom 1.0 -> 100% means the presentation on the screen is - // one-to-one with real-life - double userZoom(in double screensPerMillimetre) const { return _zoom / screensPerMillimetre; } + // For userZoom 1.0 -> 100% means the presentation on the screen is one-to-one with real-life + double userZoom(in double pixelsPerMillimetre) const { return _zoom / pixelsPerMillimetre; } double zoom() const { return _zoom; } Rectangle viewBoundsScreen() const { return _viewBoundsScreen; } + Rectangle viewBoundsModel() const { return screenToModel(_viewBoundsScreen); } Rectangle canvasBoundsModel() const { return _canvasBoundsModel; } + Rectangle canvasBoundsScreen() const { return modelToScreen(_canvasBoundsModel); } Point modelToScreen(in Point model) const { return _viewBoundsScreen.centre + _zoom * (model - _viewCentreModel); } Point screenToModel(in Point screen) const { return _viewCentreModel + (screen - _viewBoundsScreen.centre) / _zoom; } @@ -61,7 +57,7 @@ Rectangle screenToModel(in Rectangle model) const { return Rectangle(screenToModel(model.position), screenToModel(model.size)); } private { - static double clampZoom(in double zoom) { return clamp(zoom, 0.1, 10.0); } + static double clampZoom(in double zoom) { return clamp(zoom, 1e-1, 1e2); } // Screen units are pixels // Model units are millimetres