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 gesturesdtw_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 msgHideTime
= clockMilli()+5000;
65 // ////////////////////////////////////////////////////////////////////////// //
70 DTWGlyph detectedGlyph
;
74 void fixNameMaxLen () {
76 foreach (/*auto*/ g
; glib
) if (g
.name
.length
> nameMaxLen
) nameMaxLen
= cast(int)g
.name
.length
;
80 // ////////////////////////////////////////////////////////////////////////// //
87 void registerGlyph () {
88 if (drawnGlyph
!is null && drawnGlyph
.valid
&& curGlyphName
.length
> 0) {
89 auto gg
= drawnGlyph
.clone
;
91 gg
.name
= curGlyphName
;
92 usize gpos
= usize
.max
;
93 foreach (/*auto*/ idx
, /*auto*/ g
; glib
) if (g
.name
== curGlyphName
) { gpos
= idx
; break; }
94 if (gpos
!= usize
.max
) {
101 curPattern
= cast(int)gpos
;
107 enum CharHeight
= 10;
109 void frameChanged () {
110 if (sdwin
is null || sdwin
.closed
) return;
113 auto painter
= sdwin
.draw();
115 void drawText (int x
, int y
, const(char)[] str...) {
116 foreach (immutable char ch
; str) {
117 foreach (immutable int dy
; 0..CharHeight
) {
118 ushort v
= glConFont10
.ptr
[cast(ubyte)ch
*CharHeight
+dy
];
119 foreach (immutable int dx
; 0..CharWidth
) {
120 if (v
&0x8000) painter
.drawPixel(Point(x
+dx
, y
+dy
));
128 void fillRect (int x
, int y
, int w
, int h
, Color clr
) {
129 painter
.outlineColor
= clr
;
130 painter
.fillColor
= clr
;
131 painter
.drawRectangle(Point(x
, y
), w
, h
);
132 painter
.fillColor
= Color
.transparent
;
135 void drawRect (int x
, int y
, int w
, int h
, Color clr
) {
136 painter
.outlineColor
= clr
;
137 painter
.fillColor
= Color
.transparent
;
138 painter
.drawRectangle(Point(x
, y
), w
, h
);
142 static immutable string
[] helpText
= [
146 " \2F1\1: toggle help",
147 " \2F2\1: save library to '\4strokes.dat\1'",
148 " \2F3\1: replace library with '\4strokes.dat\1'",
150 " \2DEL\1: delete selected stroke",
153 " \2LMB\1: select name or start drawing",
154 " \2RMB\1: register current stroke as template",
157 static int stlen (string s
) {
159 foreach (immutable char ch
; s
) if (ch
>= 32) ++res
;
164 foreach (/*auto*/ s
; helpText
) {
166 if (ln
> maxlen
) maxlen
= ln
;
169 int wdt
= (maxlen
*CharWidth
+6);
170 int hgt
= (CharHeight
*cast(int)helpText
.length
+6);
171 int x0
= (sdwin
.width
-wdt
)/2;
172 int y0
= (sdwin
.height
-hgt
)/2;
174 fillRect(x0
, y0
, wdt
, hgt
, Color(25, 69, 247));
175 drawRect(x0
, y0
, wdt
, hgt
, Color(255, 255, 255));
176 drawRect(x0
+1, y0
+1, wdt
-2, hgt
-2, Color
.black
);
178 foreach (/*auto*/ idx
, /*auto*/ s
; helpText
) {
179 if (s
.length
== 0) continue;
180 auto ln
= stlen(s
)*CharWidth
;
182 auto y
= idx
*CharHeight
+3;
184 if (s
[0] == '\x1f') {
189 Color fg
= Color(255, 255, 255);
190 foreach (/*auto*/ ch
; st
) {
192 case 1: fg
= Color(255, 255, 255); break;
193 case 2: fg
= Color(0, 255, 0); break;
194 case 3: fg
= Color(255, 255, 0); break;
195 case 4: fg
= Color(255, 127, 0); break;
198 if (ch
< 32) continue;
199 painter
.outlineColor
= fg
;
200 drawText(x0
+x
, y0
+y
, ch
);
206 bool drawYesNoMessage () {
207 if (yesNoMessage
.length
> 0) {
208 fillRect(0, sdwin
.height
-CharHeight
, sdwin
.width
, CharHeight
, Color(128, 0, 0));
209 painter
.outlineColor
= Color(255, 255, 0);
210 drawText(0, sdwin
.height
-CharHeight
, yesNoMessage
);
218 fillRect(0, sdwin
.height
-CharHeight
, sdwin
.width
, CharHeight
, Color(0, 0, 190));
219 painter
.outlineColor
= Color(255, 127, 0);
220 drawText(0, sdwin
.height
-CharHeight
, curGlyphName
);
221 fillRect(CharWidth
*cast(int)curGlyphName
.length
, sdwin
.height
-CharHeight
, CharWidth
, CharHeight
, Color(255, 255, 0));
227 bool drawMessage () {
228 if (msgAlpha
>= 0 && msgText
.length
) {
229 int y
= sdwin
.height
-CharHeight
;
230 fillRect(0, y
, sdwin
.width
, CharHeight
, Color(60, 60, 90));
231 painter
.outlineColor
= Color(255, 255, 255);
232 drawText((sdwin
.width
-CharWidth
*cast(int)msgText
.length
)/2, y
, msgText
);
238 void drawStroke (const(DTWGlyph
) stk
) {
239 painter
.outlineColor
= Color(255, 255, 0);
240 foreach (uint idx
; 1..stk
.length
) {
241 immutable p0
= stk
[idx
-1], p1
= stk
[idx
];
242 double x0
= p0
.x
, y0
= p0
.y
;
243 double x1
= p1
.x
, y1
= p1
.y
;
244 painter
.drawLine(Point(cast(int)x0
, cast(int)y0
), Point(cast(int)x1
, cast(int)y1
));
248 void drawTemplate (const(DTWGlyph
) stk
) {
249 foreach (uint idx
; 1..stk
.length
) {
250 auto g
= cast(ubyte)(255*idx
/(stk
.length
-1));
251 auto b
= cast(ubyte)(255-(255*idx
/(stk
.length
-1)));
252 immutable p0
= stk
[idx
-1], p1
= stk
[idx
];
253 double x0
= p0
.x
, y0
= p0
.y
;
254 double x1
= p1
.x
, y1
= p1
.y
;
259 painter
.outlineColor
= Color(0, g
, b
);
260 painter
.drawLine(Point(cast(int)x0
, cast(int)y0
), Point(cast(int)x1
, cast(int)y1
));
264 void drawStrokeList (int curptr
) {
265 int wdt
= nameMaxLen
*CharWidth
+4;
266 int hgt
= cast(int)(glib
.length
*CharHeight
+4);
267 drawRect(0, 0, wdt
, hgt
, Color
.white
);
268 drawRect(1, 1, wdt
-2, hgt
-2, Color
.black
);
269 foreach (/*auto*/ idx
, /*auto*/ g
; glib
) {
271 if (g
is detectedGlyph
) {
273 col
= Color(255, 255, 255);
274 //bkcol = rgb2col(0, 0, 255);
275 bkcol
= Color(0, 100, 0);
277 col
= Color(255, 127, 0);
278 bkcol
= Color(0, 0, 127);
280 if (curptr
== idx
) bkcol
= Color(0, 127, 0);
281 if (idx
== curPattern
) col
= Color(255, 255, 0);
282 fillRect(2, idx
*CharHeight
+2, wdt
-4, CharHeight
, bkcol
);
283 painter
.outlineColor
= col
;
284 drawText(2, idx
*CharHeight
+2, g
.name
);
288 fillRect(0, 0, sdwin
.width
, sdwin
.height
, Color
.black
); // cls
290 if (curPattern
>= 0 && curPattern
< cast(int)glib
.length
) drawTemplate(glib
[curPattern
]);
291 drawStrokeList(curGlyph
);
292 if (drawnGlyph
!is null && drawnGlyph
.valid
) drawStroke(drawnGlyph
);
294 if (!drawYesNoMessage()) drawEditor();
296 if (helpVisible
) drawHelp();
302 // ////////////////////////////////////////////////////////////////////////// //
306 int getSelectedGlyph (int x
, int y
) {
307 int wdt
= nameMaxLen
*CharWidth
+4;
308 int hgt
= cast(int)(glib
.length
*CharHeight
+4);
309 if (x
>= 2 && y
>= 2 && x
< wdt
-4 && y
< hgt
-4) {
310 return cast(int)((y
-2)/CharHeight
);
317 // ////////////////////////////////////////////////////////////////////////// //
318 void main (string
[] args
) {
319 glib
= gstLibLoad(VFile("strokes.dat"));
321 writefln("%s strokes loaded", glib
.length
);
322 //gstLibSave(File("strokes_new.dat", "w"), glib[]);
323 sdwin
= new SimpleWindow(800, 600, "DTW Gesture Recognizer test");
331 delegate (MouseEvent event
) {
332 switch (event
.type
) {
333 case MouseEventType
.buttonPressed
:
334 if (yesNoMessage
.length
> 0 || editingName
) break;
336 if (event
.button
== MouseButton
.left
) {
337 auto ng
= getSelectedGlyph(event
.x
, event
.y
);
344 if (event
.button
== MouseButton
.left || event
.button
== MouseButton
.right
) {
345 mdown
= (event
.button
== MouseButton
.left ?
1 : 2);
346 detectedGlyph
= null;
347 drawnGlyph
= new DTWGlyph();
348 drawnGlyph
.appendPoint(event
.x
, event
.y
);
353 case MouseEventType
.buttonReleased
:
354 if (yesNoMessage
.length
> 0 || editingName
) return;
356 if (drawnGlyph
.valid
) {
358 detectedGlyph
= cast(DTWGlyph
)drawnGlyph
.findMatch(glib
[]); // sorry
359 if (detectedGlyph
!is null && detectedGlyph
.name
.length
> 0) {
360 showMessage("glyph: '"~detectedGlyph
.name
~"'");
363 curGlyphName
= (curPattern
>= 0 ? glib
[curPattern
].name
: "");
373 case MouseEventType
.motion
:
374 if (yesNoMessage
.length
> 0 || editingName
) break;
376 auto ng
= getSelectedGlyph(event
.x
, event
.y
);
377 if (ng
!= curGlyph
) {
381 } else if (mdown
!= 0) {
382 drawnGlyph
.appendPoint(event
.x
, event
.y
);
390 delegate (KeyEvent event
) {
391 if (!event
.pressed
) return;
393 if (event
== "Escape" || event
== "F1") {
399 if (yesNoMessage
.length
> 0) {
400 if (event
== "Escape") {
402 } else if (event
== "Enter") {
403 glib
= glib
[0..curPattern
]~glib
[curPattern
+1..$];
404 detectedGlyph
= null;
413 if (event == "Escape")
414 switch (event.keysym.sym) {
415 case SDLK_ESCAPE: editingName = false; break;
417 if (curGlyphName.length > 0) curGlyphName = curGlyphName[0..$-1];
419 case SDLK_RETURN: registerGlyph(); editingName = false; break;
422 if (!editingName) stopTextInput();
427 if (event
== "C-Q") { sdwin
.close(); return; }
434 gstLibSave(VFile("strokes.dat", "w"), glib
[]);
435 writefln("%s strokes saved", glib
.length
);
440 glib
= gstLibLoad(VFile("strokes.dat"));
442 writefln("%s strokes loaded", glib
.length
);
443 detectedGlyph
= null;
449 if (event
== "Delete") {
450 if (curPattern
>= 0) {
451 yesNoMessage
= "Remove '"~glib
[curPattern
].name
~"'?";
458 delegate (dchar ch
) {
459 if (!editingName
) return;
460 if (ch
== 27) { editingName
= false; frameChanged(); return; }
462 if (curGlyphName
.length
> 0) curGlyphName
= curGlyphName
[0..$-1];
472 if (ch
== 10 || ch
== 13) {
477 if (ch
>= ' ' && ch
< 127) {
478 curGlyphName
~= cast(char)ch
;