File README.md changed (mode: 100644) (index 41ac65b..daf3a8e) |
... |
... |
use 'dub' to compile and run the code. |
6 |
6 |
# Useful draw functions for `Context` type |
# Useful draw functions for `Context` type |
7 |
7 |
|
|
8 |
8 |
- `fill()`: fill path, then forget path. |
- `fill()`: fill path, then forget path. |
|
9 |
|
|
9 |
10 |
- `fillPreserve()`: fill path, retain path. |
- `fillPreserve()`: fill path, retain path. |
10 |
|
- `fillExtends()`, `strokeExtends()` & `pathExtends()`: return corners (whatever that may be). |
|
|
11 |
|
|
|
12 |
|
- `fillExtends()`, `strokeExtends()` & `pathExtends()`: return corners |
|
13 |
|
(whatever that may be). |
|
14 |
|
|
11 |
15 |
- `stroke()`: draw line on path, then forget path. |
- `stroke()`: draw line on path, then forget path. |
|
16 |
|
|
12 |
17 |
- `strokePreserve()`: should be obvious. |
- `strokePreserve()`: should be obvious. |
|
18 |
|
|
13 |
19 |
- `moveTo()`: Move/Pan path. |
- `moveTo()`: Move/Pan path. |
|
20 |
|
|
14 |
21 |
- `scale()`: Scale path. |
- `scale()`: Scale path. |
|
22 |
|
|
15 |
23 |
- `newPath()`: Clear path from context. |
- `newPath()`: Clear path from context. |
|
24 |
|
|
|
25 |
|
# Vragen |
|
26 |
|
|
|
27 |
|
- Is het toegstaan om een implementatie aan een interface toe te voegen, zoals |
|
28 |
|
ik in 'command.d' heb gedaan of breekt dit het Command pattern? |
|
29 |
|
|
|
30 |
|
- Hoe strict is de grammatica voor de file I/O? Dit programma redeneert vanuit |
|
31 |
|
het centrum van een shape en doet alleen aan non-uniform scaling. Daarom is de |
|
32 |
|
huidige toegepaste grammatica handiger. |
File source/commands/command.d changed (mode: 100644) (index 0274216..56c688c) |
1 |
1 |
module dp.command.cmd; |
module dp.command.cmd; |
2 |
2 |
|
|
|
3 |
|
public import dp.file; |
|
4 |
|
|
3 |
5 |
// Should be an interface. Made it a class to prevent the compiler from complaining. |
// Should be an interface. Made it a class to prevent the compiler from complaining. |
4 |
6 |
abstract class Command { |
abstract class Command { |
5 |
7 |
public abstract void execute(); |
public abstract void execute(); |
6 |
8 |
public abstract void undo(); |
public abstract void undo(); |
7 |
9 |
public abstract void render(); |
public abstract void render(); |
8 |
10 |
public abstract void check(int x, int y); |
public abstract void check(int x, int y); |
|
11 |
|
|
|
12 |
|
/+ |
|
13 |
|
The 'save' function should only be overriden by commands that (indirectly) |
|
14 |
|
create a new shape (a command that doesn't apply modifications or deletes |
|
15 |
|
a shape). |
|
16 |
|
+/ |
|
17 |
|
public void save(Savefile file) {}; |
9 |
18 |
} |
} |
File source/commands/load.d added (mode: 100644) (index 0000000..cb91ace) |
|
1 |
|
module dp.command.load; |
|
2 |
|
|
|
3 |
|
import dp.command.cmd; |
|
4 |
|
import dp.shape.shape; |
|
5 |
|
|
|
6 |
|
import Global = dp.global; |
|
7 |
|
|
|
8 |
|
public class LoadCmd : Command { |
|
9 |
|
private Shape[] shapes; |
|
10 |
|
|
|
11 |
|
this(Shape[] shapes) { |
|
12 |
|
this.shapes = shapes; |
|
13 |
|
execute(); // Obsolete, but remained for consistency between 'Command' classes. |
|
14 |
|
} |
|
15 |
|
|
|
16 |
|
public override void execute() { |
|
17 |
|
foreach(shape; shapes) |
|
18 |
|
shape.active = true; |
|
19 |
|
} |
|
20 |
|
|
|
21 |
|
public override void undo() { |
|
22 |
|
foreach(shape; shapes) |
|
23 |
|
shape.active = false; |
|
24 |
|
} |
|
25 |
|
|
|
26 |
|
public override void render() { |
|
27 |
|
foreach(shape; shapes) |
|
28 |
|
shape.render(); |
|
29 |
|
} |
|
30 |
|
|
|
31 |
|
public override void check(int x, int y) { |
|
32 |
|
foreach(shape; shapes) |
|
33 |
|
shape.checkBounds(x,y); |
|
34 |
|
} |
|
35 |
|
|
|
36 |
|
public override void save(Savefile file) { |
|
37 |
|
foreach(shape; shapes) |
|
38 |
|
file.toFile(shape); |
|
39 |
|
} |
|
40 |
|
} |
File source/file.d added (mode: 100644) (index 0000000..5a454bf) |
|
1 |
|
module dp.file; |
|
2 |
|
|
|
3 |
|
import std.stdio; |
|
4 |
|
import std.file; |
|
5 |
|
import std.conv; |
|
6 |
|
import std.array; |
|
7 |
|
import std.string; |
|
8 |
|
|
|
9 |
|
import dp.shape.shape; |
|
10 |
|
import dp.shape.rect, dp.shape.circle, dp.shape.ellipse; |
|
11 |
|
import dp.command.load; |
|
12 |
|
|
|
13 |
|
import Global = dp.global; |
|
14 |
|
|
|
15 |
|
public class Savefile { |
|
16 |
|
private string filename; |
|
17 |
|
private string content; |
|
18 |
|
|
|
19 |
|
this(string filename) { |
|
20 |
|
content = ""; |
|
21 |
|
this.filename = filename; |
|
22 |
|
} |
|
23 |
|
|
|
24 |
|
public void toFile(Shape shape) { |
|
25 |
|
if(!shape.active) |
|
26 |
|
return; |
|
27 |
|
|
|
28 |
|
content ~= shape.type ~ " "; |
|
29 |
|
content ~= to!string(shape.position[0]) ~ " "; |
|
30 |
|
content ~= to!string(shape.position[1]) ~ " "; |
|
31 |
|
content ~= to!string(shape.size) ~ "\n"; |
|
32 |
|
} |
|
33 |
|
|
|
34 |
|
public void fromFile() { |
|
35 |
|
Shape[] shapes = []; |
|
36 |
|
File f = File(filename, "r"); |
|
37 |
|
|
|
38 |
|
while(!f.eof()) { |
|
39 |
|
string line = strip(f.readln()); |
|
40 |
|
|
|
41 |
|
if(line == "") |
|
42 |
|
break; |
|
43 |
|
|
|
44 |
|
shapes.length++; |
|
45 |
|
shapes[shapes.length - 1] = parseLine(line); |
|
46 |
|
} |
|
47 |
|
|
|
48 |
|
f.close(); |
|
49 |
|
|
|
50 |
|
Global.History.clear(); |
|
51 |
|
Global.History.addCommand(new LoadCmd(shapes)); |
|
52 |
|
} |
|
53 |
|
|
|
54 |
|
public void save() { |
|
55 |
|
File f = File(filename, "w"); |
|
56 |
|
|
|
57 |
|
f.write(content); |
|
58 |
|
f.close(); |
|
59 |
|
|
|
60 |
|
content = ""; |
|
61 |
|
} |
|
62 |
|
|
|
63 |
|
private Shape parseLine(string line) { |
|
64 |
|
auto words = line.split(); |
|
65 |
|
|
|
66 |
|
writeln(words); |
|
67 |
|
|
|
68 |
|
final switch(words[0]) { |
|
69 |
|
case "rectangle": |
|
70 |
|
return new Rectangle ( |
|
71 |
|
to!int(words[1]), |
|
72 |
|
to!int(words[2]), |
|
73 |
|
Global.canvas.newContext, |
|
74 |
|
to!double(words[3]) |
|
75 |
|
); |
|
76 |
|
case "circle": |
|
77 |
|
return new Circle ( |
|
78 |
|
to!int(words[1]), |
|
79 |
|
to!int(words[2]), |
|
80 |
|
Global.canvas.newContext, |
|
81 |
|
to!double(words[3]) |
|
82 |
|
); |
|
83 |
|
case "ellipse": |
|
84 |
|
return new Ellipse ( |
|
85 |
|
to!int(words[1]), |
|
86 |
|
to!int(words[2]), |
|
87 |
|
Global.canvas.newContext, |
|
88 |
|
to!double(words[3]) |
|
89 |
|
); |
|
90 |
|
} |
|
91 |
|
} |
|
92 |
|
} |
File source/frontend/menubar.d changed (mode: 100644) (index bbb3b9f..72636ab) |
... |
... |
import gtk.Widget; |
6 |
6 |
import gdk.Event; |
import gdk.Event; |
7 |
7 |
|
|
8 |
8 |
import dp.shape.rect; |
import dp.shape.rect; |
|
9 |
|
import dp.command.load; |
9 |
10 |
|
|
10 |
11 |
import Global = dp.global; |
import Global = dp.global; |
11 |
12 |
|
|
|
... |
... |
public class Menubar : Box { |
15 |
16 |
|
|
16 |
17 |
MenuBar menubar = new MenuBar(); |
MenuBar menubar = new MenuBar(); |
17 |
18 |
|
|
18 |
|
//menubar.append(new FileMenu()); |
|
|
19 |
|
menubar.append(new FileMenu()); |
19 |
20 |
menubar.append(new EditMenu()); |
menubar.append(new EditMenu()); |
20 |
21 |
menubar.append(new ShapeMenu()); |
menubar.append(new ShapeMenu()); |
21 |
22 |
|
|
|
... |
... |
public class Menubar : Box { |
23 |
24 |
} |
} |
24 |
25 |
} |
} |
25 |
26 |
|
|
|
27 |
|
public class FileMenu : MenuItem { // protected |
|
28 |
|
Menu fileMenu; |
|
29 |
|
|
|
30 |
|
MenuItem newFile; |
|
31 |
|
MenuItem save; |
|
32 |
|
MenuItem open; |
|
33 |
|
|
|
34 |
|
this () { |
|
35 |
|
super("File"); |
|
36 |
|
fileMenu = new Menu(); |
|
37 |
|
|
|
38 |
|
newFile = new MenuItem("New"); |
|
39 |
|
newFile.addOnButtonPress(&newCallback); |
|
40 |
|
fileMenu.append(newFile); |
|
41 |
|
|
|
42 |
|
save = new MenuItem("Save"); |
|
43 |
|
save.addOnButtonPress(&saveCallback); |
|
44 |
|
fileMenu.append(save); |
|
45 |
|
|
|
46 |
|
open = new MenuItem("Open"); |
|
47 |
|
open.addOnButtonPress(&openCallback); |
|
48 |
|
fileMenu.append(open); |
|
49 |
|
|
|
50 |
|
setSubmenu(fileMenu); |
|
51 |
|
} |
|
52 |
|
|
|
53 |
|
private bool newCallback(Event event, Widget widget) { |
|
54 |
|
Global.History.clear(); |
|
55 |
|
Global.History.addCommand(new LoadCmd([])); |
|
56 |
|
Global.canvas.repaint(); |
|
57 |
|
return true; |
|
58 |
|
} |
|
59 |
|
|
|
60 |
|
private bool saveCallback(Event event, Widget widget) { |
|
61 |
|
Global.History.save("./test.sav"); |
|
62 |
|
return true; |
|
63 |
|
} |
|
64 |
|
|
|
65 |
|
private bool openCallback(Event event, Widget widget) { |
|
66 |
|
Global.History.load("./test.sav"); |
|
67 |
|
Global.canvas.repaint(); |
|
68 |
|
return true; |
|
69 |
|
} |
|
70 |
|
} |
|
71 |
|
|
26 |
72 |
public class EditMenu : MenuItem { // protected |
public class EditMenu : MenuItem { // protected |
27 |
73 |
Menu editMenu; |
Menu editMenu; |
28 |
74 |
|
|
File source/history.d changed (mode: 100644) (index e439364..feae2f7) |
1 |
1 |
module dp.history; |
module dp.history; |
2 |
2 |
|
|
3 |
3 |
import dp.command.cmd; |
import dp.command.cmd; |
|
4 |
|
import dp.file; |
4 |
5 |
|
|
5 |
6 |
import Global = dp.global; // Geen dependency-cycle? |
import Global = dp.global; // Geen dependency-cycle? |
6 |
7 |
|
|
|
... |
... |
static class History { |
55 |
56 |
foreach(command; commands) |
foreach(command; commands) |
56 |
57 |
command.check(x,y); |
command.check(x,y); |
57 |
58 |
} |
} |
|
59 |
|
|
|
60 |
|
public static void clear() { |
|
61 |
|
cmdPtr = 0; |
|
62 |
|
} |
|
63 |
|
|
|
64 |
|
public static void save(string filename) { |
|
65 |
|
Savefile file = new Savefile(filename); |
|
66 |
|
|
|
67 |
|
foreach(command; commands) |
|
68 |
|
command.save(file); |
|
69 |
|
|
|
70 |
|
file.save(); |
|
71 |
|
} |
|
72 |
|
|
|
73 |
|
public static void load(string filename) { |
|
74 |
|
Savefile file = new Savefile(filename); |
|
75 |
|
|
|
76 |
|
file.fromFile(); |
|
77 |
|
} |
58 |
78 |
} |
} |