File source/canvas.d added (mode: 100644) (index 0000000..55df17d) |
|
1 |
|
module dp.canvas; |
|
2 |
|
|
|
3 |
|
import gtk.Widget, gtk.DrawingArea; |
|
4 |
|
import gdk.Event; |
|
5 |
|
import cairo.Context; |
|
6 |
|
import cairo.ImageSurface; |
|
7 |
|
|
|
8 |
|
import dp.shape.shape, dp.shape.rect; |
|
9 |
|
import dp.command.create; |
|
10 |
|
|
|
11 |
|
import std.stdio; // For debug |
|
12 |
|
|
|
13 |
|
import Global = dp.global; |
|
14 |
|
|
|
15 |
|
public class Canvas : DrawingArea { |
|
16 |
|
ImageSurface surface; |
|
17 |
|
int mouseX; |
|
18 |
|
int mouseY; |
|
19 |
|
Context c; |
|
20 |
|
|
|
21 |
|
this (int width, int height) { |
|
22 |
|
super(width, height); |
|
23 |
|
this.addOnButtonPress(&clickCallback); |
|
24 |
|
surface = ImageSurface.create(CairoFormat.ARGB32, width, height); |
|
25 |
|
c = Context.create(surface); |
|
26 |
|
c.setSourceRgba(1,1,1,1); |
|
27 |
|
this.addOnDraw(&drawCallback); |
|
28 |
|
c.paint(); // gewoon 'repaint' gebruiken? |
|
29 |
|
} |
|
30 |
|
|
|
31 |
|
public void repaint() { |
|
32 |
|
c.paint(); // Begin met een kale, witte, achtergrond. |
|
33 |
|
Global.History.render(); |
|
34 |
|
|
|
35 |
|
// Laat alle wijzigingingen zien door 'drawCallback' indirect aan te roepen. |
|
36 |
|
queueDraw(); |
|
37 |
|
} |
|
38 |
|
|
|
39 |
|
private bool clickCallback(Event event, Widget widget) { |
|
40 |
|
// Get mouse position relative to widget.. |
|
41 |
|
getPointer(mouseX, mouseY); |
|
42 |
|
|
|
43 |
|
if(event.button.button == 3) { // if right click... |
|
44 |
|
|
|
45 |
|
} |
|
46 |
|
else { |
|
47 |
|
final switch (Global.Brush.shape) { |
|
48 |
|
case "rectangle": |
|
49 |
|
Global.History.addCommand(new CreateCmd(new Rectangle(mouseX, mouseY, Context.create(surface)))); |
|
50 |
|
break; |
|
51 |
|
case null: |
|
52 |
|
break; |
|
53 |
|
} |
|
54 |
|
repaint(); |
|
55 |
|
Global.Brush.shape = null; |
|
56 |
|
} |
|
57 |
|
|
|
58 |
|
return true; |
|
59 |
|
} |
|
60 |
|
|
|
61 |
|
// Wat te doen met iedere individuele Context die opnieuw getekend wordt? |
|
62 |
|
public bool drawCallback(Scoped!Context context, Widget widget) { |
|
63 |
|
context.setSourceSurface(surface, 0, 0); |
|
64 |
|
context.paint(); |
|
65 |
|
|
|
66 |
|
return true; |
|
67 |
|
} |
|
68 |
|
} |
File source/commands/shapeCommands.d deleted (index 1ca5444..0000000) |
1 |
|
module dp.command.shape; |
|
2 |
|
|
|
3 |
|
import dp.command.cmd; |
|
4 |
|
import Global = dp.globals; |
|
5 |
|
import File = dp.file; |
|
6 |
|
|
|
7 |
|
import dp.shape; |
|
8 |
|
|
|
9 |
|
import std.stdio; // For debug. |
|
10 |
|
|
|
11 |
|
public class CreateCmd : Command { |
|
12 |
|
public Shape s; |
|
13 |
|
|
|
14 |
|
this() { |
|
15 |
|
s = new Shape(); |
|
16 |
|
Global.canvas.addShape(s); |
|
17 |
|
File.Append(s.toString()); |
|
18 |
|
} |
|
19 |
|
|
|
20 |
|
public override void execute() { |
|
21 |
|
s.enabled = s.visible = true; |
|
22 |
|
Global.canvas.repaint(); |
|
23 |
|
} |
|
24 |
|
|
|
25 |
|
public override void undo() { |
|
26 |
|
s.enabled = s.visible = false; |
|
27 |
|
Global.canvas.repaint(); |
|
28 |
|
} |
|
29 |
|
} |
|
30 |
|
|
|
31 |
|
public class MoveCmd : Command { |
|
32 |
|
Shape original; |
|
33 |
|
Shape newShape; |
|
34 |
|
|
|
35 |
|
this(Shape original) { |
|
36 |
|
this.original = original; |
|
37 |
|
newShape = original.clone(); |
|
38 |
|
Global.canvas.addShape(newShape); |
|
39 |
|
execute(); |
|
40 |
|
} |
|
41 |
|
|
|
42 |
|
public override void execute() { |
|
43 |
|
original.visible = original.enabled = false; |
|
44 |
|
newShape.visible = newShape.enabled = true; |
|
45 |
|
} |
|
46 |
|
|
|
47 |
|
public override void undo() { |
|
48 |
|
original.visible = original.enabled = true; |
|
49 |
|
newShape.visible = newShape.enabled = false; |
|
50 |
|
} |
|
51 |
|
} |
|
52 |
|
|
|
53 |
|
public class ResizeCmd : Command { |
|
54 |
|
Shape original; |
|
55 |
|
Shape newShape; |
|
56 |
|
|
|
57 |
|
this(Shape original, float newSize) { |
|
58 |
|
this.original = original; |
|
59 |
|
newShape = original.clone(); |
|
60 |
|
Global.canvas.addShape(newShape); |
|
61 |
|
newShape.resize(newSize); |
|
62 |
|
execute(); |
|
63 |
|
} |
|
64 |
|
|
|
65 |
|
public override void execute() { |
|
66 |
|
original.visible = original.enabled = false; |
|
67 |
|
newShape.visible = newShape.enabled = true; |
|
68 |
|
} |
|
69 |
|
|
|
70 |
|
public override void undo() { |
|
71 |
|
original.visible = original.enabled = true; |
|
72 |
|
newShape.visible = newShape.enabled = false; |
|
73 |
|
} |
|
74 |
|
} |
|
File source/drawing/shapeOptions.d deleted (index e59df47..0000000) |
1 |
|
module dp.shapeOptions; |
|
2 |
|
|
|
3 |
|
import gtk.Menu, gtk.MenuItem; |
|
4 |
|
import gtk.Widget; |
|
5 |
|
import gdk.Event; |
|
6 |
|
|
|
7 |
|
import dp.shape; |
|
8 |
|
import dp.win.resize; |
|
9 |
|
import Global = dp.globals; |
|
10 |
|
|
|
11 |
|
import std.stdio; // For debugging. |
|
12 |
|
|
|
13 |
|
protected Shape s; |
|
14 |
|
protected ResizeDialog rd; |
|
15 |
|
|
|
16 |
|
public class ShapeOptions : Menu { |
|
17 |
|
this() { |
|
18 |
|
super(); |
|
19 |
|
this.append(new DeleteShape()); |
|
20 |
|
this.append(new MoveShape()); |
|
21 |
|
this.append(new ResizeShape()); |
|
22 |
|
} |
|
23 |
|
|
|
24 |
|
// Will look like: sOptions.OfShape(s); Should be differently named. |
|
25 |
|
public void OfShape (Shape shape) { // Shows options of param shape. |
|
26 |
|
s = shape; |
|
27 |
|
this.showAll(); |
|
28 |
|
this.popup(0, 0); |
|
29 |
|
} |
|
30 |
|
} |
|
31 |
|
|
|
32 |
|
protected class DeleteShape : MenuItem { |
|
33 |
|
this() { |
|
34 |
|
super("Delete"); |
|
35 |
|
addOnButtonRelease(&relCallback); |
|
36 |
|
} |
|
37 |
|
|
|
38 |
|
private bool relCallback (Event event, Widget widget) { |
|
39 |
|
s.remove(); |
|
40 |
|
Global.canvas.repaint(); |
|
41 |
|
writeln("Deleted shape."); |
|
42 |
|
return false; // Hide ShapeOptions when button is released. |
|
43 |
|
} |
|
44 |
|
} |
|
45 |
|
|
|
46 |
|
protected class MoveShape : MenuItem { |
|
47 |
|
this() { |
|
48 |
|
super("Move shape"); |
|
49 |
|
addOnButtonRelease(&relCallback); |
|
50 |
|
} |
|
51 |
|
|
|
52 |
|
private bool relCallback (Event event, Widget widget) { |
|
53 |
|
writeln("Moved shape"); |
|
54 |
|
s.select(); |
|
55 |
|
s.enabled = false; |
|
56 |
|
Global.canvas.repaint(); |
|
57 |
|
// Create ghost shape. |
|
58 |
|
return false; // Hide ShapeOptions when button is released. |
|
59 |
|
} |
|
60 |
|
} |
|
61 |
|
|
|
62 |
|
protected class ResizeShape : MenuItem { |
|
63 |
|
this() { |
|
64 |
|
super("Resize shape"); |
|
65 |
|
addOnButtonRelease(&relCallback); |
|
66 |
|
} |
|
67 |
|
|
|
68 |
|
private bool relCallback (Event event, Widget widget) { |
|
69 |
|
rd = new ResizeDialog(s); |
|
70 |
|
return false; // Hide ShapeOptions when button is released. |
|
71 |
|
} |
|
72 |
|
} |
|
File source/entities/canvas.d deleted (index f4b246d..0000000) |
1 |
|
module dp.canvas; |
|
2 |
|
|
|
3 |
|
import gtk.Widget, gtk.DrawingArea; |
|
4 |
|
import gdk.Event; |
|
5 |
|
import cairo.Context; |
|
6 |
|
import cairo.ImageSurface; |
|
7 |
|
|
|
8 |
|
import std.stdio; // For debug |
|
9 |
|
|
|
10 |
|
import dp.entity; |
|
11 |
|
|
|
12 |
|
import dp.shape; |
|
13 |
|
import dp.shapeOptions; |
|
14 |
|
|
|
15 |
|
import dp.history; |
|
16 |
|
import dp.command.shape; |
|
17 |
|
|
|
18 |
|
/+ |
|
19 |
|
Reference: |
|
20 |
|
https://github.com/gtkd-developers/GtkD/blob/42ef854f7cd975519926900fe326e220410c028a/demos/gtkD/TestWindow/TestDrawingArea.d |
|
21 |
|
+/ |
|
22 |
|
|
|
23 |
|
public class Canvas : Entity { |
|
24 |
|
|
|
25 |
|
DrawingArea area; |
|
26 |
|
ImageSurface surface; |
|
27 |
|
int mouseX; |
|
28 |
|
int mouseY; |
|
29 |
|
Shape[] shapes; |
|
30 |
|
ShapeOptions shapeOptions; |
|
31 |
|
|
|
32 |
|
this (int width, int height) { |
|
33 |
|
super(); |
|
34 |
|
area = new DrawingArea(width, height); |
|
35 |
|
shapeOptions = new ShapeOptions(); |
|
36 |
|
area.addOnButtonPress(&clickCallback); |
|
37 |
|
surface = ImageSurface.create(CairoFormat.ARGB32, width, height); |
|
38 |
|
area.addOnDraw(&drawCallback); |
|
39 |
|
shapes.length = 0; |
|
40 |
|
clearCanvas(); |
|
41 |
|
} |
|
42 |
|
|
|
43 |
|
@property |
|
44 |
|
public override size_t childrenAmount() { |
|
45 |
|
return shapes.length; |
|
46 |
|
} |
|
47 |
|
|
|
48 |
|
public override Entity[] getChildren() { |
|
49 |
|
return cast(Entity[]) shapes; |
|
50 |
|
} |
|
51 |
|
|
|
52 |
|
public ref Shape getShape(ulong n) { |
|
53 |
|
return shapes[n]; |
|
54 |
|
} |
|
55 |
|
|
|
56 |
|
public void addChild(ulong n) { |
|
57 |
|
getChild(n).enabled = true; |
|
58 |
|
} |
|
59 |
|
|
|
60 |
|
public void removeChild(ulong n) { |
|
61 |
|
getChild(n).enabled = false; |
|
62 |
|
} |
|
63 |
|
|
|
64 |
|
private bool clickCallback(Event event, Widget widget) { |
|
65 |
|
// Get mouse position relative to widget.. |
|
66 |
|
area.getPointer(mouseX, mouseY); |
|
67 |
|
|
|
68 |
|
if(Global.Brush.Shape is null) { // Brush imported from dp.shape. |
|
69 |
|
for(int i = cast(int)shapes.length - 1; i >= 0; i -= 1) { |
|
70 |
|
/+ |
|
71 |
|
Look FIFO wether you clicked on a Shape. |
|
72 |
|
FIFO is required to make sure the Shape |
|
73 |
|
most at front is selected first. |
|
74 |
|
|
|
75 |
|
if boolean expression below is true, the |
|
76 |
|
shape destroys itself and this function |
|
77 |
|
stops looking for more shapes that |
|
78 |
|
could have been clicked. |
|
79 |
|
+/ |
|
80 |
|
if(shapes[i].CheckBounds(mouseX,mouseY)) { |
|
81 |
|
if(event.button.button == 3) { // if right click... |
|
82 |
|
shapeOptions.OfShape(shapes[i]); |
|
83 |
|
} |
|
84 |
|
break; |
|
85 |
|
} |
|
86 |
|
} |
|
87 |
|
} else { |
|
88 |
|
History.addCommand(new CreateCmd()); // Add the creation of the shape to the undo-redo history. |
|
89 |
|
} |
|
90 |
|
return true; |
|
91 |
|
} |
|
92 |
|
|
|
93 |
|
private bool drawCallback(Scoped!Context context, Widget widget) { |
|
94 |
|
context.setSourceSurface(surface, 0, 0); |
|
95 |
|
context.paint(); |
|
96 |
|
writeln(treeToString(0));//Debug |
|
97 |
|
return true; |
|
98 |
|
} |
|
99 |
|
|
|
100 |
|
private void clearCanvas() { |
|
101 |
|
Context c = Context.create(surface); |
|
102 |
|
c.setSourceRgba(1,1,1,1); |
|
103 |
|
c.paint(); |
|
104 |
|
} |
|
105 |
|
|
|
106 |
|
public void repaint() { |
|
107 |
|
clearCanvas(); |
|
108 |
|
for(int i = 0; i < shapes.length; i++) |
|
109 |
|
shapes[i].applyToSource(); |
|
110 |
|
area.queueDraw(); |
|
111 |
|
} |
|
112 |
|
|
|
113 |
|
public void addShape(ref Shape shape) { |
|
114 |
|
size_t i = shapes.length; |
|
115 |
|
|
|
116 |
|
shape.move(mouseX, mouseY, Context.create(surface)); |
|
117 |
|
|
|
118 |
|
shapes.length++; |
|
119 |
|
shapes[i] = shape; |
|
120 |
|
|
|
121 |
|
area.queueDraw(); |
|
122 |
|
} |
|
123 |
|
} |
|
File source/entities/shape.d deleted (index cde8389..0000000) |
1 |
|
module dp.shape; |
|
2 |
|
|
|
3 |
|
public import Global = dp.globals; |
|
4 |
|
|
|
5 |
|
import cairo.Context; |
|
6 |
|
import cairo.ImageSurface; |
|
7 |
|
|
|
8 |
|
import std.stdio; // For debug |
|
9 |
|
import std.conv; |
|
10 |
|
|
|
11 |
|
import dp.history; |
|
12 |
|
import dp.command.shape; |
|
13 |
|
|
|
14 |
|
class Shape : Global.Entity { |
|
15 |
|
/+ |
|
16 |
|
bounds[0][0] = minX |
|
17 |
|
bounds[1][0] = maxX |
|
18 |
|
bounds[0][1] = minY |
|
19 |
|
bounds[1][1] = maxY |
|
20 |
|
+/ |
|
21 |
|
|
|
22 |
|
private Context c; |
|
23 |
|
public bool visible; // Should be encapsulated. |
|
24 |
|
private string shapeType; |
|
25 |
|
private double[2][2] bounds; |
|
26 |
|
private double size = 0; |
|
27 |
|
|
|
28 |
|
this() { |
|
29 |
|
enabled = visible = true; |
|
30 |
|
} |
|
31 |
|
|
|
32 |
|
this(double[2][2] bounds, double size, string shapeType) { |
|
33 |
|
enabled = visible = true; |
|
34 |
|
this.bounds = bounds; |
|
35 |
|
this.size = size; |
|
36 |
|
this.shapeType = shapeType; |
|
37 |
|
|
|
38 |
|
writeln(this.bounds);writeln(this.size);writeln(this.type); |
|
39 |
|
} |
|
40 |
|
|
|
41 |
|
public void resize(float factor) { |
|
42 |
|
bounds[1][1] += factor / 2; |
|
43 |
|
bounds[1][0] += factor / 2; |
|
44 |
|
bounds[0][1] -= factor / 2; |
|
45 |
|
bounds[0][0] -= factor / 2; |
|
46 |
|
|
|
47 |
|
size += factor; |
|
48 |
|
draw(); |
|
49 |
|
} |
|
50 |
|
|
|
51 |
|
@property |
|
52 |
|
public override string type() { |
|
53 |
|
return shapeType; |
|
54 |
|
} |
|
55 |
|
|
|
56 |
|
public override string toString() { |
|
57 |
|
return text(type, " ", bounds[0][0], " ", bounds[0][1], " ", size, " ", size); |
|
58 |
|
} |
|
59 |
|
|
|
60 |
|
public Shape clone() { |
|
61 |
|
return new Shape(bounds, size, type); |
|
62 |
|
} |
|
63 |
|
|
|
64 |
|
public void move(int x, int y, Context context=null) { |
|
65 |
|
if(context !is null) |
|
66 |
|
c = context; |
|
67 |
|
|
|
68 |
|
draw(x,y); |
|
69 |
|
} |
|
70 |
|
|
|
71 |
|
public void select() { |
|
72 |
|
c.setSourceRgba(1-Global.Brush.Red, 1-Global.Brush.Green, 1-Global.Brush.Blue, 1); |
|
73 |
|
c.stroke(); |
|
74 |
|
c.setSourceRgba(Global.Brush.Red, Global.Brush.Green, Global.Brush.Blue, Global.Brush.Alpha); |
|
75 |
|
} |
|
76 |
|
|
|
77 |
|
public void remove() { |
|
78 |
|
visible = enabled = false; |
|
79 |
|
} |
|
80 |
|
|
|
81 |
|
private void initSize() { |
|
82 |
|
shapeType = Global.Brush.Shape; |
|
83 |
|
Global.Brush.Shape = null; |
|
84 |
|
|
|
85 |
|
final switch (type) { |
|
86 |
|
case "rectangle": |
|
87 |
|
size = 125; |
|
88 |
|
break; |
|
89 |
|
case "ellipse": |
|
90 |
|
case "circle": |
|
91 |
|
size = 50; |
|
92 |
|
break; |
|
93 |
|
} |
|
94 |
|
} |
|
95 |
|
|
|
96 |
|
private void draw(int x, int y) { |
|
97 |
|
if(size == 0) initSize(); |
|
98 |
|
|
|
99 |
|
final switch (type) { |
|
100 |
|
case "rectangle": |
|
101 |
|
bounds[0][0] = x - size / 2; // minX |
|
102 |
|
bounds[1][0] = x + size / 2; // maxX |
|
103 |
|
bounds[0][1] = y - size / 2; // minY |
|
104 |
|
bounds[1][1] = y + size / 2; // maxY |
|
105 |
|
break; |
|
106 |
|
case "ellipse": |
|
107 |
|
bounds[0][0] = x - size / 2; // minX |
|
108 |
|
bounds[1][0] = x + size / 2; // maxX |
|
109 |
|
bounds[0][1] = y - size; // minY |
|
110 |
|
bounds[1][1] = y + size; // maxY |
|
111 |
|
break; |
|
112 |
|
case "circle": |
|
113 |
|
bounds[0][0] = x - size; // minX |
|
114 |
|
bounds[1][0] = x + size; // maxX |
|
115 |
|
bounds[0][1] = y - size; // minY |
|
116 |
|
bounds[1][1] = y + size; // maxY |
|
117 |
|
break; |
|
118 |
|
} |
|
119 |
|
draw(); |
|
120 |
|
} |
|
121 |
|
|
|
122 |
|
private void draw() { |
|
123 |
|
if(visible) { |
|
124 |
|
final switch (type) { |
|
125 |
|
case "rectangle": |
|
126 |
|
c.setSourceRgba(Global.Brush.Red, Global.Brush.Green, Global.Brush.Blue, Global.Brush.Alpha); |
|
127 |
|
c.rectangle(bounds[0][0], bounds[0][1], size, size); |
|
128 |
|
applyToSource(); |
|
129 |
|
break; |
|
130 |
|
case "ellipse": |
|
131 |
|
c.setSourceRgba(Global.Brush.Red, Global.Brush.Green, Global.Brush.Blue, Global.Brush.Alpha); |
|
132 |
|
c.scale(0.5, 1); |
|
133 |
|
c.arc((bounds[0][0]+size/2)*2 ,bounds[0][1]+size ,size,0,2*3.141); // 3.141 = Pi |
|
134 |
|
applyToSource(); |
|
135 |
|
break; |
|
136 |
|
case "circle": |
|
137 |
|
c.setSourceRgba(Global.Brush.Red, Global.Brush.Green, Global.Brush.Blue, Global.Brush.Alpha); |
|
138 |
|
c.arc(bounds[0][0]+size, bounds[0][1]+size, size,0,2*3.141); // 3.141 = Pi |
|
139 |
|
applyToSource(); |
|
140 |
|
break; |
|
141 |
|
} |
|
142 |
|
} |
|
143 |
|
} |
|
144 |
|
|
|
145 |
|
public bool CheckBounds(int x, int y) { |
|
146 |
|
if(enabled) { |
|
147 |
|
writeln(shapeType ~ ":"); |
|
148 |
|
write(bounds[0][0]);write(" <- ");write(x);write(" -> ");writeln(bounds[1][0]); |
|
149 |
|
write(bounds[0][1]);write(" <- ");write(y);write(" -> ");writeln(bounds[1][1]); |
|
150 |
|
|
|
151 |
|
if( |
|
152 |
|
x > bounds[0][0] && // minX |
|
153 |
|
x < bounds[1][0] && // maxX |
|
154 |
|
y > bounds[0][1] && // minY |
|
155 |
|
y < bounds[1][1] // maxY |
|
156 |
|
) { |
|
157 |
|
writeln("Clicked me!"); |
|
158 |
|
return true; |
|
159 |
|
} |
|
160 |
|
} |
|
161 |
|
else if(visible) |
|
162 |
|
History.addCommand(new MoveCmd(this)); |
|
163 |
|
|
|
164 |
|
return false; |
|
165 |
|
} |
|
166 |
|
|
|
167 |
|
public void applyToSource() { |
|
168 |
|
if(visible) |
|
169 |
|
c.fillPreserve(); |
|
170 |
|
} |
|
171 |
|
} |
|
File source/file.d deleted (index 69461ee..0000000) |
1 |
|
module dp.file; |
|
2 |
|
|
|
3 |
|
import std.stdio; |
|
4 |
|
import std.file; |
|
5 |
|
|
|
6 |
|
protected string[] content; |
|
7 |
|
protected size_t contentPtr = 0; |
|
8 |
|
protected string filename = ""; |
|
9 |
|
protected string[] tmpContent; |
|
10 |
|
|
|
11 |
|
public void New() { |
|
12 |
|
content.length = contentPtr = 0; |
|
13 |
|
} |
|
14 |
|
|
|
15 |
|
public void Open(string name) { |
|
16 |
|
filename = name; |
|
17 |
|
Append(readText(filename)); |
|
18 |
|
} |
|
19 |
|
|
|
20 |
|
public void Append(string text) { |
|
21 |
|
content.length++; |
|
22 |
|
content[contentPtr++] = text; |
|
23 |
|
} |
|
24 |
|
|
|
25 |
|
public void RemoveLastRecord() { |
|
26 |
|
content.length--; |
|
27 |
|
} |
|
28 |
|
|
|
29 |
|
public void Undo() { |
|
30 |
|
if(contentPtr > 0) { |
|
31 |
|
if(contentPtr > tmpContent.length) |
|
32 |
|
tmpContent.length = contentPtr--; |
|
33 |
|
|
|
34 |
|
write("contentPtr = ");writeln(contentPtr); // Debug |
|
35 |
|
tmpContent[contentPtr] = content[contentPtr]; |
|
36 |
|
content[contentPtr--] = ""; |
|
37 |
|
} |
|
38 |
|
else if(contentPtr > content.length) |
|
39 |
|
contentPtr = 0; |
|
40 |
|
/+ |
|
41 |
|
contentPtr is unsigned. Mocht het toch voorkomen for some |
|
42 |
|
reason de ptr onder nul komt, undo() dat herstelt. |
|
43 |
|
+/ |
|
44 |
|
} |
|
45 |
|
|
|
46 |
|
public void Redo() { |
|
47 |
|
if(content.length > contentPtr + 1) { |
|
48 |
|
contentPtr++; // Don't increment in if statement; the pointer would otherwise also be incremented is the expression = false. |
|
49 |
|
write("contentPtr = ");writeln(contentPtr); // Debug |
|
50 |
|
content[contentPtr] = tmpContent[contentPtr]; |
|
51 |
|
tmpContent[contentPtr] = ""; |
|
52 |
|
} |
|
53 |
|
} |
|
54 |
|
|
|
55 |
|
public void Save() { |
|
56 |
|
Save(filename); |
|
57 |
|
} |
|
58 |
|
|
|
59 |
|
public void Save(string name) { |
|
60 |
|
string file = ""; |
|
61 |
|
|
|
62 |
|
write("contentPtr = ");writeln(contentPtr); // Debug |
|
63 |
|
for(ulong i = 0; i < content.length-1; i++) |
|
64 |
|
file ~= content[i] ~ "\n"; |
|
65 |
|
|
|
66 |
|
writeln("ping"); // Debug |
|
67 |
|
file ~= content[content.length-1]; |
|
68 |
|
file.length--; |
|
69 |
|
File f = File(name, "w"); |
|
70 |
|
f.writeln(file); |
|
71 |
|
f.close(); |
|
72 |
|
|
|
73 |
|
content.length = contentPtr = tmpContent.length = 0; |
|
74 |
|
} |
|
File source/history.d changed (mode: 100644) (index 9555e0a..ab42483) |
... |
... |
module dp.history; |
2 |
2 |
|
|
3 |
3 |
import dp.command.cmd; |
import dp.command.cmd; |
4 |
4 |
|
|
5 |
|
import File = dp.file; |
|
|
5 |
|
import Global = dp.global; // Geen dependency-cycle? |
|
6 |
|
|
|
7 |
|
import std.stdio; // Debug |
6 |
8 |
|
|
7 |
9 |
// The Invoker in the command pattern. |
// The Invoker in the command pattern. |
8 |
10 |
static class History { |
static class History { |
9 |
11 |
private static Command[] commands; |
private static Command[] commands; |
10 |
|
private static int cmdPtr = 0; |
|
|
12 |
|
private static size_t cmdPtr = 0; |
|
13 |
|
private static bool belowZero; |
11 |
14 |
|
|
12 |
15 |
public static void addCommand(Command cmd) { |
public static void addCommand(Command cmd) { |
|
16 |
|
belowZero = false; |
13 |
17 |
commands.length++; |
commands.length++; |
|
18 |
|
writeln(commands.length); |
14 |
19 |
commands[cmdPtr] = cmd; |
commands[cmdPtr] = cmd; |
15 |
|
cmdPtr++; |
|
|
20 |
|
cmdPtr = commands.length; |
|
21 |
|
writeln(cmdPtr); |
16 |
22 |
} |
} |
17 |
23 |
|
|
18 |
24 |
public static void undo() { |
public static void undo() { |
19 |
|
if(cmdPtr > 0) { |
|
|
25 |
|
if(belowZero) |
|
26 |
|
return; |
|
27 |
|
else if(cmdPtr == 0) |
|
28 |
|
belowZero = true; |
|
29 |
|
else { |
20 |
30 |
commands[--cmdPtr].undo(); |
commands[--cmdPtr].undo(); |
21 |
|
File.Undo(); |
|
|
31 |
|
write("undo ");write(cmdPtr);writeln(commands.length); |
|
32 |
|
Global.canvas.repaint(); |
22 |
33 |
} |
} |
23 |
34 |
} |
} |
24 |
35 |
|
|
25 |
36 |
public static void redo() { |
public static void redo() { |
26 |
|
if(commands.length > cmdPtr) { |
|
|
37 |
|
if(cmdPtr < commands.length) { |
27 |
38 |
commands[cmdPtr++].execute(); |
commands[cmdPtr++].execute(); |
28 |
|
File.Redo(); |
|
|
39 |
|
Global.canvas.repaint(); |
|
40 |
|
belowZero = false; |
|
41 |
|
write("redo ");write(cmdPtr);writeln(commands.length); |
29 |
42 |
} |
} |
30 |
43 |
} |
} |
|
44 |
|
|
|
45 |
|
public static void render() { |
|
46 |
|
foreach(command; commands) |
|
47 |
|
command.render(); |
|
48 |
|
} |
|
49 |
|
|
|
50 |
|
public static void CheckBounds(int x, int y) { |
|
51 |
|
foreach(command; commands) |
|
52 |
|
command.check(x,y); |
|
53 |
|
} |
31 |
54 |
} |
} |
File source/menubar.d changed (mode: 100644) (index 6a01cb0..3d4fc9b) |
... |
... |
import gtk.MenuBar, gtk.Menu, gtk.MenuItem; |
5 |
5 |
import gtk.Widget; |
import gtk.Widget; |
6 |
6 |
import gdk.Event; |
import gdk.Event; |
7 |
7 |
|
|
8 |
|
import Global = dp.globals; |
|
9 |
|
import File = dp.file; |
|
10 |
|
import Brush = dp.brush; |
|
|
8 |
|
import dp.shape.rect; |
11 |
9 |
|
|
12 |
|
import dp.group; |
|
|
10 |
|
import Global = dp.global; |
13 |
11 |
|
|
14 |
12 |
public class Menubar : Box { |
public class Menubar : Box { |
15 |
13 |
this() { |
this() { |
|
... |
... |
public class Menubar : Box { |
17 |
15 |
|
|
18 |
16 |
MenuBar menubar = new MenuBar(); |
MenuBar menubar = new MenuBar(); |
19 |
17 |
|
|
20 |
|
menubar.append(new FileMenu()); |
|
|
18 |
|
//menubar.append(new FileMenu()); |
21 |
19 |
menubar.append(new EditMenu()); |
menubar.append(new EditMenu()); |
22 |
20 |
menubar.append(new ShapeMenu()); |
menubar.append(new ShapeMenu()); |
23 |
|
//menubar.append(new GroupMenu()); |
|
24 |
21 |
|
|
25 |
22 |
this.packStart(menubar, false, false, 0); |
this.packStart(menubar, false, false, 0); |
26 |
23 |
} |
} |
27 |
24 |
} |
} |
28 |
25 |
|
|
29 |
|
protected class FileMenu : MenuItem { |
|
30 |
|
Menu fileMenu; |
|
31 |
|
|
|
32 |
|
MenuItem newFile; |
|
33 |
|
MenuItem saveFile; |
|
34 |
|
MenuItem saveAsFile; |
|
35 |
|
MenuItem openFile; |
|
36 |
|
|
|
37 |
|
this () { |
|
38 |
|
super("File"); |
|
39 |
|
fileMenu = new Menu(); |
|
40 |
|
|
|
41 |
|
newFile = new MenuItem("New"); |
|
42 |
|
newFile.addOnButtonPress(&newFCallback); |
|
43 |
|
fileMenu.append(newFile); |
|
44 |
|
|
|
45 |
|
saveFile = new MenuItem("Save"); |
|
46 |
|
saveFile.addOnButtonPress(&saveFCallback); |
|
47 |
|
fileMenu.append(saveFile); |
|
48 |
|
|
|
49 |
|
saveAsFile = new MenuItem("Save as"); |
|
50 |
|
saveAsFile.addOnButtonPress(&saveAsFCallback); |
|
51 |
|
fileMenu.append(saveAsFile); |
|
52 |
|
|
|
53 |
|
openFile = new MenuItem("Open"); |
|
54 |
|
openFile.addOnButtonPress(&openFCallback); |
|
55 |
|
fileMenu.append(openFile); |
|
56 |
|
|
|
57 |
|
setSubmenu(fileMenu); |
|
58 |
|
} |
|
59 |
|
|
|
60 |
|
private bool newFCallback(Event event, Widget widget) { |
|
61 |
|
File.New(); |
|
62 |
|
return true; |
|
63 |
|
} |
|
64 |
|
|
|
65 |
|
private bool saveFCallback(Event event, Widget widget) { |
|
66 |
|
File.Save("./" ~ "test.sav"); |
|
67 |
|
return true; |
|
68 |
|
} |
|
69 |
|
|
|
70 |
|
private bool saveAsFCallback(Event event, Widget widget) { |
|
71 |
|
// File.Save() na een soort file choose dialog. |
|
72 |
|
return true; |
|
73 |
|
} |
|
74 |
|
|
|
75 |
|
private bool openFCallback(Event event, Widget widget) { |
|
76 |
|
File.Open("./" ~ "test.sav"); |
|
77 |
|
return true; |
|
78 |
|
} |
|
79 |
|
} |
|
80 |
|
|
|
81 |
|
protected class EditMenu : MenuItem { |
|
|
26 |
|
public class EditMenu : MenuItem { // protected |
82 |
27 |
Menu editMenu; |
Menu editMenu; |
83 |
28 |
|
|
84 |
29 |
MenuItem undo; |
MenuItem undo; |
|
... |
... |
protected class EditMenu : MenuItem { |
110 |
55 |
} |
} |
111 |
56 |
} |
} |
112 |
57 |
|
|
113 |
|
protected class ShapeMenu : MenuItem { |
|
|
58 |
|
public class ShapeMenu : MenuItem { // protected |
114 |
59 |
// Hetgeen wat geactiveerd wordt als je op 'New shape' klikt. |
// Hetgeen wat geactiveerd wordt als je op 'New shape' klikt. |
115 |
60 |
Menu shapeMenu; |
Menu shapeMenu; |
116 |
61 |
|
|
|
... |
... |
protected class ShapeMenu : MenuItem { |
127 |
72 |
rectangle.addOnButtonPress(&rectCallback); |
rectangle.addOnButtonPress(&rectCallback); |
128 |
73 |
shapeMenu.append(rectangle); |
shapeMenu.append(rectangle); |
129 |
74 |
|
|
130 |
|
ellipse = new MenuItem("New ellipse"); |
|
|
75 |
|
/* ellipse = new MenuItem("New ellipse"); |
131 |
76 |
ellipse.addOnButtonPress(&ellipseCallback); |
ellipse.addOnButtonPress(&ellipseCallback); |
132 |
77 |
shapeMenu.append(ellipse); |
shapeMenu.append(ellipse); |
133 |
78 |
|
|
134 |
79 |
circle = new MenuItem("New circle"); |
circle = new MenuItem("New circle"); |
135 |
80 |
circle.addOnButtonPress(&circleCallback); |
circle.addOnButtonPress(&circleCallback); |
136 |
|
shapeMenu.append(circle); |
|
|
81 |
|
shapeMenu.append(circle); */ |
137 |
82 |
|
|
138 |
83 |
setSubmenu(shapeMenu); |
setSubmenu(shapeMenu); |
139 |
84 |
} |
} |
140 |
85 |
|
|
141 |
86 |
private bool rectCallback(Event event, Widget widget) { |
private bool rectCallback(Event event, Widget widget) { |
142 |
|
Brush.Shape = "rectangle"; |
|
|
87 |
|
Global.Brush.shape = "rectangle"; |
143 |
88 |
return true; |
return true; |
144 |
89 |
} |
} |
145 |
90 |
|
|
146 |
91 |
private bool ellipseCallback(Event event, Widget widget) { |
private bool ellipseCallback(Event event, Widget widget) { |
147 |
|
Brush.Shape = "ellipse"; |
|
|
92 |
|
Global.Brush.shape = "ellipse"; |
148 |
93 |
return true; |
return true; |
149 |
94 |
} |
} |
150 |
95 |
|
|
151 |
96 |
private bool circleCallback(Event event, Widget widget) { |
private bool circleCallback(Event event, Widget widget) { |
152 |
|
Brush.Shape = "circle"; |
|
|
97 |
|
Global.Brush.shape = "circle"; |
153 |
98 |
return true; |
return true; |
154 |
99 |
} |
} |
155 |
100 |
} |
} |
File source/shapes/rect.d added (mode: 100644) (index 0000000..60b3770) |
|
1 |
|
module dp.shape.rect; |
|
2 |
|
|
|
3 |
|
import cairo.Context; |
|
4 |
|
import dp.shape.shape; |
|
5 |
|
|
|
6 |
|
import Global = dp.global; |
|
7 |
|
|
|
8 |
|
class Rectangle : Shape { |
|
9 |
|
|
|
10 |
|
this(int x, int y, Context context, double size = 0) { |
|
11 |
|
super(x, y, context, size); |
|
12 |
|
} |
|
13 |
|
|
|
14 |
|
@property |
|
15 |
|
public override string type() { |
|
16 |
|
return "rectangle"; |
|
17 |
|
} |
|
18 |
|
|
|
19 |
|
protected override void initSize(double size) { |
|
20 |
|
this.size = size != 0 ? size : 125; |
|
21 |
|
} |
|
22 |
|
|
|
23 |
|
protected override double[2][2] calcBounds(int x, int y) { |
|
24 |
|
double[2][2] result; |
|
25 |
|
|
|
26 |
|
result[0][0] = x - size / 2; // minX |
|
27 |
|
result[1][0] = x + size / 2; // maxX |
|
28 |
|
result[0][1] = y - size / 2; // minY |
|
29 |
|
result[1][1] = y + size / 2; // maxY |
|
30 |
|
|
|
31 |
|
return result; |
|
32 |
|
} |
|
33 |
|
|
|
34 |
|
protected override void draw() { |
|
35 |
|
c.setSourceRgba(Global.Brush.red, Global.Brush.green, Global.Brush.blue, Global.Brush.alpha); |
|
36 |
|
c.rectangle(bounds[0][0], bounds[0][1], size, size); |
|
37 |
|
} |
|
38 |
|
} |
File source/windows/resizeDialog.d deleted (index dc961a4..0000000) |
1 |
|
module dp.win.resize; |
|
2 |
|
|
|
3 |
|
import gtk.Dialog; |
|
4 |
|
import gtk.MessageDialog; |
|
5 |
|
import gtk.Label; |
|
6 |
|
import gtk.Button; |
|
7 |
|
import gtk.Entry; |
|
8 |
|
|
|
9 |
|
import dp.shape; |
|
10 |
|
import dp.history; |
|
11 |
|
import dp.command.shape; |
|
12 |
|
|
|
13 |
|
public import Global = dp.globals; |
|
14 |
|
|
|
15 |
|
import std.stdio; // Debug |
|
16 |
|
|
|
17 |
|
import std.string, std.conv; |
|
18 |
|
|
|
19 |
|
class ResizeDialog : Dialog { |
|
20 |
|
Shape shape; |
|
21 |
|
Entry factorEntry; |
|
22 |
|
|
|
23 |
|
this(Shape shape) { |
|
24 |
|
super(); |
|
25 |
|
setTitle("Resize shape"); |
|
26 |
|
this.shape = shape; |
|
27 |
|
|
|
28 |
|
factorEntry = new Entry(); |
|
29 |
|
factorEntry.setPlaceholderText("factor"); |
|
30 |
|
|
|
31 |
|
Button confirmBtn = new Button("Resize!", &clickCallback); |
|
32 |
|
|
|
33 |
|
// Content area, containing non-interactable GTK objects. |
|
34 |
|
getContentArea().add(new Label("By what factor should the shape be resized?")); |
|
35 |
|
getContentArea().setBorderWidth(20); |
|
36 |
|
|
|
37 |
|
// Action area, containing interactable GTK objects. |
|
38 |
|
getActionArea().add(factorEntry); |
|
39 |
|
getActionArea().add(confirmBtn); |
|
40 |
|
|
|
41 |
|
showAll(); |
|
42 |
|
} |
|
43 |
|
|
|
44 |
|
void clickCallback (Button button) { |
|
45 |
|
float factor = 1.3; |
|
46 |
|
string input = factorEntry.getText(); |
|
47 |
|
|
|
48 |
|
if(isNumeric(input)) { |
|
49 |
|
factor = parse!float(input); |
|
50 |
|
History.addCommand(new ResizeCmd(shape, factor)); |
|
51 |
|
this.close(); |
|
52 |
|
} |
|
53 |
|
else { |
|
54 |
|
MessageDialog msgd = new MessageDialog ( |
|
55 |
|
this, DialogFlags.MODAL, MessageType.ERROR, ButtonsType.OK, |
|
56 |
|
"'" ~ input ~ "' is an invalid factor. Please use numbers only.", |
|
57 |
|
null |
|
58 |
|
); |
|
59 |
|
scope(exit) msgd.destroy(); |
|
60 |
|
msgd.run(); |
|
61 |
|
} |
|
62 |
|
} |
|
63 |
|
} |
|