1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module gesturespro_test
/*is aliced*/;
21 import arsd
.simpledisplay
;
30 // ////////////////////////////////////////////////////////////////////////// //
34 // ////////////////////////////////////////////////////////////////////////// //
35 ulong msgHideTime
= 0;
43 if ((msgAlpha
+= 10) > 255) {
48 if (clockMilli() >= msgHideTime
) {
57 void showMessage (string msg
) {
58 if (msg
.length
== 0) return;
60 ovlMsg = new VLOverlay(msg.length*6+6, 8+6);
61 ovlMsg.fillRect(0, 0, ovlMsg.width, ovlMsg.height, rgb2col(25, 69, 247));
62 ovlMsg.rect(0, 0, ovlMsg.width, ovlMsg.height, rgb2col(255, 255, 255));
63 ovlMsg.rect(1, 1, ovlMsg.width-2, ovlMsg.height-2, rgb2col(0, 0, 0));
64 Color fg = rgb2col(255, 255, 255);
66 foreach (/+auto+/ ch
; msg
) {
69 case 1: fg = rgb2col(255, 255, 255); break;
70 case 2: fg = rgb2col(0, 255, 0); break;
71 case 3: fg = rgb2col(255, 255, 0); break;
72 case 4: fg = rgb2col(255, 127, 0); break;
75 if (ch < 32) continue;
77 ovlMsg
.drawChar(x
, 3, ch
, fg
);
82 msgHideTime
= clockMilli()+5000;
88 // ////////////////////////////////////////////////////////////////////////// //
93 PTGlyph detectedGlyph
;
97 void fixNameMaxLen () {
99 foreach (/*auto*/ g
; glib
) if (g
.name
.length
> nameMaxLen
) nameMaxLen
= cast(int)g
.name
.length
;
103 // ////////////////////////////////////////////////////////////////////////// //
110 void registerGlyph () {
111 if (drawnGlyph
!is null && drawnGlyph
.valid
&& curGlyphName
.length
> 0) {
112 auto gg
= drawnGlyph
.clone
;
113 gg
.normalize(true); // drop original points
114 gg
.name
= curGlyphName
;
115 usize gpos
= usize
.max
;
116 foreach (/*auto*/ idx
, /*auto*/ g
; glib
) if (g
.name
== curGlyphName
) { gpos
= idx
; break; }
117 if (gpos
!= usize
.max
) {
124 curPattern
= cast(int)gpos
;
129 // ////////////////////////////////////////////////////////////////////////// //
131 enum CharHeight
= 10;
133 void frameChanged () {
134 if (sdwin
is null || sdwin
.closed
) return;
137 auto painter
= sdwin
.draw();
139 void drawText (int x
, int y
, const(char)[] str...) {
140 foreach (immutable char ch
; str) {
141 foreach (immutable int dy
; 0..CharHeight
) {
142 ushort v
= glConFont10
.ptr
[cast(ubyte)ch
*CharHeight
+dy
];
143 foreach (immutable int dx
; 0..CharWidth
) {
145 painter
.drawPixel(Point(x
+dx
, y
+dy
));
146 //painter.drawLine(Point(x+dx, y+dy), Point(x+dx+1, y+dy+1));
155 void helpOverlay () {
156 static immutable string
[] helpText
= [
160 " \2F1\1: toggle help",
161 " \2F2\1: save library to '\4strokes.dat\1'",
162 " \2F3\1: replace library with '\4strokes.dat\1'",
164 " \2DEL\1: delete selected stroke",
167 " \2LMB\1: select name or start drawing",
168 " \2RMB\1: register current stroke as template",
171 static int stlen (string s
) {
173 foreach (immutable char ch
; s
) if (ch
>= 32) ++res
;
178 foreach (/*auto*/ s
; helpText
) {
180 if (ln
> maxlen
) maxlen
= ln
;
183 int wdt
= (maxlen
*CharWidth
+6);
184 int hgt
= (CharHeight
*cast(int)helpText
.length
+6);
185 int x0
= (sdwin
.width
-wdt
)/2;
186 int y0
= (sdwin
.height
-hgt
)/2;
188 painter
.outlineColor
= Color(25, 69, 247);
189 painter
.fillColor
= Color(25, 69, 247);
190 painter
.drawRectangle(Point(x0
, y0
), wdt
, hgt
);
191 painter
.fillColor
= Color
.transparent
;
192 painter
.outlineColor
= Color(255, 255, 255);
193 painter
.drawRectangle(Point(x0
, y0
), wdt
, hgt
);
194 painter
.outlineColor
= Color
.black
;
195 painter
.drawRectangle(Point(x0
+1, y0
+1), wdt
-2, hgt
-2);
197 foreach (/*auto*/ idx
, /*auto*/ s
; helpText
) {
198 if (s
.length
== 0) continue;
199 auto ln
= stlen(s
)*CharWidth
;
201 auto y
= idx
*CharHeight
+3;
203 if (s
[0] == '\x1f') {
208 Color fg
= Color(255, 255, 255);
209 foreach (/*auto*/ ch
; st
) {
211 case 1: fg
= Color(255, 255, 255); break;
212 case 2: fg
= Color(0, 255, 0); break;
213 case 3: fg
= Color(255, 255, 0); break;
214 case 4: fg
= Color(255, 127, 0); break;
217 if (ch
< 32) continue;
218 painter
.outlineColor
= fg
;
219 drawText(x0
+x
, y0
+y
, ch
);
225 void drawStroke (const(PTGlyph
) stk
) {
226 painter
.outlineColor
= Color(255, 255, 0);
227 foreach (uint idx
; 1..stk
.length
) {
228 immutable p0
= stk
[idx
-1], p1
= stk
[idx
];
229 double x0
= p0
.x
, y0
= p0
.y
;
230 double x1
= p1
.x
, y1
= p1
.y
;
231 painter
.drawLine(Point(cast(int)x0
, cast(int)y0
), Point(cast(int)x1
, cast(int)y1
));
235 void drawTemplate (const(PTGlyph
) stk
) {
236 if (!stk
.valid
) return;
237 foreach (uint idx
; 1..stk
.normLength
) {
238 auto g
= cast(ubyte)(255*idx
/(stk
.normLength
-1));
239 auto b
= cast(ubyte)(255-(255*idx
/(stk
.normLength
-1)));
240 immutable p0
= stk
.normPoint(idx
-1), p1
= stk
.normPoint(idx
);
241 double x0
= p0
.x
, y0
= p0
.y
;
242 double x1
= p1
.x
, y1
= p1
.y
;
247 painter
.outlineColor
= Color(0, g
, b
);
248 painter
.drawLine(Point(cast(int)x0
, cast(int)y0
), Point(cast(int)x1
, cast(int)y1
));
252 void drawStrokeList (int curptr
) {
253 int wdt
= nameMaxLen
*CharWidth
+4;
254 int hgt
= cast(int)(glib
.length
*CharHeight
+4);
255 painter
.outlineColor
= Color
.white
;
256 painter
.fillColor
= Color
.transparent
;
257 painter
.drawRectangle(Point(0, 0), wdt
, hgt
);
258 painter
.outlineColor
= Color
.black
;
259 painter
.drawRectangle(Point(1, 1), wdt
-2, hgt
-2);
260 painter
.fillColor
= Color
.white
;
261 painter
.drawRectangle(Point(2, 2), wdt
-4, hgt
-4);
262 painter
.fillColor
= Color
.transparent
;
263 foreach (/*auto*/ idx
, /*auto*/ g
; glib
) {
265 if (g
is detectedGlyph
) {
267 col
= Color(255, 255, 255);
268 //bkcol = rgb2col(0, 0, 255);
269 bkcol
= Color(0, 100, 0);
271 col
= Color(255, 127, 0);
272 bkcol
= Color(0, 0, 127);
274 if (curptr
== idx
) bkcol
= Color(0, 127, 0);
275 if (idx
== curPattern
) col
= Color(255, 255, 0);
276 painter
.outlineColor
= bkcol
;
277 painter
.fillColor
= bkcol
;
278 painter
.drawRectangle(Point(2, idx
*CharHeight
+2), wdt
-4, CharHeight
);
279 painter
.outlineColor
= col
;
280 painter
.fillColor
= Color
.transparent
;
281 drawText(2, idx
*CharHeight
+2, g
.name
);
285 painter
.outlineColor
= Color
.black
;
286 painter
.fillColor
= Color
.black
;
287 painter
.drawRectangle(Point(0, 0), sdwin
.width
, sdwin
.height
);
289 if (curPattern
>= 0 && curPattern
< cast(int)glib
.length
) drawTemplate(glib
[curPattern
]);
290 drawStrokeList(curGlyph
);
291 if (drawnGlyph
!is null && drawnGlyph
.valid
) drawStroke(drawnGlyph
);
292 if (yesNoMessage
.length
> 0) {
293 painter
.outlineColor
= Color(128, 0, 0);
294 painter
.fillColor
= Color(128, 0, 0);
295 painter
.drawRectangle(Point(0, sdwin
.height
-CharHeight
), sdwin
.width
, CharHeight
);
296 painter
.outlineColor
= Color(255, 255, 0);
297 painter
.fillColor
= Color
.transparent
;
298 drawText(0, sdwin
.height
-CharHeight
, yesNoMessage
);
299 } else if (editingName
) {
300 painter
.outlineColor
= Color(0, 0, 190);
301 painter
.fillColor
= Color(0, 0, 190);
302 painter
.drawRectangle(Point(0, sdwin
.height
-CharHeight
), sdwin
.width
, CharHeight
);
303 painter
.outlineColor
= Color(255, 127, 0);
304 painter
.fillColor
= Color
.transparent
;
305 drawText(0, sdwin
.height
-CharHeight
, curGlyphName
);
306 painter
.outlineColor
= Color(255, 255, 0);
307 painter
.fillColor
= Color(255, 255, 0);
308 painter
.drawRectangle(Point(CharWidth
*cast(int)curGlyphName
.length
, sdwin
.height
-CharHeight
), CharWidth
, CharHeight
);
309 painter
.outlineColor
= Color(255, 127, 0);
310 painter
.fillColor
= Color
.transparent
;
312 if (msgAlpha
>= 0 && msgText
.length
) {
313 int y
= sdwin
.height
-CharHeight
;
314 painter
.outlineColor
= Color(60, 60, 90);
315 painter
.fillColor
= Color(60, 60, 90);
316 painter
.drawRectangle(Point(0, y
), sdwin
.width
, CharHeight
);
317 painter
.outlineColor
= Color(255, 255, 255);
318 painter
.fillColor
= Color
.transparent
;
319 drawText((sdwin
.width
-CharWidth
*cast(int)msgText
.length
)/2, y
, msgText
);
320 painter
.fillColor
= Color
.transparent
;
330 // ////////////////////////////////////////////////////////////////////////// //
334 int getSelectedGlyph (int x
, int y
) {
335 int wdt
= nameMaxLen
*CharWidth
+4;
336 int hgt
= cast(int)(glib
.length
*CharHeight
+4);
337 if (x
>= 2 && y
>= 2 && x
< wdt
-4 && y
< hgt
-4) {
338 return cast(int)((y
-2)/CharHeight
);
345 // ////////////////////////////////////////////////////////////////////////// //
346 void main (string
[] args
) {
347 glib
= gstLibLoad(VFile("strokes.dat"));
349 writefln("%s strokes loaded", glib
.length
);
350 //gstLibSave(File("strokes_new.dat", "w"), glib[]);
351 sdwin
= new SimpleWindow(800, 600, "Protractor Gesture Recognizer test");
359 delegate (MouseEvent event
) {
360 switch (event
.type
) {
361 case MouseEventType
.buttonPressed
:
362 if (yesNoMessage
.length
> 0 || editingName
) break;
364 if (event
.button
== MouseButton
.left
) {
365 auto ng
= getSelectedGlyph(event
.x
, event
.y
);
372 if (event
.button
== MouseButton
.left || event
.button
== MouseButton
.right
) {
373 mdown
= (event
.button
== MouseButton
.left ?
1 : 2);
374 detectedGlyph
= null;
375 drawnGlyph
= new PTGlyph();
376 drawnGlyph
.appendPoint(event
.x
, event
.y
);
381 case MouseEventType
.buttonReleased
:
382 if (yesNoMessage
.length
> 0 || editingName
) return;
384 if (drawnGlyph
.valid
) {
387 detectedGlyph
= cast(PTGlyph
)drawnGlyph
.findMatch(glib
[], &score
); // sorry
388 if (detectedGlyph
!is null && detectedGlyph
.name
.length
> 0) {
389 showMessage("glyph: '"~detectedGlyph
.name
~"'");
390 writeln("glyph: '", detectedGlyph
.name
, "'; score: ", score
);
393 curGlyphName
= (curPattern
>= 0 ? glib
[curPattern
].name
: "");
403 case MouseEventType
.motion
:
404 if (yesNoMessage
.length
> 0 || editingName
) break;
406 auto ng
= getSelectedGlyph(event
.x
, event
.y
);
407 if (ng
!= curGlyph
) {
411 } else if (mdown
!= 0) {
412 drawnGlyph
.appendPoint(event
.x
, event
.y
);
420 delegate (KeyEvent event
) {
421 if (!event
.pressed
) return;
423 if (event
== "Escape" || event
== "F1") {
429 if (yesNoMessage
.length
> 0) {
430 if (event
== "Escape") {
432 } else if (event
== "Enter") {
433 glib
= glib
[0..curPattern
]~glib
[curPattern
+1..$];
434 detectedGlyph
= null;
441 if (event
== "C-Q") { sdwin
.close(); return; }
448 gstLibSave(VFile("strokes.dat", "w"), glib
[]);
449 writefln("%s strokes saved", glib
.length
);
454 glib
= gstLibLoad(VFile("strokes.dat"));
456 writefln("%s strokes loaded", glib
.length
);
457 detectedGlyph
= null;
463 if (event
== "Delete") {
464 if (curPattern
>= 0) {
465 yesNoMessage
= "Remove '"~glib
[curPattern
].name
~"'?";
472 delegate (dchar ch
) {
473 if (!editingName
) return;
474 if (ch
== 27) { editingName
= false; frameChanged(); return; }
476 if (curGlyphName
.length
> 0) curGlyphName
= curGlyphName
[0..$-1];
486 if (ch
== 10 || ch
== 13) {
491 if (ch
>= ' ' && ch
< 127) {
492 curGlyphName
~= cast(char)ch
;