egedit: do not save cursor movement in undo -- this is my stupid habit, and it comple...
[iv.d.git] / dtw_test / gestures_old.d
blobfd26597257cf9b713ea9609b0fa5da28d004b279
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*/;
18 private:
20 import std.stdio;
22 import iv.alice;
23 import iv.videolib;
24 import iv.gengdtw;
27 // ////////////////////////////////////////////////////////////////////////// //
28 ulong msgHideTime = 0;
29 VLOverlay ovlMsg;
30 int msgAlpha = -1;
33 void updateMsg () {
34 if (msgAlpha >= 0) {
35 if (msgAlpha > 0) {
36 if ((msgAlpha += 10) > 255) {
37 msgAlpha = -1;
38 ovlMsg = null;
40 } else {
41 if (getTicks() >= msgHideTime) {
42 msgAlpha = 1;
45 frameChanged();
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);
57 int x = 3;
58 foreach (auto ch; msg) {
60 switch (ch) {
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;
65 default: break;
67 if (ch < 32) continue;
69 ovlMsg.drawChar(x, 3, ch, fg);
70 x += 6;
72 msgHideTime = getTicks()+5000;
73 msgAlpha = 0;
74 frameChanged();
78 // ////////////////////////////////////////////////////////////////////////// //
79 VLOverlay helpOverlay () {
80 static immutable string[] helpText = [
81 "\x1fDemo actions",
82 "\x1f------------",
83 "\3keyboard:\1",
84 " \2F1\1: toggle help",
85 " \2F2\1: save library to '\4strokes.dat\1'",
86 " \2F3\1: replace library with '\4strokes.dat\1'",
87 " \2ESC\1: quit",
88 " \2DEL\1: delete selected stroke",
89 "",
90 "\3mouse:\1",
91 " \2LMB\1: select name or start drawing",
92 " \2RMB\1: register current stroke as template",
95 static auto stlen (string s) {
96 usize res = 0;
97 foreach (immutable char ch; s) if (ch >= 32) ++res;
98 return res;
101 static VLOverlay ovlHelp = null;
103 if (ovlHelp is null) {
104 usize maxlen = 0;
105 foreach (auto s; helpText) {
106 auto ln = stlen(s);
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;
117 auto y = idx*8+3;
118 string st = s;
119 if (s[0] == '\x1f') {
120 st = s[1..$];
121 } else {
122 x = 3;
124 Color fg = rgb2col(255, 255, 255);
125 foreach (auto ch; st) {
126 switch (ch) {
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;
131 default: break;
133 if (ch < 32) continue;
134 ovlHelp.drawChar(x, y, ch, fg);
135 x += 6;
140 return ovlHelp;
144 // ////////////////////////////////////////////////////////////////////////// //
145 DTWGlyph[] glib;
146 int nameMaxLen = 0;
147 int curPattern = -1;
148 DTWGlyph drawnGlyph;
149 DTWGlyph detectedGlyph;
150 bool helpVisible;
153 void fixNameMaxLen () {
154 nameMaxLen = 0;
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;
178 x0 = x0*200+400;
179 y0 = y0*200+300;
180 x1 = x1*200+400;
181 y1 = y1*200+300;
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);
190 with (vscrOvl) {
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) {
196 Color col, bkcol;
197 if (g is detectedGlyph) {
198 // highlighted
199 col = rgb2col(255, 255, 255);
200 //bkcol = rgb2col(0, 0, 255);
201 bkcol = rgb2col(0, 100, 0);
202 } else {
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);
208 with (vscrOvl) {
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) {
218 updateMsg();
222 // ////////////////////////////////////////////////////////////////////////// //
223 int curGlyph = -1;
224 string curGlyphName;
225 bool editingName;
226 string yesNoMessage;
229 void registerGlyph () {
230 if (drawnGlyph !is null && drawnGlyph.valid && curGlyphName.length > 0) {
231 auto gg = drawnGlyph.clone;
232 gg.finish;
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) {
237 glib[gpos] = gg;
238 } else {
239 gpos = glib.length;
240 glib ~= gg;
242 fixNameMaxLen();
243 curPattern = cast(int)gpos;
248 void rebuildCB () {
249 vscrOvl.clear(0);
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) {
254 with (vscrOvl) {
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) {
259 with (vscrOvl) {
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) {
266 auto ho = ovlMsg;
267 ho.blit(vscrOvl, (vlWidth-ho.width)/2, 2, msgAlpha&0xff);
269 if (helpVisible) {
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;
280 frameChanged();
281 return;
286 void onKeyDownCB (in ref SDL_KeyboardEvent ev) {
287 if (ev.keysym.sym == SDLK_RETURN && (ev.keysym.mod&KMOD_ALT)) { switchFullscreen(); return; }
288 if (helpVisible) {
289 if (ev.keysym.sym == SDLK_ESCAPE || ev.keysym.sym == SDLK_F1) {
290 helpVisible = false;
291 frameChanged();
293 return;
295 if (yesNoMessage.length > 0) {
296 switch (ev.keysym.sym) {
297 case SDLK_ESCAPE: yesNoMessage = null; break;
298 case SDLK_RETURN:
299 glib = glib[0..curPattern]~glib[curPattern+1..$];
300 detectedGlyph = null;
301 curPattern = -1;
302 yesNoMessage = null;
303 break;
304 default: break;
306 frameChanged();
307 return;
309 if (editingName) {
310 switch (ev.keysym.sym) {
311 case SDLK_ESCAPE: editingName = false; break;
312 case SDLK_BACKSPACE:
313 if (curGlyphName.length > 0) curGlyphName = curGlyphName[0..$-1];
314 break;
315 case SDLK_RETURN: registerGlyph(); editingName = false; break;
316 default: break;
318 if (!editingName) stopTextInput();
319 frameChanged();
320 return;
322 if (ev.keysym.sym == SDLK_ESCAPE) { postQuitMessage(); return; }
323 if (ev.keysym.sym == SDLK_F1) {
324 helpVisible = true;
325 frameChanged();
326 return;
328 if (ev.keysym.sym == SDLK_F2) {
329 gstLibSave(File("strokes.dat", "w"), glib[]);
330 writefln("%s strokes saved", glib.length);
331 frameChanged();
332 return;
334 if (ev.keysym.sym == SDLK_F3) {
335 glib = gstLibLoad(File("strokes.dat"));
336 fixNameMaxLen();
337 writefln("%s strokes loaded", glib.length);
338 detectedGlyph = null;
339 curPattern = -1;
340 drawnGlyph = null;
341 frameChanged();
342 return;
344 if (ev.keysym.sym == SDLK_DELETE) {
345 if (curPattern >= 0) {
346 yesNoMessage = "Remove '"~glib[curPattern].name~"'?";
347 frameChanged();
348 return;
354 // ////////////////////////////////////////////////////////////////////////// //
355 int mdown = 0;
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);
363 } else {
364 return -1;
369 void onMouseDownCB (in ref SDL_MouseButtonEvent ev) {
370 if (yesNoMessage.length > 0 || editingName) return;
371 if (mdown == 0) {
372 if (ev.button == SDL_BUTTON_LEFT) {
373 auto ng = getSelectedGlyph(ev.x, ev.y);
374 if (ng >= 0) {
375 curPattern = ng;
376 frameChanged();
377 return;
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);
385 frameChanged();
391 void onMouseUpCB (in ref SDL_MouseButtonEvent ev) {
392 if (yesNoMessage.length > 0 || editingName) return;
393 if (mdown != 0) {
394 if (drawnGlyph.valid) {
395 if (mdown == 1) {
396 detectedGlyph = drawnGlyph.findMatch(glib[]);
397 if (detectedGlyph !is null && detectedGlyph.name.length > 0) {
398 showMessage("glyph: '"~detectedGlyph.name~"'");
400 } else {
401 curGlyphName = (curPattern >= 0 ? glib[curPattern].name : "");
402 editingName = true;
403 startTextInput();
405 } else {
406 drawnGlyph = null;
408 frameChanged();
410 mdown = 0;
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;
421 if (mdown == 0) {
422 auto ng = getSelectedGlyph(ev.x, ev.y);
423 if (ng != curGlyph) {
424 curGlyph = ng;
425 frameChanged();
427 } else if (mdown != 0) {
428 drawnGlyph.addPoint(ev.x, ev.y);
429 frameChanged();
434 // ////////////////////////////////////////////////////////////////////////// //
435 void main (string[] args) {
436 glib = gstLibLoad(File("strokes.dat"));
437 fixNameMaxLen();
438 writefln("%s strokes loaded", glib.length);
439 //gstLibSave(File("strokes_new.dat", "w"), glib[]);
440 vlWidth = 800;
441 vlHeight = 600;
442 useMag2x = false;
443 processArgs(args);
444 try {
445 initVideo("Gestures/SDL");
446 } catch (Throwable e) {
447 writeln("FATAL: ", e.msg);
448 return;
451 setFPS(35);
452 onUpdate = &updateCB;
453 onRebuild = &rebuildCB;
454 onKeyDown = &onKeyDownCB;
455 onTextInput = &onTextInputCB;
456 onMouseDown = &onMouseDownCB;
457 onMouseUp = &onMouseUpCB;
458 onMouseDouble = &onMouseDoubleCB;
459 onMouseMotion = &onMouseMotionCB;
460 mainLoop();