1 /* DrawOfPages: Take notes with touchscreen input.
2  * Copyright (C) 2017  Marko Semet(Marko10_000)
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 module drawofpages.tools.interaction;
18 
19 private
20 {
21 	import core.thread;
22 	import drawofpages.draw;
23 	import drawofpages.gui;
24 	import drawofpages.tools;
25 	import structuresd.containers.queue;
26 }
27 
28 package struct CursorInteraction
29 {
30 	Point2D pos;
31 	CURSOR_TYPE ctype;
32 	double pressure;
33 	string id;
34 }
35 package struct RedrawInteraction
36 {
37 	Square box;
38 	Draw target;
39 }
40 
41 public class DrawThread : Thread
42 {
43 	private enum INTERACTION_TYPE
44 	{
45 		REDRAW = 0,
46 		CURSOR_DOWN = 1,
47 		CURSOR_CONTIN = 2,
48 		CURSOR_UP = 3
49 	}
50 	private static struct Interaction
51 	{
52 		public INTERACTION_TYPE itype;
53 		public Document doc;
54 		public Tool tool;
55 		public Draw draw;
56 		union
57 		{
58 			public CursorInteraction cursor;
59 			public RedrawInteraction redraw;
60 		}
61 	}
62 
63 	private Queue!(Interaction, true) queue;
64 	public bool stop;
65 
66 	private void run()
67 	{
68 		Interaction tmp;
69 		while(!this.stop)
70 		{
71 			bool[Draw] redraw;
72 			while(this.queue.fetch(tmp))
73 			{
74 				if(tmp.tool is null)
75 				{
76 					continue;
77 				}
78 				final switch(tmp.itype)
79 				{
80 					case INTERACTION_TYPE.REDRAW:
81 						redraw[tmp.draw] = true;
82 						tmp.doc.redraw(tmp.redraw.box, tmp.redraw.target);
83 						break;
84 					case INTERACTION_TYPE.CURSOR_DOWN:
85 						redraw[tmp.draw] = true;
86 						tmp.tool.cursorDown(tmp.doc, tmp.cursor.pos, tmp.cursor.ctype, tmp.cursor.pressure, tmp.cursor.id);
87 						break;
88 					case INTERACTION_TYPE.CURSOR_CONTIN:
89 						redraw[tmp.draw] = true;
90 						tmp.tool.cursorContin(tmp.doc, tmp.cursor.pos, tmp.cursor.ctype, tmp.cursor.pressure, tmp.cursor.id);
91 						break;
92 					case INTERACTION_TYPE.CURSOR_UP:
93 						redraw[tmp.draw] = true;
94 						tmp.tool.cursorUp(tmp.doc, tmp.cursor.pos, tmp.cursor.ctype, tmp.cursor.pressure, tmp.cursor.id);
95 						break;
96 				}
97 			}
98 			foreach(Draw draw; redraw.keys)
99 			{
100 				draw.redraw();
101 			}
102 			yield();
103 		}
104 	}
105 
106 	public this()
107 	{
108 		this.queue = new Queue!(Interaction, true);
109 		this.stop = false;
110 		super(&this.run);
111 		this.start();
112 	}
113 
114 	pragma(inline, true)
115 	private void add(ref Interaction interact)
116 	{
117 		this.queue.insert(interact);
118 	}
119 
120 	pragma(inline, true)
121 	public void add(string TYPE)(Document doc, Draw draw, Tool tool, CursorInteraction ci)
122 	{
123 		Interaction tmp;
124 		static if(TYPE == "DOWN")
125 		{
126 			tmp.itype = INTERACTION_TYPE.CURSOR_DOWN;
127 		}
128 		else static if(TYPE == "CONTIN")
129 		{
130 			tmp.itype = INTERACTION_TYPE.CURSOR_CONTIN;
131 		}
132 		else static if(TYPE == "UP")
133 		{
134 			tmp.itype = INTERACTION_TYPE.CURSOR_UP;
135 		}
136 		else
137 		{
138 			static assert(false);
139 		}
140 		tmp.doc = doc;
141 		tmp.tool = tool;
142 		tmp.cursor = ci;
143 		tmp.draw = draw;
144 		this.add(tmp);
145 	}
146 
147 	pragma(inline, true)
148 	public void add(Document doc, Draw draw, RedrawInteraction redraw)
149 	{
150 		Interaction tmp;
151 		tmp.itype = INTERACTION_TYPE.REDRAW;
152 		tmp.doc = doc;
153 		tmp.tool = voidTool;
154 		tmp.draw = draw;
155 		tmp.redraw = redraw;
156 		this.add(tmp);
157 	}
158 };
159 
160 public class InteractionSafer : GuiInteraction
161 {
162 	private Document document;
163 	public Tool currentTool;
164 	private DrawThread thread;
165 	private Draw draw;
166 
167 	public this(DrawThread thread, Draw draw)
168 	{
169 		this.document = new Document();
170 		this.currentTool = null;
171 		this.thread = thread;
172 		this.draw = draw;
173 	}
174 
175 	public void down(Point2D point, CURSOR_TYPE cursor, double pressure, string cursorID)
176 	{
177 		CursorInteraction ci;
178 		ci.pos = point;
179 		ci.ctype = cursor;
180 		ci.pressure = pressure;
181 		ci.id = cursorID;
182 		thread.add!"DOWN"(this.document, this.draw, this.currentTool, ci);
183 	}
184 	public void contin(Point2D point, CURSOR_TYPE cursor, double pressure, string cursorID)
185 	{
186 		CursorInteraction ci;
187 		ci.pos = point;
188 		ci.ctype = cursor;
189 		ci.pressure = pressure;
190 		ci.id = cursorID;
191 		thread.add!"CONTIN"(this.document, this.draw, this.currentTool, ci);
192 	}
193 	public void up(Point2D point, CURSOR_TYPE cursor, double pressure, string cursorID)
194 	{
195 		CursorInteraction ci;
196 		ci.pos = point;
197 		ci.ctype = cursor;
198 		ci.pressure = pressure;
199 		ci.id = cursorID;
200 		thread.add!"UP"(this.document, this.draw, this.currentTool, ci);
201 	}
202 	public void redraw(Square area, Draw target)
203 	{
204 		RedrawInteraction ri;
205 		ri.box = area;
206 		ri.target = target;
207 		this.thread.add(this.document, this.draw, ri);
208 	}
209 }