Mercurial > projects > doodle
changeset 25:8f58a8f88735
Checkpoint
author | "David Bryant <bagnose@gmail.com>" |
---|---|
date | Wed, 15 Jul 2009 23:49:02 +0930 |
parents | a24c13bb9c98 |
children | 06c30d250c0a |
files | common/undo.d import/canvas.d import/geometry.d import/undo.d tk/geometry.d undo_manager.d |
diffstat | 6 files changed, 183 insertions(+), 406 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/undo.d Wed Jul 15 23:49:02 2009 +0930 @@ -0,0 +1,15 @@ +module common.undo; + +abstract class Action { + void undo(); + void redo(); +} + +interface IUndoObserver { + void canUndo(in bool value, in string description); + void canRedo(in bool value, in string description); +} + +interface IUndoManager { + void addAction(Action action); +}
--- a/import/canvas.d Wed Jul 15 23:39:29 2009 +0930 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -module interaction.canvas; - -import presentation.geometry; - -// World coordinates - -interface Canvas { - // color, line color, line style, line width, fill color, - // stroke, fill, - // image - // text, clip, -} - -// Pixel coordinates - -interface Screen { -}
--- a/import/geometry.d Wed Jul 15 23:39:29 2009 +0930 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,220 +0,0 @@ -module interaction.geometry; - -private import std.math; - -private const double EPSILON = 1e-20; - -final class Point { - this() { - this(0.0, 0.0); - } - - this(double x, double y) { - _x = x; - _y = y; - } - - char[] toString() { - return "(" ~ std.string.toString(_x) ~ ", " ~ std.string.toString(_y) ~ ")"; - } - - Point opAdd(in Vector v) { - return new Point(_x + v._x, _y + v._y); - } - - Vector opSub(in Point p) { - return new Vector(_x - p._x, _y - p._y); - } - - double x() { return _x; } - double y() { return _y; } - - private { - double _x; - double _y; - } -} - -// - -final class Vector { - this() { - this(0.0, 0.0); - } - - this(double x, double y) { - _x = x; - _y = y; - } - - char[] toString() { - return "[" ~ std.string.toString(_x) ~ ", " ~ std.string.toString(_y) ~ "]"; - } - - Vector opAdd(in Vector v) { - return new Vector(_x + v._x, _y + v._y); - } - - Vector opSub(in Vector v) { - return new Vector(_x - v._x, _y - v._y); - } - - Vector opNeg() { - return new Vector(-_x, -_y); - } - - Vector opMul_r(double d) { - return new Vector(d * _x, d * _y); - } - - double length() { - return sqrt(_x * _x + _y * _y); - } - - bool has_length() { - return _x * _x + _y * _y > EPSILON * EPSILON; - } - - double x() { return _x; } - double y() { return _y; } - - private { - double _x; - double _y; - } -} - -// - -final class Segment { - this() { - } - - this(Point start, Point end) { - _start = start; - _end = end; - } - - Point start() { return _start; } - Point end() { return _end; } - - private { - Point _start; - Point _end; - } -} - -// - -final class Line { - this() { - } - - this(Point point, Vector vector) { - assert(vector.has_length); - _point = point; - _vector = vector; - } - - this(Point point1, Point point2) { - _point = point1; - _vector = point2 - point1; - assert(_vector.has_length); - } - - private { - Point _point; - Vector _vector; - } -} - -// - -final class Rectangle { - this() { - this(0.0, 0.0, 0.0, 0.0); - } - - this(double x, double y, double w, double h) { - assert(w >= 0.0); - assert(h >= 0.0); - _x = x; - _y = y; - _w = w; - _h = h; - } - - double x() { return _x; } - double y() { return _y; } - double w() { return _w; } - double h() { return _h; } - double xw() { return _x + _w; } - double yh() { return _y + _h; } - - /* - Point corner00() { return new Point(_x, _y ); } - Point corner10() { return new Point(_x + _w, _y ); } - Point corner11() { return new Point(_x + _w, _y + _h); } - Point corner01() { return new Point(_x, _y + _h); } - - Point centre() { return new Point(_x + _w / 2.0, _y + _h / 2.0); } - */ - - double area() { - return _w * _h; - } - - bool has_area() { - return area > 0.0; - } - - bool contains(Point point) { - return point.x > x && point.x < xw & point.y > y && point.y < xy; - } - - bool contains(Segment segment) { - return contains(segment.start, segment.end); - } - - private double _x, _y, _w, _h; -} - -unittest { - const double absdiff = 1e-20, reldiff= 1e-20; - - bool cmpdouble(in double lhs, in double rhs) { - double adiff = fabs(rhs - lhs); - - if (adiff < absdiff && adiff > -absdiff) { - return true; - } - - if (fabs(lhs) > absdiff && fabs(rhs) > absdiff) { - double rdiff = rhs / lhs; - - if (rdiff < (1.0 + reldiff) && rdiff > 1.0 / (1.0 + reldiff)) { - return true; - } - } - - // They must differ significantly - - return false; - } - - bool cmpvector(in Vector lhs, in Vector rhs) { - return cmpdouble(lhs._x, rhs._x) && cmpdouble(lhs._y, rhs._y); - } - - bool cmppoint(in Point lhs, in Point rhs) { - return cmpdouble(lhs._x, rhs._x) && cmpdouble(lhs._y, rhs._y); - } - - assert(cmpvector(new Vector(0.0, 0.0), new Vector)); - assert(!cmpvector(new Vector(0.0, 1e-10), new Vector)); - assert(cmpvector(new Vector(1.0, 2.0) + new Vector(3.0, 4.0), new Vector(4.0, 6.0))); - assert(cmpvector(new Vector(1.0, 2.0) - new Vector(3.0, 4.0), new Vector(-2.0, -2.0))); - assert(cmpvector(-(new Vector(1.0, 2.0)), new Vector(-1.0, -2.0))); - assert(cmpdouble((new Vector(3.0, 4.0)).length(), 5.0)); - assert(cmpvector(3.0 * (new Vector(3.0, 4.0)), new Vector(9.0, 12.0))); -}
--- a/import/undo.d Wed Jul 15 23:39:29 2009 +0930 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -module dog.core.undo; - -import util.list; - -abstract class Action { - void undo(); - void redo(); -} - -interface IUndoObserver { - void canUndo(bool value, char[] description); - void canRedo(bool value, char[] description); -} - -interface IUndoManager { - void addAction(Action action); -} - -class UndoManager : IUndoManager { - this() { - } - - void addObserver(IUndoObserver observer) { - _observers.add(observer); - } - - void removeObserver(IUndoObserver observer) { - _observers.remove(observer); - } - - void reset() { - assert(!inTransaction()); - _past.clear(); - _future.clear(); - foreach(IUndoObserver obs; _observers) { - obs.canUndo(false, ""); - obs.canRedo(false, ""); - } - } - - void undo() { - assert(canUndo()); - Transaction t = _past.pop(); - t.undo(); - _future.push(t); - } - - void redo() { - assert(canRedo()); - Transaction t = _future.pop(); - t.redo(); - _past.push(t); - } - - bool canUndo() { - assert(!inTransaction()); - return !_past.empty(); - } - - bool canRedo() { - assert(!inTransaction()) { - return !_future.empty(); - } - } - - void beginTransaction(char[] description) { - assert(!inTransaction()); - _current_transaction = new Transaction(description); - } - - void cancelTransaction() { - assert(inTransaction()); - _current_transaction.cancel(); - _current_transaction = null; - } - - void endTransaction() { - assert(inTransaction()); - _current_transaction.finalise(); - - if (!_future.empty()) { - _future.clear(); - foreach(IUndoObserver obs; _observers) { - obs.canRedo(false, ""); - } - } - - _past.push(_current_transaction); - - foreach(IUndoObserver obs; _observers) { - bs.canUndo(true, _current_transaction.name()); - } - - _current_transaction = null; - } - - // IUndoManager implementations: - - void addAction(Action action) { - assert(inTransaction()); - _current_transaction.add(action); - } - - private { - bool inTransaction() { - return _current_transaction !is null; - } - - class Transaction { - enum State { - Accumulating, - Finalised, - Canceled - } - - this(char[] description) { - _description = description; - _state = Accumulating; - } - - char[] description() { - return _description; - } - - void add(Action action) { - assert(_state == State.Accumulating); - _actions.addTail(action); - } - - void finalise() { - assert(_state == State.Accumulating); - assert(!_actions.empty()); - _finalised = true; - } - - void cancel() { - assert(_state == State.Accumulating); - foreachreverse(UndoAction ua; _actions) { - ua.undo(); - } - } - - void redo() { - assert(_finalised); - foreach (UndoAction ua; _actions) { - ua.redo(); - } - } - - void undo() { - assert(_finalised); - foreachreverse(UndoAction ua; _actions) { - ua.undo(); - } - } - - private { - char[] _description; - List<Action> _actions; - State _state; - } - } - - Transaction _current_transaction; - Stack!(Transaction) _past; - Stack!(Transaction) _future; - Set!(IUndoObserver) _observers; - } -}
--- a/tk/geometry.d Wed Jul 15 23:39:29 2009 +0930 +++ b/tk/geometry.d Wed Jul 15 23:49:02 2009 +0930 @@ -233,3 +233,18 @@ Vector _size; } } + +/* +struct Segment { + private { + Point _begin, _end; + } +} + +struct Line { + private { + Point _point; + Vector _gradien; + } +} +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/undo_manager.d Wed Jul 15 23:49:02 2009 +0930 @@ -0,0 +1,153 @@ +module undo_manager; + +class UndoManager : IUndoManager { + this() { + } + + void addObserver(IUndoObserver observer) { + _observers.add(observer); + } + + void removeObserver(IUndoObserver observer) { + _observers.remove(observer); + } + + void reset() { + assert(!inTransaction()); + _past.clear(); + _future.clear(); + foreach(IUndoObserver obs; _observers) { + obs.canUndo(false, ""); + obs.canRedo(false, ""); + } + } + + void undo() { + assert(canUndo()); + Transaction t = _past.pop(); + t.undo(); + _future.push(t); + } + + void redo() { + assert(canRedo()); + Transaction t = _future.pop(); + t.redo(); + _past.push(t); + } + + bool canUndo() { + assert(!inTransaction()); + return !_past.empty(); + } + + bool canRedo() { + assert(!inTransaction()) { + return !_future.empty(); + } + } + + void beginTransaction(char[] description) { + assert(!inTransaction()); + _current_transaction = new Transaction(description); + } + + void cancelTransaction() { + assert(inTransaction()); + _current_transaction.cancel(); + _current_transaction = null; + } + + void endTransaction() { + assert(inTransaction()); + _current_transaction.finalise(); + + if (!_future.empty()) { + _future.clear(); + foreach(IUndoObserver obs; _observers) { + obs.canRedo(false, ""); + } + } + + _past.push(_current_transaction); + + foreach(IUndoObserver obs; _observers) { + bs.canUndo(true, _current_transaction.name()); + } + + _current_transaction = null; + } + + // IUndoManager implementations: + + void addAction(Action action) { + assert(inTransaction()); + _current_transaction.add(action); + } + + private { + bool inTransaction() { + return _current_transaction !is null; + } + + class Transaction { + enum State { + Accumulating, + Finalised, + Canceled + } + + this(char[] description) { + _description = description; + _state = Accumulating; + } + + char[] description() { + return _description; + } + + void add(Action action) { + assert(_state == State.Accumulating); + _actions.addTail(action); + } + + void finalise() { + assert(_state == State.Accumulating); + assert(!_actions.empty()); + _finalised = true; + } + + void cancel() { + assert(_state == State.Accumulating); + foreachreverse(UndoAction ua; _actions) { + ua.undo(); + } + } + + void redo() { + assert(_finalised); + foreach (UndoAction ua; _actions) { + ua.redo(); + } + } + + void undo() { + assert(_finalised); + foreachreverse(UndoAction ua; _actions) { + ua.undo(); + } + } + + private { + char[] _description; + List<Action> _actions; + State _state; + } + } + + Transaction _current_transaction; + Stack!(Transaction) _past; + Stack!(Transaction) _future; + Set!(IUndoObserver) _observers; + } +}