libfusefdc: better TR-DOS boot setting
[zymosis.git] / src / ZXEmuT / jimapi_uiovl.c
blobd2a76fb154de91031640caf94036977258ee0aae
1 /***************************************************************************
3 * ZXEmuT -- ZX Spectrum Emulator with Tcl scripting
5 * Copyright (C) 2012-2020 Ketmar Dark <ketmar@ketmar.no-ip.org>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **************************************************************************/
21 // return non-zero to indicate that the key was eaten
22 typedef int (*uiovlOnKeyCB) (UIOverlay *self, SDL_KeyboardEvent *key);
23 // called to render the overlay
24 typedef void (*uiovlOnDrawCB) (UIOverlay *self);
25 // called before destroying the overlay; you cannot cancel it
26 typedef void (*uiovlOnDestroyCB) (UIOverlay *self);
28 enum {
29 // if this flag is set, the overlay will be destroyed by the main code
30 // you cannot destroy overlay from event handlers, hence the flag
31 UIOvlFlag_HIDDEN = 1u<<0,
32 UIOvlFlag_INACTIVE = 1u<<1, // inactive overlays doesn't process keys
33 UIOvlFlag_MUSTDIE = 1u<<15,
36 struct UIOverlay_t {
37 VOverlay *ovl;
38 VExSurface esf;
39 uint32_t uid;
40 char *id; // you can assign ID to the overlay
41 int x0, y0; // position on the screen
42 uint8_t alpha;
43 unsigned flags;
44 uiovlOnKeyCB keycb;
45 uiovlOnDrawCB drawcb;
46 uiovlOnDestroyCB diecb;
47 void *udata;
48 UIOverlay *prev;
49 UIOverlay *next;
52 static UIOverlay *uiovlHead = NULL;
53 static UIOverlay *uiovlTail = NULL;
54 static uint32_t uiovlNextUID = 1u;
57 ////////////////////////////////////////////////////////////////////////////////
58 UIOverlay *uiovlFindById (const char *id) {
59 if (!id || !id[0]) return NULL;
60 for (UIOverlay *ovl = uiovlTail; ovl; ovl = ovl->prev) {
61 if (ovl->id && strcasecmp(ovl->id, id) == 0) return ovl;
63 return NULL;
67 void uiovlDraw (void) {
68 UIOverlay *ovl = uiovlHead;
69 while (ovl) {
70 if (ovl->ovl) {
71 if ((ovl->flags&(UIOvlFlag_MUSTDIE|UIOvlFlag_HIDDEN)) == 0) {
72 if (ovl->drawcb) {
73 vidResetPalette();
74 ovl->esf.vo = ovl->ovl;
75 vResetClip(&ovl->esf);
76 ovl->drawcb(ovl);
79 if ((ovl->flags&(UIOvlFlag_MUSTDIE|UIOvlFlag_HIDDEN)) == 0) {
80 blitVO(ovl->ovl, ovl->x0, ovl->y0, ovl->alpha);
81 vidResetPalette();
84 // remove dead overlay
85 UIOverlay *n = ovl->next;
86 if (ovl->flags&UIOvlFlag_MUSTDIE) {
87 if (ovl->diecb) ovl->diecb(ovl);
88 if (ovl->prev) ovl->prev->next = n; else uiovlHead = n;
89 if (ovl->next) ovl->next->prev = ovl->prev; else uiovlTail = ovl->prev;
90 freeVO(ovl->ovl);
91 if (ovl->id) free(ovl->id);
92 free(ovl);
94 ovl = n;
99 // returns !0 if the key was eaten
100 int uiovlKey (SDL_KeyboardEvent *key) {
101 if (!key) return 0;
102 for (UIOverlay *ovl = uiovlTail; ovl; ovl = ovl->prev) {
103 if ((ovl->flags&(UIOvlFlag_MUSTDIE|UIOvlFlag_INACTIVE)) == 0) {
104 if (ovl->keycb) {
105 const int res = ovl->keycb(ovl, key);
106 if (res) return res;
110 return 0;
114 UIOverlay *uiovlAllocate (int wdt, int hgt) {
115 if (wdt < 1) wdt = 1; else if (wdt > 1024) wdt = 1024;
116 if (hgt < 1) hgt = 1; else if (hgt > 1024) hgt = 1024;
117 UIOverlay *res = malloc(sizeof(UIOverlay));
118 memset(res, 0, sizeof(UIOverlay));
119 res->uid = uiovlNextUID++;
120 if (res->uid == 0) abort(); // just in case
121 res->ovl = createVO(wdt, hgt);
122 res->alpha = 255;
123 res->prev = uiovlTail;
124 res->next = NULL;
125 if (uiovlTail) uiovlTail->next = res; else uiovlHead = res;
126 uiovlTail = res;
127 return res;
131 void uiovlInit (void) {
132 // nothing to do here
136 void uiovlDeinit (void) {
137 // kill all overlays
138 while (uiovlTail) {
139 UIOverlay *ovl = uiovlTail;
140 uiovlTail = ovl->prev;
141 ovl->next = NULL; // just in case
142 if (ovl->diecb) ovl->diecb(ovl);
143 freeVO(ovl->ovl);
144 if (ovl->id) free(ovl->id);
145 free(ovl);
147 uiovlHead = uiovlTail = NULL;
151 ////////////////////////////////////////////////////////////////////////////////
152 // uioverlay xxx
153 typedef int (*JimUIOvlCmdEx) (UIOverlay *ovl, Jim_Interp *interp, int argc, Jim_Obj *const *argv);
155 #define JIMAPI_UIOVL_FN(pname_) \
156 static int jim_uioverlay_##pname_ (UIOverlay *ovl, Jim_Interp *interp, int argc, Jim_Obj *const *argv)
158 #define JIMAPI_UIOVL_ARGC_EXACT(n_) do { \
159 if (argc != 2+(n_)) { Jim_WrongNumArgs(interp, argc, argv, "cmd ...?"); return JIM_ERR; } \
160 } while (0)
162 #define JIMAPI_UIOVL_ARGC_BETWEEN(lo_,hi_) do { \
163 if (argc < 2+(lo_) || argc > 2+(hi_)) { Jim_WrongNumArgs(interp, argc, argv, "cmd ...?"); return JIM_ERR; } \
164 } while (0)
166 #define JIMAPI_UIOVL_ONE_INT_ARG(vname_) do { \
167 if (argc != 3) { Jim_WrongNumArgs(interp, argc, argv, "cmd ...?"); return JIM_ERR; } \
168 long val_val_; \
169 if (Jim_GetLong(interp, argv[2], &val_val_) != JIM_OK) { \
170 jim_SetResStrf(interp, "uioverlay %s: integer expected, got '%s'", Jim_String(argv[0]), Jim_String(argv[2])); \
171 return JIM_ERR; \
173 vname_ = (int)val_val_; \
174 } while (0)
177 ////////////////////////////////////////////////////////////////////////////////
178 typedef struct {
179 Jim_Interp *interp;
180 Jim_Obj *onkey;
181 Jim_Obj *ondraw;
182 Jim_Obj *ondie;
183 Jim_Obj *origlist; // so it will stay anchored
184 Jim_Obj *otherdict;
185 Jim_Obj *self;
186 } UIOverlayJimData;
189 static int jim_uiovl_dispatcher (Jim_Interp *interp, int argc, Jim_Obj *const *argv);
192 static void jimUIOvlDelProc (Jim_Interp *interp, void *udata) {
194 UIOverlay *ovl = (UIOverlay *)udata;
195 fprintf(stderr, "jimUIOvlDelProc: deleting command for uiovl %p (%s)\n", ovl, (ovl->id ? ovl->id : "<noid>"));
200 // this creates "overlay object"
201 static Jim_Obj *createUIOvlCmd (Jim_Interp *interp, UIOverlay *ovl) {
202 if (!ovl) return NULL;
204 UIOverlayJimData *jd = (UIOverlayJimData *)ovl->udata;
205 if (!jd) return NULL;
206 if (!jd->self) {
207 // create new command
208 char namebuf[128];
209 snprintf(namebuf, sizeof(namebuf), "<uioverlay:%08x>", ovl->uid);
210 if (Jim_CreateCommand(interp, namebuf, &jim_uiovl_dispatcher, ovl, &jimUIOvlDelProc) != JIM_OK) {
211 return NULL;
213 jd->self = Jim_NewStringObj(interp, namebuf, -1);
214 Jim_IncrRefCount(jd->self);
215 // cache it
216 (void)Jim_GetCommand(interp, jd->self, JIM_NONE);
219 return jd->self;
223 ////////////////////////////////////////////////////////////////////////////////
224 // ovl getval str -> obj or false
225 JIMAPI_UIOVL_FN(getval) {
226 JIMAPI_UIOVL_ARGC_EXACT(1);
227 UIOverlayJimData *jd = (UIOverlayJimData *)ovl->udata;
228 Jim_Obj *res = NULL;
229 if (Jim_DictKey(jd->interp, jd->otherdict, argv[2], &res, JIM_NONE) != JIM_OK) {
230 //Jim_SetResultString(interp, "", -1);
231 Jim_SetResultBool(interp, 0);
232 } else {
233 Jim_SetResult(interp, res);
235 return JIM_OK;
239 // ovl setval name value -> true
240 JIMAPI_UIOVL_FN(setval) {
241 JIMAPI_UIOVL_ARGC_EXACT(2);
242 UIOverlayJimData *jd = (UIOverlayJimData *)ovl->udata;
243 if (Jim_DictAddElement(jd->interp, jd->otherdict, argv[2], argv[3]) != JIM_OK) {
244 Jim_SetResultString(interp, "dictionary failure", -1);
245 return JIM_ERR;
246 } else {
247 Jim_SetResultBool(interp, 1);
249 return JIM_OK;
253 // ovl getuid -> uint
254 JIMAPI_UIOVL_FN(getuid) {
255 JIMAPI_UIOVL_ARGC_EXACT(0);
256 Jim_SetResultInt(interp, (int)ovl->uid);
257 return JIM_OK;
261 // ovl getid -> string
262 JIMAPI_UIOVL_FN(getid) {
263 JIMAPI_UIOVL_ARGC_EXACT(0);
264 Jim_SetResultString(interp, (ovl->id != NULL ? ovl->id : ""), -1);
265 return JIM_OK;
269 // ovl setid name -> string
270 JIMAPI_UIOVL_FN(setid) {
271 JIMAPI_UIOVL_ARGC_EXACT(1);
272 const char *newid = Jim_String(argv[2]);
273 if (ovl->id) free(ovl->id);
274 ovl->id = (newid[0] ? strdup(newid) : NULL);
275 Jim_SetResultString(interp, (ovl->id != NULL ? ovl->id : ""), -1);
276 return JIM_OK;
280 // ovl getx -> int
281 JIMAPI_UIOVL_FN(getx) {
282 JIMAPI_UIOVL_ARGC_EXACT(0);
283 Jim_SetResultInt(interp, ovl->x0);
284 return JIM_OK;
288 // ovl gety -> int
289 JIMAPI_UIOVL_FN(gety) {
290 JIMAPI_UIOVL_ARGC_EXACT(0);
291 Jim_SetResultInt(interp, ovl->y0);
292 return JIM_OK;
296 // ovl getw -> int
297 JIMAPI_UIOVL_FN(getw) {
298 JIMAPI_UIOVL_ARGC_EXACT(0);
299 Jim_SetResultInt(interp, ovl->ovl->w);
300 return JIM_OK;
304 // ovl geth -> int
305 JIMAPI_UIOVL_FN(geth) {
306 JIMAPI_UIOVL_ARGC_EXACT(0);
307 Jim_SetResultInt(interp, ovl->ovl->h);
308 return JIM_OK;
312 // ovl setx value -> int
313 JIMAPI_UIOVL_FN(setx) {
314 int v;
315 JIMAPI_UIOVL_ONE_INT_ARG(v);
316 ovl->x0 = v;
317 Jim_SetResultInt(interp, v);
318 return JIM_OK;
322 // ovl sety value -> int
323 JIMAPI_UIOVL_FN(sety) {
324 int v;
325 JIMAPI_UIOVL_ONE_INT_ARG(v);
326 ovl->y0 = v;
327 Jim_SetResultInt(interp, v);
328 return JIM_OK;
332 // ovl setw value -> int
333 JIMAPI_UIOVL_FN(setw) {
334 int v;
335 JIMAPI_UIOVL_ONE_INT_ARG(v);
336 if (ovl->ovl) resizeVO(ovl->ovl, v, ovl->ovl->h);
337 Jim_SetResultInt(interp, v);
338 return JIM_OK;
342 // ovl seth value -> int
343 JIMAPI_UIOVL_FN(seth) {
344 int v;
345 JIMAPI_UIOVL_ONE_INT_ARG(v);
346 if (ovl->ovl) resizeVO(ovl->ovl, ovl->ovl->w, v);
347 Jim_SetResultInt(interp, v);
348 return JIM_OK;
352 ////////////////////////////////////////////////////////////////////////////////
353 JIMAPI_UIOVL_FN(isalive) {
354 JIMAPI_UIOVL_ARGC_EXACT(0);
355 Jim_SetResultBool(interp, (ovl->flags&UIOvlFlag_MUSTDIE ? 0 : 1));
356 return JIM_OK;
360 JIMAPI_UIOVL_FN(close) {
361 JIMAPI_UIOVL_ARGC_EXACT(0);
362 ovl->flags |= UIOvlFlag_MUSTDIE;
363 Jim_SetResultBool(interp, 1);
364 return JIM_OK;
368 JIMAPI_UIOVL_FN(isvisible) {
369 JIMAPI_UIOVL_ARGC_EXACT(0);
370 Jim_SetResultBool(interp, (ovl->flags&(UIOvlFlag_MUSTDIE|UIOvlFlag_HIDDEN) ? 0 : 1));
371 return JIM_OK;
375 JIMAPI_UIOVL_FN(hide) {
376 JIMAPI_UIOVL_ARGC_EXACT(0);
377 ovl->flags |= UIOvlFlag_HIDDEN|UIOvlFlag_INACTIVE;
378 Jim_SetResultBool(interp, 1);
379 return JIM_OK;
383 JIMAPI_UIOVL_FN(show) {
384 JIMAPI_UIOVL_ARGC_EXACT(0);
385 ovl->flags &= ~(UIOvlFlag_HIDDEN|UIOvlFlag_INACTIVE);
386 Jim_SetResultBool(interp, 1);
387 return JIM_OK;
391 JIMAPI_UIOVL_FN(isactive) {
392 JIMAPI_UIOVL_ARGC_EXACT(0);
393 Jim_SetResultBool(interp, (ovl->flags&(UIOvlFlag_MUSTDIE|UIOvlFlag_INACTIVE) ? 0 : 1));
394 return JIM_OK;
398 JIMAPI_UIOVL_FN(activate) {
399 JIMAPI_UIOVL_ARGC_EXACT(0);
400 ovl->flags &= ~UIOvlFlag_INACTIVE;
401 Jim_SetResultBool(interp, 1);
402 return JIM_OK;
406 JIMAPI_UIOVL_FN(deactivate) {
407 JIMAPI_UIOVL_ARGC_EXACT(0);
408 ovl->flags |= UIOvlFlag_INACTIVE;
409 Jim_SetResultBool(interp, 1);
410 return JIM_OK;
414 ////////////////////////////////////////////////////////////////////////////////
415 static int juiovlGetIntArgs (int dest[], Jim_Interp *interp, int argc, Jim_Obj *const *argv, int count, int shift) {
416 shift += 2;
417 for (int f = 0; f < count; ++f) {
418 if (f+shift < argc) {
419 long lval;
420 if (Jim_GetLong(interp, argv[f+shift], &lval) != JIM_OK) {
421 jim_SetResStrf(interp, "uioverlay %s: integer expected, got '%s'", Jim_String(argv[0]), Jim_String(argv[f+shift]));
422 return JIM_ERR;
424 dest[f] = (int)lval;
427 return JIM_OK;
431 // ovl clear value -> true
432 JIMAPI_UIOVL_FN(clear) {
433 int v;
434 JIMAPI_UIOVL_ONE_INT_ARG(v);
435 if (ovl->ovl) {
436 clearVO(ovl->ovl, v&0xff);
438 Jim_SetResultBool(interp, 1);
439 return JIM_OK;
443 // ovl fillrect x y w h clr -> true
444 JIMAPI_UIOVL_FN(fillrect) {
445 int iargs[5];
446 JIMAPI_UIOVL_ARGC_EXACT(5);
447 if (juiovlGetIntArgs(iargs, interp, argc, argv, 5, 0) != JIM_OK) return JIM_ERR;
448 if (ovl->ovl) {
449 fillRectVO(ovl->ovl, iargs[0], iargs[1], iargs[2], iargs[3], iargs[4]&0xff);
451 Jim_SetResultBool(interp, 1);
452 return JIM_OK;
456 // ovl rect x y w h clr -> true
457 JIMAPI_UIOVL_FN(rect) {
458 int iargs[5];
459 JIMAPI_UIOVL_ARGC_EXACT(5);
460 if (juiovlGetIntArgs(iargs, interp, argc, argv, 5, 0) != JIM_OK) return JIM_ERR;
461 if (ovl->ovl) {
462 drawFrameVO(ovl->ovl, iargs[0], iargs[1], iargs[2], iargs[3], iargs[4]&0xff);
464 Jim_SetResultBool(interp, 1);
465 return JIM_OK;
469 // ovl putpixel x y clr -> true
470 JIMAPI_UIOVL_FN(putpixel) {
471 int iargs[3];
472 JIMAPI_UIOVL_ARGC_EXACT(3);
473 if (juiovlGetIntArgs(iargs, interp, argc, argv, 3, 0) != JIM_OK) return JIM_ERR;
474 if (ovl->ovl) {
475 putPixelVO(ovl->ovl, iargs[0], iargs[1], iargs[2]&0xff);
477 Jim_SetResultBool(interp, 1);
478 return JIM_OK;
482 // ovl drawchar6 x y char fg [bg] -> true
483 JIMAPI_UIOVL_FN(drawchar6) {
484 int xy[2];
485 int fgbg[2];
486 JIMAPI_UIOVL_ARGC_BETWEEN(4, 5);
487 if (juiovlGetIntArgs(xy, interp, argc, argv, 2, 0) != JIM_OK) return JIM_ERR;
488 fgbg[1] = -1;
489 if (juiovlGetIntArgs(fgbg, interp, argc, argv, 2, 3) != JIM_OK) return JIM_ERR;
490 const char *s = Jim_String(argv[4]);
491 if (ovl->ovl && s && s[0]) {
492 drawChar6VO(ovl->ovl, s[0], xy[0], xy[1], fgbg[0]&0xff, fgbg[1]&0xff);
494 Jim_SetResultBool(interp, 1);
495 return JIM_OK;
499 // ovl drawchar8 x y char fg [bg] -> true
500 JIMAPI_UIOVL_FN(drawchar8) {
501 int xy[2];
502 int fgbg[2];
503 JIMAPI_UIOVL_ARGC_BETWEEN(4, 5);
504 if (juiovlGetIntArgs(xy, interp, argc, argv, 2, 0) != JIM_OK) return JIM_ERR;
505 fgbg[1] = -1;
506 if (juiovlGetIntArgs(fgbg, interp, argc, argv, 2, 3) != JIM_OK) return JIM_ERR;
507 const char *s = Jim_String(argv[4]);
508 if (ovl->ovl && s && s[0]) {
509 drawChar8VO(ovl->ovl, s[0], xy[0], xy[1], fgbg[0]&0xff, fgbg[1]&0xff);
511 Jim_SetResultBool(interp, 1);
512 return JIM_OK;
516 // ovl drawtext6 x y str fg [bg] -> true
517 JIMAPI_UIOVL_FN(drawtext6) {
518 int xy[2];
519 int fgbg[2];
520 JIMAPI_UIOVL_ARGC_BETWEEN(4, 5);
521 if (juiovlGetIntArgs(xy, interp, argc, argv, 2, 0) != JIM_OK) return JIM_ERR;
522 fgbg[1] = -1;
523 if (juiovlGetIntArgs(fgbg, interp, argc, argv, 2, 3) != JIM_OK) return JIM_ERR;
524 const char *s = Jim_String(argv[4]);
525 if (ovl->ovl && s && s[0]) {
526 drawStr6VO(ovl->ovl, s, xy[0], xy[1], fgbg[0]&0xff, fgbg[1]&0xff);
528 Jim_SetResultBool(interp, 1);
529 return JIM_OK;
533 // ovl drawtext8 x y str fg [bg] -> true
534 JIMAPI_UIOVL_FN(drawtext8) {
535 int xy[2];
536 int fgbg[2];
537 JIMAPI_UIOVL_ARGC_BETWEEN(4, 5);
538 if (juiovlGetIntArgs(xy, interp, argc, argv, 2, 0) != JIM_OK) return JIM_ERR;
539 fgbg[1] = -1;
540 if (juiovlGetIntArgs(fgbg, interp, argc, argv, 2, 3) != JIM_OK) return JIM_ERR;
541 const char *s = Jim_String(argv[4]);
542 if (ovl->ovl && s && s[0]) {
543 drawStr8VO(ovl->ovl, s, xy[0], xy[1], fgbg[0]&0xff, fgbg[1]&0xff);
545 Jim_SetResultBool(interp, 1);
546 return JIM_OK;
550 // ovl line x0 y0 x1 y1 clr
551 JIMAPI_UIOVL_FN(draw_line) {
552 int iargs[5];
553 JIMAPI_UIOVL_ARGC_EXACT(5);
554 if (juiovlGetIntArgs(iargs, interp, argc, argv, 5, 0) != JIM_OK) return JIM_ERR;
555 vDrawLine(&ovl->esf, iargs[0], iargs[1], iargs[2], iargs[3], iargs[4]&0xff);
556 Jim_SetResultBool(interp, 1);
557 return JIM_OK;
561 static int jdraw_get_filled_arg (Jim_Interp *interp, int argc, Jim_Obj *const *argv, int idx) {
562 idx += 2;
563 if (idx < 2 || idx >= argc) return 0;
564 int res = 0;
565 if (Jim_GetBoolean(interp, argv[idx], &res) == JIM_OK) return res;
566 const char *opt = Jim_String(argv[idx]);
567 if (strcasecmp(opt, "fill") == 0) res = 1;
568 else if (strcasecmp(opt, "filled") == 0) res = 1;
569 return res;
573 // ovl ellipse x0 y0 x1 y1 clr [filled]
574 JIMAPI_UIOVL_FN(draw_ellipse) {
575 int iargs[5];
576 JIMAPI_UIOVL_ARGC_BETWEEN(5, 6);
577 if (juiovlGetIntArgs(iargs, interp, argc, argv, 5, 0) != JIM_OK) return JIM_ERR;
578 int filled = jdraw_get_filled_arg(interp, argc, argv, 5);
579 if (filled) {
580 vDrawFilledEllipse(&ovl->esf, iargs[0], iargs[1], iargs[2], iargs[3], iargs[4]&0xff);
581 } else {
582 vDrawEllipse(&ovl->esf, iargs[0], iargs[1], iargs[2], iargs[3], iargs[4]&0xff);
584 Jim_SetResultBool(interp, 1);
585 return JIM_OK;
589 // ovl circle xc yc radius clr [filled]
590 JIMAPI_UIOVL_FN(draw_circle) {
591 int iargs[4];
592 JIMAPI_UIOVL_ARGC_BETWEEN(4, 5);
593 if (juiovlGetIntArgs(iargs, interp, argc, argv, 4, 0) != JIM_OK) return JIM_ERR;
594 int filled = jdraw_get_filled_arg(interp, argc, argv, 4);
595 if (filled) {
596 vDrawFilledCircle(&ovl->esf, iargs[0], iargs[1], iargs[2], iargs[3]&0xff);
597 } else {
598 vDrawCircle(&ovl->esf, iargs[0], iargs[1], iargs[2], iargs[3]&0xff);
600 Jim_SetResultBool(interp, 1);
601 return JIM_OK;
605 ////////////////////////////////////////////////////////////////////////////////
606 static int jovl_do_keycb (UIOverlay *self, SDL_KeyboardEvent *key) {
607 int res = 0;
608 UIOverlayJimData *jd = (UIOverlayJimData *)self->udata;
609 if (jd && jd->self && jd->onkey && jd->interp) {
610 // args: self char keyname emacskey pressed
611 const char *kname = sdlFindKeyName(key->keysym.sym);
612 const char *ekey = sdlBuildEmacsKeyName(key);
613 // charstr
614 char ss[2];
615 if (key->keysym.unicode >= 32 && key->keysym.unicode <= 127) {
616 ss[0] = (char)(key->keysym.unicode&0xff);
617 ss[1] = 0;
618 } else {
619 ss[0] = 0;
621 // call handler
622 Jim_Obj *lstb[6];
623 lstb[0] = jd->onkey;
624 lstb[1] = jd->self; // self
625 lstb[2] = Jim_NewStringObj(jd->interp, ss, -1); // char
626 lstb[3] = Jim_NewStringObj(jd->interp, kname, -1); // keyname
627 lstb[4] = Jim_NewStringObj(jd->interp, ekey, -1); // emacskey
628 lstb[5] = Jim_NewIntObj(jd->interp, (key->type == SDL_KEYDOWN ? 1 : 0));
629 if (Jim_EvalObjVector(jd->interp, 6, lstb) != JIM_OK) {
630 Jim_MakeErrorMessage(jd->interp);
631 cprintf("\4=== JIM ERROR ===\n%s\n=================\n", Jim_GetString(Jim_GetResult(jd->interp), NULL));
632 } else {
633 int bval = 0;
634 if (Jim_GetBoolean(jd->interp, Jim_GetResult(jd->interp), &bval) == JIM_OK) res = bval;
637 return res;
641 static void jovl_do_drawcb (UIOverlay *self) {
642 if (!self->ovl) return;
643 UIOverlayJimData *jd = (UIOverlayJimData *)self->udata;
644 if (jd && jd->self && jd->ondraw && jd->interp) {
645 Jim_Obj *lstb[2];
646 lstb[0] = jd->ondraw;
647 lstb[1] = jd->self;
648 if (Jim_EvalObjVector(jd->interp, 2, lstb) != JIM_OK) {
649 Jim_MakeErrorMessage(jd->interp);
650 cprintf("\4=== JIM ERROR ===\n%s\n=================\n", Jim_GetString(Jim_GetResult(jd->interp), NULL));
652 } else {
653 clearVO(self->ovl, 0);
658 static void jovl_do_diecb (UIOverlay *self) {
659 UIOverlayJimData *jd = (UIOverlayJimData *)self->udata;
660 if (jd && jd->self && jd->interp) {
661 if (jd->ondie) {
662 Jim_Obj *lstb[2];
663 lstb[0] = jd->ondie;
664 lstb[1] = jd->self;
665 if (Jim_EvalObjVector(jd->interp, 2, lstb) != JIM_OK) {
666 Jim_MakeErrorMessage(jd->interp);
667 cprintf("\4=== JIM ERROR ===\n%s\n=================\n", Jim_GetString(Jim_GetResult(jd->interp), NULL));
670 if (jd->onkey) Jim_DecrRefCount(jd->interp, jd->onkey);
671 if (jd->ondraw) Jim_DecrRefCount(jd->interp, jd->ondraw);
672 if (jd->ondie) Jim_DecrRefCount(jd->interp, jd->ondie);
673 if (jd->origlist) Jim_DecrRefCount(jd->interp, jd->origlist);
674 if (jd->otherdict) Jim_DecrRefCount(jd->interp, jd->otherdict);
675 if (jd->self) {
676 Jim_DeleteCommand(jd->interp, jd->self);
677 Jim_DecrRefCount(jd->interp, jd->self);
679 free(self->udata);
680 self->udata = NULL;
685 ////////////////////////////////////////////////////////////////////////////////
686 // uiovlobj cmd ...
687 JIMAPI_FN(uiovl_dispatcher) {
688 UIOverlay *ovl = Jim_CmdPrivData(interp);
690 if (argc < 2) { Jim_WrongNumArgs(interp, argc, argv, "cmd ...?"); return JIM_ERR; }
692 if (strcmp(Jim_String(argv[1]), "type") == 0) {
693 const char *typestr = (ovl == NULL || (ovl->flags&UIOvlFlag_MUSTDIE) != 0 ? "" : "uioverlay");
694 Jim_SetResultString(interp, typestr, -1);
695 return JIM_OK;
698 const char *const cmd0n[] = {
699 "getid",
700 "setid",
702 "getuid",
704 "getval",
705 "setval",
707 "getx",
708 "gety",
709 "getw",
710 "geth",
712 "setx",
713 "sety",
714 "setw",
715 "seth",
717 "isalive",
718 "close",
720 "isvisible",
721 "show",
722 "hide",
724 "isactive",
725 "activate",
726 "deactivate",
728 "clear", // clr
729 "rect", // x y w h clr
730 "fillrect", // x y w h clr
731 "drawchar", // x y ch fg [bg]
732 "drawtext", // x y str fg [bg]
733 "drawchar6", // x y ch fg [bg]
734 "drawtext6", // x y str fg [bg]
735 "drawchar8", // x y ch fg [bg]
736 "drawtext8", // x y str fg [bg]
737 "putpixel", // x y clr
739 "line", // x0 y0 x1 y1 clr
740 "circle", // xc yc radius clr [filled]
741 "ellipse", // x0 y0 x1 y1 clr [filled]
742 NULL,
744 static JimUIOvlCmdEx cmd0h[] = {
745 jim_uioverlay_getid,
746 jim_uioverlay_setid,
748 jim_uioverlay_getuid,
750 jim_uioverlay_getval,
751 jim_uioverlay_setval,
753 jim_uioverlay_getx,
754 jim_uioverlay_gety,
755 jim_uioverlay_getw,
756 jim_uioverlay_geth,
758 jim_uioverlay_setx,
759 jim_uioverlay_sety,
760 jim_uioverlay_setw,
761 jim_uioverlay_seth,
763 jim_uioverlay_isalive,
764 jim_uioverlay_close,
766 jim_uioverlay_isvisible,
767 jim_uioverlay_show,
768 jim_uioverlay_hide,
770 jim_uioverlay_isactive,
771 jim_uioverlay_activate,
772 jim_uioverlay_deactivate,
774 jim_uioverlay_clear,
775 jim_uioverlay_rect,
776 jim_uioverlay_fillrect,
778 jim_uioverlay_drawchar6,
779 jim_uioverlay_drawtext6,
780 jim_uioverlay_drawchar6,
781 jim_uioverlay_drawtext6,
782 jim_uioverlay_drawchar8,
783 jim_uioverlay_drawtext8,
784 jim_uioverlay_putpixel,
786 jim_uioverlay_draw_line,
787 jim_uioverlay_draw_circle,
788 jim_uioverlay_draw_ellipse,
790 int cidx;
791 if (Jim_GetEnum(interp, argv[1], cmd0n, &cidx, "uioverlay method", JIM_ERRMSG) == JIM_OK) {
792 return (cmd0h[cidx])(ovl, interp, argc, argv);
795 jim_SetResStrf(interp, "uioverlay: unknown command: '%s'", Jim_String(argv[1]));
796 return JIM_ERR;
800 ////////////////////////////////////////////////////////////////////////////////
801 #define UOVL_PARSE_INT_FIELD() do { \
802 if (Jim_GetLong(interp, val, &ival) != JIM_OK) { \
803 jim_SetResStrf(interp, "uioverlay %s: integer expected for a '%s'", Jim_String(argv[0]), fldname); \
804 goto getlost; \
806 } while (0)
809 // uioverlay create list
810 JIMAPI_FN(uiovl_create) {
811 JIMAPI_UIOVL_ARGC_EXACT(1);
813 Jim_Obj *lsto = jimRemoveComments(interp, argv[2]);
814 Jim_IncrRefCount(lsto);
815 //fprintf(stderr, "=====================\n%s\n-----------------\n", Jim_String(lsto));
817 Jim_Obj *newlist = NULL; // refcount will be 0
818 if (Jim_SubstObj(interp, lsto, &newlist, 0) != JIM_OK) {
819 Jim_MakeErrorMessage(interp);
820 cprintf("\4=== JIM ERROR ===\n%s\n=================\n", Jim_GetString(Jim_GetResult(interp), NULL));
821 Jim_DecrRefCount(interp, lsto);
822 return JIM_ERR;
824 Jim_IncrRefCount(newlist);
826 // collect unknown fields here
827 Jim_Obj *otherdict = Jim_NewDictObj(interp, NULL, 0);
828 Jim_IncrRefCount(otherdict);
830 UIOverlay ovlproto;
831 memset(&ovlproto, 0, sizeof(ovlproto));
833 UIOverlayJimData jimdata;
834 memset(&jimdata, 0, sizeof(jimdata));
835 jimdata.interp = interp;
836 jimdata.origlist = newlist;
837 jimdata.otherdict = otherdict;
839 int wdt = 100;
840 int hgt = 100;
842 // parse it
843 long ival;
844 const int llen = Jim_ListLength(interp, newlist);
845 for (int f = 0; f+1 < llen; f += 2) {
846 const char *fldname = Jim_String(Jim_ListGetIndex(interp, newlist, f));
847 size_t fnlen = strlen(fldname);
848 if (fnlen == 0 || fldname[fnlen-1] != ':') {
849 jim_SetResStrf(interp, "uioverlay %s: '%s' should be a field", Jim_String(argv[0]), fldname);
850 getlost:
851 Jim_DecrRefCount(interp, otherdict);
852 Jim_FreeObj(interp, otherdict);
853 Jim_DecrRefCount(interp, newlist);
854 Jim_DecrRefCount(interp, lsto);
855 if (ovlproto.id) free(ovlproto.id);
856 return JIM_ERR;
858 Jim_Obj *val = Jim_ListGetIndex(interp, newlist, f+1);
859 // "id:"
860 if (strcasecmp(fldname, "id:") == 0) {
861 ovlproto.id = strdup(Jim_String(val));
862 if (!ovlproto.id[0]) { free(ovlproto.id); ovlproto.id = NULL; }
863 continue;
865 // "x:"
866 if (strcasecmp(fldname, "x:") == 0) {
867 UOVL_PARSE_INT_FIELD();
868 ovlproto.x0 = ival;
869 continue;
871 // "y:"
872 if (strcasecmp(fldname, "y:") == 0) {
873 UOVL_PARSE_INT_FIELD();
874 ovlproto.y0 = ival;
875 continue;
877 // "width:"
878 if (strcasecmp(fldname, "width:") == 0 || strcasecmp(fldname, "w:") == 0) {
879 UOVL_PARSE_INT_FIELD();
880 wdt = ival;
881 continue;
883 // "height:"
884 if (strcasecmp(fldname, "height:") == 0 || strcasecmp(fldname, "h:") == 0) {
885 UOVL_PARSE_INT_FIELD();
886 hgt = ival;
887 continue;
889 // "alpha:"
890 if (strcasecmp(fldname, "alpha:") == 0) {
891 UOVL_PARSE_INT_FIELD();
892 if (ival < 0) ival = 0; else if (ival > 255) ival = 255;
893 ovlproto.alpha = (uint8_t)(ival&0xff);
894 continue;
896 // "ondraw:"
897 if (strcasecmp(fldname, "ondraw:") == 0) {
898 jimdata.ondraw = val;
899 continue;
901 // "onkey:"
902 if (strcasecmp(fldname, "onkey:") == 0) {
903 jimdata.onkey = val;
904 continue;
906 // "ondie:"
907 if (strcasecmp(fldname, "ondie:") == 0) {
908 jimdata.ondie = val;
909 continue;
911 // put to `otherdict`
912 if (fldname[0] != ':' && fldname[1]) {
913 Jim_Obj *fn = Jim_NewStringObj(interp, fldname, (int)strlen(fldname)-1);
914 if (Jim_DictAddElement(interp, otherdict, fn, val) != JIM_OK) {
915 jim_SetResStrf(interp, "uioverlay %s: '%s' cannot be put into a dictionary", Jim_String(argv[0]), fldname);
916 goto getlost;
919 //fprintf(stderr, " FIELD: <%s> is <%s>\n", fldname, Jim_String(Jim_ListGetIndex(interp, newlist, f+1)));
922 // parsed, create an object
923 if (jimdata.onkey) Jim_IncrRefCount(jimdata.onkey);
924 if (jimdata.ondraw) Jim_IncrRefCount(jimdata.ondraw);
925 if (jimdata.ondie) Jim_IncrRefCount(jimdata.ondie);
927 UIOverlay *ovl = uiovlAllocate(wdt, hgt);
928 ovl->id = ovlproto.id;
929 ovl->x0 = ovlproto.x0;
930 ovl->y0 = ovlproto.y0;
931 ovl->alpha = ovlproto.alpha;
933 ovl->udata = malloc(sizeof(UIOverlayJimData));
934 memcpy(ovl->udata, &jimdata, sizeof(UIOverlayJimData));
935 ovl->keycb = &jovl_do_keycb;
936 ovl->drawcb = &jovl_do_drawcb;
937 ovl->diecb = &jovl_do_diecb;
939 Jim_SetResult(interp, createUIOvlCmd(interp, ovl));
940 Jim_DecrRefCount(interp, lsto);
941 //Jim_SetResultBool(interp, 1);
942 return JIM_OK;
946 ////////////////////////////////////////////////////////////////////////////////
947 // uioverlay find id
948 JIMAPI_FN(uiovl_findbyid) {
949 JIMAPI_UIOVL_ARGC_EXACT(1);
950 const char *id = Jim_String(argv[2]);
951 if (id[0]) {
952 for (UIOverlay *ovl = uiovlTail; ovl; ovl = ovl->prev) {
953 if (ovl->id && strcasecmp(ovl->id, id) == 0) {
954 Jim_SetResult(interp, createUIOvlCmd(interp, ovl));
955 return JIM_OK;
959 Jim_SetResultBool(interp, 0);
960 return JIM_OK;
964 ////////////////////////////////////////////////////////////////////////////////
965 // uioverlay findbyuid uid
966 JIMAPI_FN(uiovl_findbyuid) {
967 int uid;
968 JIMAPI_UIOVL_ONE_INT_ARG(uid);
969 if (uid > 0) {
970 for (UIOverlay *ovl = uiovlTail; ovl; ovl = ovl->prev) {
971 if (ovl->uid == (uint32_t)uid) {
972 Jim_SetResult(interp, createUIOvlCmd(interp, ovl));
973 return JIM_OK;
977 Jim_SetResultBool(interp, 0);
978 return JIM_OK;
982 ////////////////////////////////////////////////////////////////////////////////
983 // uioverlay killall
984 JIMAPI_FN(uiovl_killall) {
985 JIMAPI_UIOVL_ARGC_EXACT(0);
986 // mark all overlays as "dead"
987 for (UIOverlay *ovl = uiovlHead; ovl; ovl = ovl->next) ovl->flags |= UIOvlFlag_MUSTDIE;
988 Jim_SetResultBool(interp, 1);
989 return JIM_OK;
993 ////////////////////////////////////////////////////////////////////////////////
994 // uioverlay rgb r g b -- cidx
995 JIMAPI_FN(uiovl_rgb) {
996 int rgb[3];
997 JIMAPI_UIOVL_ARGC_EXACT(3);
998 if (juiovlGetIntArgs(rgb, interp, argc, argv, 3, 0) != JIM_OK) return JIM_ERR;
999 const uint8_t clr = vidAllocColor(rgb[0], rgb[1], rgb[2]);
1000 Jim_SetResultInt(interp, clr);
1001 return JIM_OK;
1005 ////////////////////////////////////////////////////////////////////////////////
1006 // uioverlay cmd...
1007 JIMAPI_FN(uioverlay) {
1008 if (argc < 2) {
1009 Jim_WrongNumArgs(interp, argc, argv, "cmd ...?");
1010 return JIM_ERR;
1013 const char *const cmd0n[] = {
1014 "rgb",
1015 "create",
1016 "find",
1017 "findbyuid",
1018 "killall",
1019 NULL
1022 Jim_CmdProc *cmd0h[] = {
1023 jim_uiovl_rgb,
1024 jim_uiovl_create,
1025 jim_uiovl_findbyid,
1026 jim_uiovl_findbyuid,
1027 jim_uiovl_killall,
1030 int cidx = 0;
1031 if (Jim_GetEnum(interp, argv[1], cmd0n, &cidx, "uiovl static method", JIM_ERRMSG) == JIM_OK) {
1032 return (cmd0h[cidx])(interp, argc, argv);
1035 if (argc == 2) {
1036 UIOverlay *ovl = uiovlFindById(Jim_String(argv[1]));
1037 if (ovl != NULL) {
1038 Jim_SetResult(interp, createUIOvlCmd(interp, ovl));
1039 return JIM_OK;
1041 Jim_SetResultBool(interp, 0);
1042 return JIM_OK;
1045 jim_SetResStrf(interp, "%s: wut?!", Jim_String(argv[0]));
1046 return JIM_ERR;
1050 ////////////////////////////////////////////////////////////////////////////////
1051 static void jimRegisterUIOverlayAPI (void) {
1052 JIMAPI_REGISTER(uioverlay);