# HG changeset patch # User "David Bryant " # Date 1281801982 -34200 # Node ID 15ca7d5cd1ed06850d659d570c104bf2599476af # Parent 78bc2046256e0976e218aa41055000267f477461 The rulers are broken diff -r 78bc2046256e -r 15ca7d5cd1ed doodle/core/misc.d --- a/doodle/core/misc.d Sun Aug 15 01:21:14 2010 +0930 +++ b/doodle/core/misc.d Sun Aug 15 01:36:22 2010 +0930 @@ -18,3 +18,5 @@ else if (v > max) { return max; } else { return v; } } + +// wrap? diff -r 78bc2046256e -r 15ca7d5cd1ed doodle/dia/icanvas.d --- a/doodle/dia/icanvas.d Sun Aug 15 01:21:14 2010 +0930 +++ b/doodle/dia/icanvas.d Sun Aug 15 01:36:22 2010 +0930 @@ -14,13 +14,12 @@ "DEFAULT", "HAND", "CROSSHAIR", "PENCIL")); interface IViewport { - void zoomRelative(in Point pixelDatum, in double factor); - void panRelative(in Vector pixelDisplacement); + void zoomRelative(in Point screenDatum, in double factor); + void panRelative(in Vector screenDisplacement); void setCursor(in Cursor cursor); - // FIXME get rid of these and accumulate damage during event handling - void damageModel(in Rectangle area); // FIXME could be an inout parameter of the event handling, or a special scope Damage object that supports growth only - void damagePixel(in Rectangle area); // FIXME as above + void damageModel(in Rectangle area); + void damageScreen(in Rectangle area); } final class Damage { @@ -64,7 +63,7 @@ Rectangle bounds() const; - void draw(in Rectangle pixelDamage, scope Context pixelCr, + void draw(in Rectangle screenDamage, scope Context screenCr, in Rectangle modelDamage, scope Context modelCr) const; private { diff -r 78bc2046256e -r 15ca7d5cd1ed doodle/fig/select_tool.d --- a/doodle/fig/select_tool.d Sun Aug 15 01:21:14 2010 +0930 +++ b/doodle/fig/select_tool.d Sun Aug 15 01:36:22 2010 +0930 @@ -28,7 +28,7 @@ override bool handleButtonRelease(scope IViewport viewport, in ButtonEvent event) { if (event.buttonName == ButtonName.LEFT && _active) { _active = false; - viewport.damagePixel(feather(Rectangle(_anchorPoint, _currentPoint), LINE_WIDTH / 2.0)); + viewport.damageScreen(feather(Rectangle(_anchorPoint, _currentPoint), LINE_WIDTH / 2.0)); viewport.setCursor(Cursor.DEFAULT); return true; } @@ -39,9 +39,9 @@ override bool handleMotion(scope IViewport viewport, in MotionEvent event) { if (_active) { - viewport.damagePixel(feather(Rectangle(_anchorPoint, _currentPoint), LINE_WIDTH / 2.0)); + viewport.damageScreen(feather(Rectangle(_anchorPoint, _currentPoint), LINE_WIDTH / 2.0)); _currentPoint = event.pixelPoint; - viewport.damagePixel(feather(Rectangle(_anchorPoint, _currentPoint), LINE_WIDTH / 2.0)); + viewport.damageScreen(feather(Rectangle(_anchorPoint, _currentPoint), LINE_WIDTH / 2.0)); } return false; diff -r 78bc2046256e -r 15ca7d5cd1ed doodle/gtk/canvas.d --- a/doodle/gtk/canvas.d Sun Aug 15 01:21:14 2010 +0930 +++ b/doodle/gtk/canvas.d Sun Aug 15 01:36:22 2010 +0930 @@ -6,7 +6,6 @@ } private { - import doodle.core.misc; import doodle.core.logging; import doodle.tk.pixel_model; import doodle.tk.cairo; @@ -144,18 +143,18 @@ // IViewport overrides: void zoomRelative(in Point screenDatum, in double factor) { - _pixelModel.zoomRelative(factor, screenDatum); + _screenModel.zoomRelative(factor, screenDatum); consolidateBounds; updateAdjustments; updateRulers; - _grid.zoomChanged(_pixelModel.zoom); + _grid.zoomChanged(_screenModel.zoom); queueDraw; } void panRelative(in Vector screenDisplacement) { - _pixelModel.panRelativePixel(screenDisplacement); + _screenModel.panRelativeScreen(screenDisplacement); consolidateBounds; @@ -165,6 +164,7 @@ } void setCursor(in Cursor cursor) { + // FIXME how about an associative array instead of a switch statement? CursorType cursorType; switch (cursor) { @@ -188,26 +188,26 @@ } void damageModel(in Rectangle area) { - _damageScreen = _damageScreen | _pixelModel.modelToPixel(area); + _damageScreen = _damageScreen | _screenModel.modelToScreen(area); } - void damagePixel(in Rectangle area) { + void damageScreen(in Rectangle area) { _damageScreen = _damageScreen | area; } } private { - void initialiseBounds(in Rectangle viewBounds) { + 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); - _pixelModel = new PixelModel(0.25 * _pixelsPerMillimetre, paddedLayerBounds, viewBounds); + _screenModel = new ScreenModel(0.25 * _pixelsPerMillimetre, paddedLayerBounds, viewBoundsScreen); - _grid.zoomChanged(_pixelModel.zoom); + _grid.zoomChanged(_screenModel.zoom); updateAdjustments; updateRulers; @@ -219,7 +219,7 @@ // FIXME likewise as above Rectangle paddedLayerBounds = expand(move(lb, - lb.size), 2.0 * lb.size); - _pixelModel.consolidateCanvasBounds(paddedLayerBounds); + _screenModel.consolidateCanvasBounds(paddedLayerBounds); updateAdjustments; updateRulers; @@ -228,10 +228,10 @@ bool onConfigure(GdkEventConfigure * event, Widget widget) { assert(widget is _drawingArea); - Rectangle viewBounds = Rectangle(Point(0.0, 0.0), Vector(cast(double)event.width, cast(double)event.height)); + Rectangle viewBoundsScreen = Rectangle(Point(0.0, 0.0), Vector(cast(double)event.width, cast(double)event.height)); - if (_pixelModel is null) { - initialiseBounds(viewBounds); + if (_screenModel is null) { + initialiseBounds(viewBoundsScreen); } else { consolidateBounds; @@ -250,25 +250,25 @@ //trace("Got expose %dx%d\n", width, height); scope modelCr = new Context(dr); - scope pixelCr = new Context(dr); + scope screenCr = new Context(dr); - Rectangle pixelDamage = - event is null ? _pixelModel.viewBounds : + Rectangle screenDamage = + event is null ? _screenModel.viewBoundsScreen : // FIXME next line sucks - Rectangle(_pixelModel.viewBounds.position + Vector(cast(double)event.area.x, _pixelModel.viewBounds.h - cast(double)(event.area.y + event.area.height)), + 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 = _pixelModel.pixelToModel(pixelDamage); + Rectangle modelDamage = _screenModel.screenToModel(screenDamage); - //trace("Pixel damage: %s, model damage: %s", pixelDamage, modelDamage); + //trace("Screen damage: %s, model damage: %s", screenDamage, modelDamage); - modelCr.save; pixelCr.save; { + modelCr.save; screenCr.save; { { // Setup model context and clip - modelCr.translate(0.0, _pixelModel.viewBounds.h); - modelCr.scale(_pixelModel.zoom, -_pixelModel.zoom); + modelCr.translate(0.0, _screenModel.viewBoundsScreen.h); + modelCr.scale(_screenModel.zoom, -_screenModel.zoom); - immutable Point viewLeftBottom = _pixelModel.pixelToModel(Point(0.0, 0.0)); + immutable Point viewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0)); modelCr.translate(-viewLeftBottom.x, -viewLeftBottom.y); rectangle(modelCr, modelDamage); @@ -276,23 +276,23 @@ } { - // Setup pixel context and clip - pixelCr.translate(0.0, _pixelModel.viewBounds.h); - pixelCr.scale(1.0, -1.0); + // Setup screen context and clip + screenCr.translate(0.0, _screenModel.viewBoundsScreen.h); + screenCr.scale(1.0, -1.0); - rectangle(pixelCr, pixelDamage); - pixelCr.clip; + rectangle(screenCr, screenDamage); + screenCr.clip; } - pixelCr.save; { + screenCr.save; { // Fill the background with light grey - pixelCr.setSourceRgba(0.9, 0.9, 0.9, 1.0); - rectangle(pixelCr, pixelDamage); - pixelCr.fill; - } pixelCr.restore; + screenCr.setSourceRgba(0.9, 0.9, 0.9, 1.0); + rectangle(screenCr, screenDamage); + screenCr.fill; + } screenCr.restore; - _layerStack.draw(pixelDamage, pixelCr, modelDamage, modelCr); - } pixelCr.restore; modelCr.restore; + _layerStack.draw(screenDamage, screenCr, modelDamage, modelCr); + } screenCr.restore; modelCr.restore; return true; } @@ -300,7 +300,7 @@ bool onButtonPress(GdkEventButton * event, Widget widget) { assert(widget is _drawingArea); - auto buttonEvent = makeButtonEvent(event, _pixelModel); + auto buttonEvent = makeButtonEvent(event, _screenModel); _eventHandler.handleButtonPress(this, buttonEvent); fixDamage; return true; @@ -309,7 +309,7 @@ bool onButtonRelease(GdkEventButton * event, Widget widget) { assert(widget is _drawingArea); - auto buttonEvent = makeButtonEvent(event, _pixelModel); + auto buttonEvent = makeButtonEvent(event, _screenModel); _eventHandler.handleButtonRelease(this, buttonEvent); fixDamage; return true; @@ -332,7 +332,7 @@ bool onKeyReleaseEvent(GdkEventKey * event, Widget widget) { assert(widget is _drawingArea); - _eventHandler.handleKeyRelease(this, makeKeyEvent(event, _pixelModel)); + _eventHandler.handleKeyRelease(this, makeKeyEvent(event, _screenModel)); fixDamage; return true; } @@ -340,13 +340,11 @@ bool onMotionNotify(GdkEventMotion * event, Widget widget) { assert(widget is _drawingArea); - { - // Pass the events on to the rulers so that they update - gtk_widget_event(_hRuler.getWidgetStruct(), cast(GdkEvent *)event); - gtk_widget_event(_vRuler.getWidgetStruct(), cast(GdkEvent *)event); - } + // Pass the events on to the rulers so that they update + gtk_widget_event(_hRuler.getWidgetStruct(), cast(GdkEvent *)event); + gtk_widget_event(_vRuler.getWidgetStruct(), cast(GdkEvent *)event); - _eventHandler.handleMotion(this, makeMotionEvent(event, _pixelModel)); + _eventHandler.handleMotion(this, makeMotionEvent(event, _screenModel)); fixDamage; return true; } @@ -354,7 +352,7 @@ bool onScroll(GdkEventScroll * event, Widget widget) { assert(widget is _drawingArea); - _eventHandler.handleScroll(this, makeScrollEvent(event, _pixelModel)); + _eventHandler.handleScroll(this, makeScrollEvent(event, _screenModel)); fixDamage; return true; } @@ -362,7 +360,7 @@ bool onEnterNotify(GdkEventCrossing * event, Widget widget) { assert(widget is _drawingArea); - _eventHandler.handleEnter(this, makeCrossingEvent(event, _pixelModel)); + _eventHandler.handleEnter(this, makeCrossingEvent(event, _screenModel)); fixDamage; return true; } @@ -370,7 +368,7 @@ bool onLeaveNotify(GdkEventCrossing * event, Widget widget) { assert(widget is _drawingArea); - _eventHandler.handleLeave(this, makeCrossingEvent(event, _pixelModel)); + _eventHandler.handleLeave(this, makeCrossingEvent(event, _screenModel)); fixDamage; return true; } @@ -406,19 +404,19 @@ GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct; GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct; - Point oldViewLeftBottom = _pixelModel.pixelToModel(Point(0.0, 0.0)); + Point oldViewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0)); Point newViewLeftBottom = Point(gtk_adjustment_get_value(hGtkAdjustment), gtk_adjustment_get_value(vGtkAdjustment)); - _pixelModel.panRelativeModel(newViewLeftBottom - oldViewLeftBottom); + _screenModel.panRelativeModel(newViewLeftBottom - oldViewLeftBottom); updateRulers; queueDraw; } void updateRulers() { - immutable Point viewLeftBottom = _pixelModel.pixelToModel(Point(0.0, 0.0)); - immutable Point viewRightTop = _pixelModel.pixelToModel(_pixelModel.viewBounds.corner1); + immutable Point viewLeftBottom = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1); + immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1); // Define these just to obtain the position // below and we can preserve it @@ -428,42 +426,42 @@ _hRuler.setRange(viewLeftBottom.x, viewRightTop.x, position, - _pixelModel.zoom * 50.0); + _screenModel.zoom * 50.0); _vRuler.getRange(lower, upper, position, maxSize); _vRuler.setRange(viewRightTop.y, viewLeftBottom.y, position, - _pixelModel.zoom * 50.0); + _screenModel.zoom * 50.0); } void updateAdjustments() { - immutable Point viewLeftBottom = _pixelModel.pixelToModel(Point(0.0, 0.0)); - immutable Point viewRightTop = _pixelModel.pixelToModel(_pixelModel.viewBounds.corner1); + 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?? - _pixelModel.canvasAccommodate(Rectangle(viewLeftBottom, viewRightTop)); + _screenModel.canvasAccommodate(Rectangle(viewLeftBottom, viewRightTop)); // FIXME - Rectangle modelSize = _pixelModel.pixelToModel(_pixelModel.viewBounds); + Rectangle modelSize = _screenModel.screenToModel(_screenModel.viewBoundsScreen); // Update the adjustments GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct; GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct; - gtk_adjustment_set_lower(hGtkAdjustment, _pixelModel.canvasBounds.x0); - gtk_adjustment_set_upper(hGtkAdjustment, _pixelModel.canvasBounds.x1); + gtk_adjustment_set_lower(hGtkAdjustment, _screenModel.canvasBoundsModel.x0); + gtk_adjustment_set_upper(hGtkAdjustment, _screenModel.canvasBoundsModel.x1); gtk_adjustment_set_value(hGtkAdjustment, viewLeftBottom.x); - gtk_adjustment_set_step_increment(hGtkAdjustment, _pixelModel.canvasBounds.w / 16.0); - gtk_adjustment_set_page_increment(hGtkAdjustment, _pixelModel.canvasBounds.w / 4.0); + 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_lower(vGtkAdjustment, _pixelModel.canvasBounds.y0); - gtk_adjustment_set_upper(vGtkAdjustment, _pixelModel.canvasBounds.y1); + 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, _pixelModel.canvasBounds.h / 16.0); - gtk_adjustment_set_page_increment(vGtkAdjustment, _pixelModel.canvasBounds.h / 4.0); + 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); _hAdjustment.changed; @@ -476,7 +474,7 @@ if (_damageScreen.valid) { int x, y, w, h; _damageScreen.getQuantised(x, y, w, h); - _drawingArea.queueDrawArea(x, cast(int)_pixelModel.viewBounds.h - (y + h), w, h); + _drawingArea.queueDrawArea(x, cast(int)_screenModel.viewBoundsScreen.h - (y + h), w, h); _damageScreen = Rectangle.DEFAULT; } } @@ -501,7 +499,7 @@ Adjustment _vAdjustment; VScrollbar _vScrollbar; - Rectangle _damageScreen; // in pixels - PixelModel _pixelModel; + Rectangle _damageScreen; // in screens + ScreenModel _screenModel; } } diff -r 78bc2046256e -r 15ca7d5cd1ed doodle/gtk/events.d --- a/doodle/gtk/events.d Sun Aug 15 01:21:14 2010 +0930 +++ b/doodle/gtk/events.d Sun Aug 15 01:36:22 2010 +0930 @@ -29,12 +29,12 @@ } */ -ButtonEvent makeButtonEvent(const GdkEventButton * event, in PixelModel pixelModel) { - Point pixelPoint = Point(event.x + 0.5, pixelModel.viewBounds.h - (event.y + 0.5)); - Point modelPoint = pixelModel.pixelToModel(pixelPoint); +ButtonEvent makeButtonEvent(const GdkEventButton * event, in ScreenModel screenModel) { + Point screenPoint = Point(event.x + 0.5, screenModel.viewBoundsScreen.h - (event.y + 0.5)); + Point modelPoint = screenModel.screenToModel(screenPoint); return new ButtonEvent(gtk2tkButtonAction(event.type), gtk2tkButtonName(event.button), - pixelPoint, modelPoint, gtk2tkMask(event.state)); + screenPoint, modelPoint, gtk2tkMask(event.state)); } /* @@ -53,11 +53,11 @@ } */ -MotionEvent makeMotionEvent(const GdkEventMotion * event, in PixelModel pixelModel) { - Point pixelPoint = Point(event.x + 0.5, pixelModel.viewBounds.h - (event.y + 0.5)); - Point modelPoint = pixelModel.pixelToModel(pixelPoint); +MotionEvent makeMotionEvent(const GdkEventMotion * event, in ScreenModel screenModel) { + Point screenPoint = Point(event.x + 0.5, screenModel.viewBoundsScreen.h - (event.y + 0.5)); + Point modelPoint = screenModel.screenToModel(screenPoint); - return new MotionEvent(pixelPoint, modelPoint, gtk2tkMask(event.state)); + return new MotionEvent(screenPoint, modelPoint, gtk2tkMask(event.state)); } /* @@ -77,7 +77,7 @@ } */ -KeyEvent makeKeyEvent(const GdkEventKey * event, in PixelModel pixelModel) { +KeyEvent makeKeyEvent(const GdkEventKey * event, in ScreenModel screenModel) { return new KeyEvent(event.string[0..strlen(event.string)].idup, event.keyval, gtk2tkMask(event.state)); @@ -98,11 +98,11 @@ } */ -ScrollEvent makeScrollEvent(const GdkEventScroll * event, in PixelModel pixelModel) { - Point pixelPoint = Point(event.x + 0.5, pixelModel.viewBounds.h - (event.y + 0.5)); - Point modelPoint = pixelModel.pixelToModel(pixelPoint); +ScrollEvent makeScrollEvent(const GdkEventScroll * event, in ScreenModel screenModel) { + Point screenPoint = Point(event.x + 0.5, screenModel.viewBoundsScreen.h - (event.y + 0.5)); + Point modelPoint = screenModel.screenToModel(screenPoint); return new ScrollEvent(gtk2tkDirection(event.direction), - pixelPoint, + screenPoint, modelPoint, gtk2tkMask(event.state)); } @@ -134,11 +134,11 @@ } */ -CrossingEvent makeCrossingEvent(const GdkEventCrossing * event, in PixelModel pixelModel) { - Point pixelPoint = Point(event.x + 0.5, pixelModel.viewBounds.h - (event.y + 0.5)); - Point modelPoint = pixelModel.pixelToModel(pixelPoint); +CrossingEvent makeCrossingEvent(const GdkEventCrossing * event, in ScreenModel screenModel) { + Point screenPoint = Point(event.x + 0.5, screenModel.viewBoundsScreen.h - (event.y + 0.5)); + Point modelPoint = screenModel.screenToModel(screenPoint); return new CrossingEvent(gtk2tkCrossingMode(event.mode), - pixelPoint, + screenPoint, modelPoint, gtk2tkMask(event.state)); } diff -r 78bc2046256e -r 15ca7d5cd1ed doodle/tk/pixel_model.d --- a/doodle/tk/pixel_model.d Sun Aug 15 01:21:14 2010 +0930 +++ b/doodle/tk/pixel_model.d Sun Aug 15 01:36:22 2010 +0930 @@ -1,4 +1,4 @@ -module doodle.tk.pixel_model; +module doodle.tk.screen_model; public { import doodle.tk.geometry; @@ -8,66 +8,64 @@ import doodle.core.misc; } -// FIXME consider using the term Screen instead of Pixel... - -// This class manages the relationship between pixel space and model space. +// This class manages the relationship between screen space and model space. // It provides convenient high-level operations. // -// x and y run right and up respectively for pixel and model space +// x and y run right and up respectively for screen and model space -class PixelModel { - this(in double zoom, in Rectangle canvasBounds, in Rectangle viewBounds) { +class ScreenModel { + this(in double zoom, in Rectangle canvasBoundsModel, in Rectangle viewBoundsScreen) { _zoom = zoom; - _viewBoundsScreen = viewBounds; - _canvasBoundsModel = canvasBounds; + _viewBoundsScreen = viewBoundsScreen; + _canvasBoundsModel = canvasBoundsModel; // Choose the centre of the canvas as the centre of the view _viewCentreModel = _canvasBoundsModel.centre; } void consolidateCanvasBounds(in Rectangle requiredCanvasBounds) { - _canvasBoundsModel = pixelToModel(_viewBoundsScreen) | requiredCanvasBounds; + _canvasBoundsModel = screenToModel(_viewBoundsScreen) | requiredCanvasBounds; } void canvasAccommodate(in Rectangle bounds) { _canvasBoundsModel = _canvasBoundsModel | bounds; } - void zoomRelative(in double factor, in Point pixelDatum) { - // Work out pixel distance from current centre to datum, + void zoomRelative(in double factor, in Point screenDatum) { + // Work out screen distance from current centre to datum, // Do the zoom, then work out the new centre that keeps the - // pixel distance the same + // screen distance the same - Point oldModelDatum = pixelToModel(pixelDatum); - Vector pixelDistance = modelToPixel(oldModelDatum - _viewCentreModel); + Point oldModelDatum = screenToModel(screenDatum); + Vector screenDistance = modelToScreen(oldModelDatum - _viewCentreModel); _zoom = clampZoom(zoom * factor); - _viewCentreModel = oldModelDatum - pixelToModel(pixelDistance); + _viewCentreModel = oldModelDatum - screenToModel(screenDistance); } - void panRelativePixel(in Vector pixelDisplacement) { _viewCentreModel = _viewCentreModel + pixelToModel(pixelDisplacement); } + void panRelativeScreen(in Vector screenDisplacement) { _viewCentreModel = _viewCentreModel + screenToModel(screenDisplacement); } void panRelativeModel(in Vector modelDisplacement) { _viewCentreModel = _viewCentreModel + modelDisplacement; } - // For normalZoom 1.0 -> 100% means the presentation on the screen is + // For userZoom 1.0 -> 100% means the presentation on the screen is // one-to-one with real-life - double normalZoom(in double pixelsPerMillimetre) const { return _zoom / pixelsPerMillimetre; } + double userZoom(in double screensPerMillimetre) const { return _zoom / screensPerMillimetre; } double zoom() const { return _zoom; } - Rectangle viewBounds() const { return _viewBoundsScreen; } - Rectangle canvasBounds() const { return _canvasBoundsModel; } + Rectangle viewBoundsScreen() const { return _viewBoundsScreen; } + Rectangle canvasBoundsModel() const { return _canvasBoundsModel; } - Point modelToPixel(in Point model) const { return _viewBoundsScreen.centre + _zoom * (model - _viewCentreModel); } - Point pixelToModel(in Point pixel) const { return _viewCentreModel + (pixel - _viewBoundsScreen.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)); } + Point modelToScreen(in Point model) const { return _viewBoundsScreen.centre + _zoom * (model - _viewCentreModel); } + Point screenToModel(in Point screen) const { return _viewCentreModel + (screen - _viewBoundsScreen.centre) / _zoom; } + Vector modelToScreen(in Vector model) const { return _zoom * model; } + Vector screenToModel(in Vector screen) const { return screen / _zoom; } + Rectangle modelToScreen(in Rectangle model) const { return Rectangle(modelToScreen(model.position), modelToScreen(model.size)); } + 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); } - // Screen units are pixels + // Screen units are screens // Model units are millimetres - double _zoom; // pixels-per-millimetre - Rectangle _viewBoundsScreen; // bounds of the viewport in pixels + double _zoom; // screens-per-millimetre + Rectangle _viewBoundsScreen; // bounds of the viewport in screens Point _viewCentreModel; // where in the model is the centre of our view Rectangle _canvasBoundsModel; // the bounds of the canvas in millimetres }