view doodle/dia/grid_layer.d @ 48:1b4c9ba58673

Stylistic overhaul.
author daveb
date Tue, 03 Aug 2010 17:37:21 +0930
parents f2e4e1d29b98
children 9960c4fbd0dd
line wrap: on
line source

module doodle.dia.grid_layer;

public {
    import doodle.dia.icanvas;
}

private {
    import doodle.cairo.routines;
    import std.math;
    import std.stdio;
}

private {
    double start(in double value, in double spacing) {
        real r = floor(value / spacing);
        return r * spacing;
    }
}

class GridLayer : Layer, Grid {
    static const double MIN_SPACING = 5.0;      // pixels

    this(in string name) {
        super(name);
        _zoomValid = false;
    }

    // Layer overrides:

    override Rectangle bounds() const {
        // We don't require any geometry
        return Rectangle();
    }

    override void draw(in Viewport viewport,
                       in Rectangle pixelDamage, scope Context pixelCr,
                       in Rectangle modelDamage, scope Context modelCr) const {
        assert(_zoomValid);

        double xx = 1.0, yy = 1.0;
        modelCr.userToDeviceDistance(xx, yy);

        modelCr.save(); {
            modelCr.setSourceRgba(0.0, 0.0, 0.0, 0.3);
            modelCr.setLineWidth(0.5);

            {
                // vertical grid lines
                double x = start(modelDamage.minCorner.x, _spacing);

                for (;;) {
                    vline(modelCr, x, modelDamage.minCorner.y, modelDamage.maxCorner.y);

                    // Ensure 1 pixel wide FIXME is this naughty? We are sneaking
                    // through cairo to mix model and pixel coordinates...
                    modelCr.save(); {
                        modelCr.scale(1.0 / xx, 1.0 / yy);
                        modelCr.stroke();
                    } modelCr.restore();

                    if (x > modelDamage.maxCorner.x) {
                        break;
                    }

                    x += _spacing;
                }
            }

            {
                // horizontal grid lines
                double y = start(modelDamage.minCorner.y, _spacing);

                for (;;) {
                    hline(modelCr, y, modelDamage.minCorner.x, modelDamage.maxCorner.x);

                    // FIXME?
                    modelCr.save(); {
                        modelCr.scale(1.0 / xx, 1.0 / yy);
                        modelCr.stroke();
                    } modelCr.restore();

                    if (y > modelDamage.maxCorner.y) {
                        break;
                    }

                    y += _spacing;
                }
            }
        } modelCr.restore();
    }

    // Grid overrides:

    override void zoomChanged(double zoom) {
        _zoom = zoom;
        _zoomValid = true;

        // FIXME compute spacing properly
        _spacing = 20.0 / _zoom;        // mm
    }

    // FIXME use inout parameter?
    override bool snap(in Point a, out Point b) const {
        b = a;
        return false;
    }

    private {
        bool _zoomValid;
        double _zoom;           // pixels per millimetre

        double _spacing;        // model spacing
    }
}