kapstok / NHL-DePa2 (public) (License: Unspecified) (since 2018-11-09) (hash sha1)
Design Patterns school project; a GUI using multiple Design Patterns.
List of commits:
Subject Hash Author Date (UTC)
Rebuild project from scratch. df0f2f82a86581ba9fa3a169d63a950229341a9f Jan Allersma 2018-09-18 15:04:32
Add resize option. 961e464090918d83690ff66838f2fc96c6ad213a Jan Allersma 2018-09-13 18:29:44
Make `MoveCmd` Command-oriented. 2970a8d862285752551be2464422375ca958357f Jan Allersma 2018-09-12 15:33:17
Change of strategy: Make project command-oriented. ce40dffb1675661922411eeb07f148f61a176c22 Jan Allersma 2018-09-12 11:35:45
Initial commit. 38c8818349679937ae25dde38949202ec45ea7b2 Jan Allersma 2018-09-11 20:21:57
Commit df0f2f82a86581ba9fa3a169d63a950229341a9f - Rebuild project from scratch.
Author: Jan Allersma
Author date (UTC): 2018-09-18 15:04
Committer name: Jan Allersma
Committer date (UTC): 2018-09-21 13:39
Parent(s): 961e464090918d83690ff66838f2fc96c6ad213a
Signing key:
Tree: db95daac589c59d4fd492d3af33d70832042e8b2
File Lines added Lines deleted
source/app.d 0 1
source/brush.d 7 0
source/canvas.d 68 0
source/commands/command.d 2 0
source/commands/create.d 29 0
source/commands/shapeCommands.d 0 74
source/drawing/brush.d 0 8
source/drawing/shapeOptions.d 0 72
source/entities/canvas.d 0 123
source/entities/entity.d 0 45
source/entities/group.d 0 21
source/entities/shape.d 0 171
source/file.d 0 74
source/globals.d 13 3
source/history.d 30 7
source/menubar.d 10 65
source/shapes/rect.d 38 0
source/shapes/shape.d 45 0
source/windows/mainWindow.d 3 8
source/windows/resizeDialog.d 0 63
File source/app.d changed (mode: 100644) (index a68c161..87e2d5c)
... ... int main(string[] args) {
8 8
9 9 application.addOnActivate(delegate void(GioApplication app) { application.addOnActivate(delegate void(GioApplication app) {
10 10 Win win = new Win(application); Win win = new Win(application);
11 //new ResizeWin(application);
12 11 }); });
13 12
14 13 return application.run(args); return application.run(args);
File source/brush.d added (mode: 100644) (index 0000000..a66c80b)
1 module dp.brush;
2
3 static string shape;
4 static double red;
5 static double green;
6 static double blue;
7 static double alpha;
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/command.d changed (mode: 100644) (index baacb6b..0274216)
... ... module dp.command.cmd;
4 4 abstract class Command { abstract class Command {
5 5 public abstract void execute(); public abstract void execute();
6 6 public abstract void undo(); public abstract void undo();
7 public abstract void render();
8 public abstract void check(int x, int y);
7 9 } }
File source/commands/create.d added (mode: 100644) (index 0000000..6e82cc8)
1 module dp.command.create;
2
3 import dp.command.cmd;
4 import dp.shape.shape;
5
6 import Global = dp.global;
7
8 public class CreateCmd : Command {
9 private Shape s;
10
11 this(Shape shape) {
12 s = shape;
13 }
14
15 public override void execute() {
16 s.active = true;
17 }
18
19 public override void undo() {
20 s.active = false;
21 }
22
23 public override void render() {
24 s.render();
25 }
26
27 public override void check(int x, int y) {
28 }
29 }
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/brush.d deleted (index 8d9cd40..0000000)
1 module dp.brush;
2
3 string Shape = null;
4 int Size = 125;
5 double Red = 0.5;
6 double Green = 0.9;
7 double Blue = 0.5;
8 double Alpha = 0.8;
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/entity.d deleted (index 47c02d2..0000000)
1 module dp.entity;
2
3 import std.stdio;
4
5 abstract class Entity {
6 protected Entity[] children;
7 public bool enabled = true;
8
9 this() {}
10
11 @property
12 public string type() {
13 return "entity";
14 }
15
16 @property
17 public size_t childrenAmount() {
18 return children.length;
19 }
20
21 public Entity getChild(ulong n) {
22 return getChildren()[n];
23 }
24
25 public Entity[] getChildren() {
26 return children;
27 }
28
29 public void addChild(Entity child) {
30 children.length++;
31 children[children.length - 1] = child;
32 }
33
34 public string treeToString(int depth = 1) { // Laagste depth = 1.
35 string result = this.toString() ~ "\n";
36
37 for(ulong i = 0; i < childrenAmount; i++) {
38 for(int tabs = 0; tabs < depth; tabs++)
39 result ~= "\t";
40
41 result ~= getChildren[i].treeToString(++depth) ~ "\n";
42 }
43 return result;
44 }
45 }
File source/entities/group.d deleted (index f03caad..0000000)
1 module dp.group;
2
3 import Global = dp.globals;
4 import std.conv;
5
6 class Group : Global.Entity {
7 private int index;
8
9 this(int index) {
10 this.index = index;
11 }
12
13 @property
14 public override string type() {
15 return "group";
16 }
17
18 public override string toString() {
19 return text(type, " ", index);
20 }
21 }
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/globals.d changed (mode: 100644) (index 84c27dd..0ea1b31)
1 module dp.globals;
1 module dp.global;
2
3 import dp.canvas;
2 4
3 5 public import dp.history; public import dp.history;
4 public import dp.entity;
5 6 public import Brush = dp.brush; public import Brush = dp.brush;
6 7
7 public dp.canvas.Canvas* canvas;
8 public static Canvas canvas;
9
10 public static void init() {
11 canvas = new Canvas(500,500);
12 Brush.shape = null;
13 Brush.red = 0.5;
14 Brush.green = 0.9;
15 Brush.blue = 0.5;
16 Brush.alpha = 0.8;
17 }
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/shapes/shape.d added (mode: 100644) (index 0000000..5ee84d0)
1 module dp.shape.shape;
2
3 import cairo.Context;
4
5 class Shape {
6 /+
7 bounds[0][0] = minX
8 bounds[1][0] = maxX
9 bounds[0][1] = minY
10 bounds[1][1] = maxY
11 +/
12
13 protected Context c;
14 protected double[2][2] bounds;
15 public double size;
16 public bool active;
17
18 this(int x, int y, Context context, double size = 0) {
19 c = context;
20 initSize(size);
21 active = true;
22 this.bounds = calcBounds(x,y);
23 render();
24 }
25
26 @property
27 public abstract string type();
28
29 /+
30 public string toString() {
31 return text(type, " ", position[0], " ", position[1], " ", size);
32 }
33 +/
34
35 protected abstract double[2][2] calcBounds(int x, int y);
36 protected abstract void initSize(double size);
37 protected abstract void draw();
38
39 public void render() {
40 if(active) {
41 draw();
42 c.fill();
43 }
44 }
45 }
File source/windows/mainWindow.d changed (mode: 100644) (index 10e234b..e915f48)
... ... import gtk.Application;
4 4 import gtk.ApplicationWindow; import gtk.ApplicationWindow;
5 5 import gtk.Box; import gtk.Box;
6 6
7 import dp.canvas;
7 import Global = dp.global;
8 8 import dp.menubar; import dp.menubar;
9 9
10 import Global = dp.globals;
11
12 10 class Win : ApplicationWindow { class Win : ApplicationWindow {
13 Canvas canvas;
14
15 11 this(Application application) { this(Application application) {
16 12 super(application); super(application);
17 13 setTitle("DPainter"); setTitle("DPainter");
 
... ... class Win : ApplicationWindow {
22 18 Box menubar = new Menubar(); Box menubar = new Menubar();
23 19 container.add(menubar); container.add(menubar);
24 20
25 canvas = new Canvas(500, 500);
26 container.add(canvas.area);
27 Global.canvas = &canvas;
21 Global.init();
22 container.add(Global.canvas);
28 23
29 24 add(container); add(container);
30 25 showAll(); showAll();
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 }
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/kapstok/NHL-DePa2

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/kapstok/NHL-DePa2

Clone this repository using git:
git clone git://git.rocketgit.com/user/kapstok/NHL-DePa2

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main