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*/;
27 // ////////////////////////////////////////////////////////////////////////// //
28 ulong msgHideTime
= 0;
36 if ((msgAlpha
+= 10) > 255) {
41 if (getTicks() >= msgHideTime
) {
50 void showMessage (string msg
) {
51 if (msg
.length
== 0) return;
52 ovlMsg
= new VLOverlay(msg
.length
*6+6, 8+6);
53 ovlMsg
.fillRect(0, 0, ovlMsg
.width
, ovlMsg
.height
, rgb2col(25, 69, 247));
54 ovlMsg
.rect(0, 0, ovlMsg
.width
, ovlMsg
.height
, rgb2col(255, 255, 255));
55 ovlMsg
.rect(1, 1, ovlMsg
.width
-2, ovlMsg
.height
-2, rgb2col(0, 0, 0));
56 Color fg
= rgb2col(255, 255, 255);
58 foreach (auto ch
; msg
) {
61 case 1: fg = rgb2col(255, 255, 255); break;
62 case 2: fg = rgb2col(0, 255, 0); break;
63 case 3: fg = rgb2col(255, 255, 0); break;
64 case 4: fg = rgb2col(255, 127, 0); break;
67 if (ch < 32) continue;
69 ovlMsg
.drawChar(x
, 3, ch
, fg
);
72 msgHideTime
= getTicks()+5000;
78 // ////////////////////////////////////////////////////////////////////////// //
79 VLOverlay
helpOverlay () {
80 static immutable string
[] helpText
= [
84 " \2F1\1: toggle help",
85 " \2F2\1: save library to '\4strokes.dat\1'",
86 " \2F3\1: replace library with '\4strokes.dat\1'",
88 " \2DEL\1: delete selected stroke",
91 " \2LMB\1: select name or start drawing",
92 " \2RMB\1: register current stroke as template",
95 static auto stlen (string s
) {
97 foreach (immutable char ch
; s
) if (ch
>= 32) ++res
;
101 static VLOverlay ovlHelp
= null;
103 if (ovlHelp
is null) {
105 foreach (auto s
; helpText
) {
107 if (ln
> maxlen
) maxlen
= ln
;
109 ovlHelp
= new VLOverlay(maxlen
*6+6, helpText
.length
*8+6);
110 ovlHelp
.fillRect(0, 0, ovlHelp
.width
, ovlHelp
.height
, rgb2col(25, 69, 247));
111 ovlHelp
.rect(0, 0, ovlHelp
.width
, ovlHelp
.height
, rgb2col(255, 255, 255));
112 ovlHelp
.rect(1, 1, ovlHelp
.width
-2, ovlHelp
.height
-2, rgb2col(0, 0, 0));
113 foreach (auto idx
, auto s
; helpText
) {
114 if (s
.length
== 0) continue;
115 auto ln
= stlen(s
)*6;
116 auto x
= (ovlHelp
.width
-ln
)/2;
119 if (s
[0] == '\x1f') {
124 Color fg
= rgb2col(255, 255, 255);
125 foreach (auto ch
; st
) {
127 case 1: fg
= rgb2col(255, 255, 255); break;
128 case 2: fg
= rgb2col(0, 255, 0); break;
129 case 3: fg
= rgb2col(255, 255, 0); break;
130 case 4: fg
= rgb2col(255, 127, 0); break;
133 if (ch
< 32) continue;
134 ovlHelp
.drawChar(x
, y
, ch
, fg
);
144 // ////////////////////////////////////////////////////////////////////////// //
149 DTWGlyph detectedGlyph
;
153 void fixNameMaxLen () {
155 foreach (auto g
; glib
) if (g
.name
.length
> nameMaxLen
) nameMaxLen
= cast(int)g
.name
.length
;
159 // ////////////////////////////////////////////////////////////////////////// //
160 void drawStroke (const(DTWGlyph
) stk
) {
161 auto col
= rgb2col(255, 255, 0);
162 foreach (uint idx
; 1..stk
.length
) {
163 immutable p0
= stk
[idx
-1], p1
= stk
[idx
];
164 double x0
= p0
.x
, y0
= p0
.y
;
165 double x1
= p1
.x
, y1
= p1
.y
;
166 vscrOvl
.line(cast(int)x0
, cast(int)y0
, cast(int)x1
, cast(int)y1
, col
);
171 void drawTemplate (const(DTWGlyph
) stk
) {
172 foreach (uint idx
; 1..stk
.length
) {
173 auto g
= cast(ubyte)(255*idx
/(stk
.length
-1));
174 auto b
= cast(ubyte)(255-(255*idx
/(stk
.length
-1)));
175 immutable p0
= stk
[idx
-1], p1
= stk
[idx
];
176 double x0
= p0
.x
, y0
= p0
.y
;
177 double x1
= p1
.x
, y1
= p1
.y
;
182 vscrOvl
.line(cast(int)x0
, cast(int)y0
, cast(int)x1
, cast(int)y1
, rgb2col(0, g
, b
));
187 void drawStrokeList (int curptr
) {
188 int wdt
= nameMaxLen
*6+4;
189 int hgt
= cast(int)(glib
.length
*8+4);
191 rect(0, 0, wdt
, hgt
, rgb2col(255, 255, 255));
192 rect(1, 1, wdt
-2, hgt
-2, 0);
193 fillRect(2, 2, wdt
-4, hgt
-4, rgb2col(0, 0, 127));
195 foreach (auto idx
, auto g
; glib
) {
197 if (g
is detectedGlyph
) {
199 col
= rgb2col(255, 255, 255);
200 //bkcol = rgb2col(0, 0, 255);
201 bkcol
= rgb2col(0, 100, 0);
203 col
= rgb2col(255, 127, 0);
204 bkcol
= rgb2col(0, 0, 127);
206 if (curptr
== idx
) bkcol
= rgb2col(0, 127, 0);
207 if (idx
== curPattern
) col
= rgb2col(255, 255, 0);
209 fillRect(2, idx
*8+2, wdt
-4, 8, bkcol
);
210 drawStr(2, idx
*8+2, g
.name
, col
);
216 // ////////////////////////////////////////////////////////////////////////// //
217 void updateCB (int elapsedTicks
) {
222 // ////////////////////////////////////////////////////////////////////////// //
229 void registerGlyph () {
230 if (drawnGlyph
!is null && drawnGlyph
.valid
&& curGlyphName
.length
> 0) {
231 auto gg
= drawnGlyph
.clone
;
233 gg
.name
= curGlyphName
;
234 usize gpos
= usize
.max
;
235 foreach (auto idx
, auto g
; glib
) if (g
.name
== curGlyphName
) { gpos
= idx
; break; }
236 if (gpos
!= usize
.max
) {
243 curPattern
= cast(int)gpos
;
250 if (curPattern
>= 0 && curPattern
< cast(int)glib
.length
) drawTemplate(glib
[curPattern
]);
251 drawStrokeList(curGlyph
);
252 if (drawnGlyph
!is null && drawnGlyph
.valid
) drawStroke(drawnGlyph
);
253 if (yesNoMessage
.length
> 0) {
255 fillRect(0, vlHeight
-8, vlWidth
, 8, rgb2col(128, 0, 0));
256 drawStr(0, vlHeight
-8, yesNoMessage
, rgb2col(255, 255, 0));
258 } else if (editingName
) {
260 fillRect(0, vlHeight
-8, vlWidth
, 8, rgb2col(0, 0, 190));
261 drawStr(0, vlHeight
-8, curGlyphName
, rgb2col(255, 127, 0));
262 fillRect(curGlyphName
.length
*6, vlHeight
-8, 6, 8, rgb2col(255, 255, 0));
265 if (msgAlpha
>= 0 && ovlMsg
!is null) {
267 ho
.blit(vscrOvl
, (vlWidth
-ho
.width
)/2, 2, msgAlpha
&0xff);
270 auto ho
= helpOverlay
;
271 ho
.blit(vscrOvl
, (vlWidth
-ho
.width
)/2, (vlHeight
-ho
.height
)/2, 32);
276 // ////////////////////////////////////////////////////////////////////////// //
277 void onTextInputCB (dchar ch
) {
278 if (ch
>= ' ' && ch
<= 255) {
279 curGlyphName
~= cast(char)ch
;
286 void onKeyDownCB (in ref SDL_KeyboardEvent ev
) {
287 if (ev
.keysym
.sym
== SDLK_RETURN
&& (ev
.keysym
.mod
&KMOD_ALT
)) { switchFullscreen(); return; }
289 if (ev
.keysym
.sym
== SDLK_ESCAPE || ev
.keysym
.sym
== SDLK_F1
) {
295 if (yesNoMessage
.length
> 0) {
296 switch (ev
.keysym
.sym
) {
297 case SDLK_ESCAPE
: yesNoMessage
= null; break;
299 glib
= glib
[0..curPattern
]~glib
[curPattern
+1..$];
300 detectedGlyph
= null;
310 switch (ev
.keysym
.sym
) {
311 case SDLK_ESCAPE
: editingName
= false; break;
313 if (curGlyphName
.length
> 0) curGlyphName
= curGlyphName
[0..$-1];
315 case SDLK_RETURN
: registerGlyph(); editingName
= false; break;
318 if (!editingName
) stopTextInput();
322 if (ev
.keysym
.sym
== SDLK_ESCAPE
) { postQuitMessage(); return; }
323 if (ev
.keysym
.sym
== SDLK_F1
) {
328 if (ev
.keysym
.sym
== SDLK_F2
) {
329 gstLibSave(File("strokes.dat", "w"), glib
[]);
330 writefln("%s strokes saved", glib
.length
);
334 if (ev
.keysym
.sym
== SDLK_F3
) {
335 glib
= gstLibLoad(File("strokes.dat"));
337 writefln("%s strokes loaded", glib
.length
);
338 detectedGlyph
= null;
344 if (ev
.keysym
.sym
== SDLK_DELETE
) {
345 if (curPattern
>= 0) {
346 yesNoMessage
= "Remove '"~glib
[curPattern
].name
~"'?";
354 // ////////////////////////////////////////////////////////////////////////// //
358 int getSelectedGlyph (int x
, int y
) {
359 int wdt
= nameMaxLen
*6+4;
360 int hgt
= cast(int)(glib
.length
*8+4);
361 if (x
>= 2 && y
>= 2 && x
< wdt
-4 && y
< hgt
-4) {
362 return cast(int)((y
-2)/8);
369 void onMouseDownCB (in ref SDL_MouseButtonEvent ev
) {
370 if (yesNoMessage
.length
> 0 || editingName
) return;
372 if (ev
.button
== SDL_BUTTON_LEFT
) {
373 auto ng
= getSelectedGlyph(ev
.x
, ev
.y
);
380 if (ev
.button
== SDL_BUTTON_LEFT || ev
.button
== SDL_BUTTON_RIGHT
) {
381 mdown
= (ev
.button
== SDL_BUTTON_LEFT ?
1 : 2);
382 detectedGlyph
= null;
383 drawnGlyph
= new DTWGlyph();
384 drawnGlyph
.addPoint(ev
.x
, ev
.y
);
391 void onMouseUpCB (in ref SDL_MouseButtonEvent ev
) {
392 if (yesNoMessage
.length
> 0 || editingName
) return;
394 if (drawnGlyph
.valid
) {
396 detectedGlyph
= drawnGlyph
.findMatch(glib
[]);
397 if (detectedGlyph
!is null && detectedGlyph
.name
.length
> 0) {
398 showMessage("glyph: '"~detectedGlyph
.name
~"'");
401 curGlyphName
= (curPattern
>= 0 ? glib
[curPattern
].name
: "");
414 void onMouseDoubleCB (in ref SDL_MouseButtonEvent ev
) {
415 //writeln("double button", ev.button, " at (", ev.x, ",", ev.y, ")");
419 void onMouseMotionCB (in ref SDL_MouseMotionEvent ev
) {
420 if (yesNoMessage
.length
> 0 || editingName
) return;
422 auto ng
= getSelectedGlyph(ev
.x
, ev
.y
);
423 if (ng
!= curGlyph
) {
427 } else if (mdown
!= 0) {
428 drawnGlyph
.addPoint(ev
.x
, ev
.y
);
434 // ////////////////////////////////////////////////////////////////////////// //
435 void main (string
[] args
) {
436 glib
= gstLibLoad(File("strokes.dat"));
438 writefln("%s strokes loaded", glib
.length
);
439 //gstLibSave(File("strokes_new.dat", "w"), glib[]);
445 initVideo("Gestures/SDL");
446 } catch (Throwable e
) {
447 writeln("FATAL: ", e
.msg
);
452 onUpdate
= &updateCB
;
453 onRebuild
= &rebuildCB
;
454 onKeyDown
= &onKeyDownCB
;
455 onTextInput
= &onTextInputCB
;
456 onMouseDown
= &onMouseDownCB
;
457 onMouseUp
= &onMouseUpCB
;
458 onMouseDouble
= &onMouseDoubleCB
;
459 onMouseMotion
= &onMouseMotionCB
;