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
);
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,
40 char *id
; // you can assign ID to the overlay
41 int x0
, y0
; // position on the screen
46 uiovlOnDestroyCB diecb
;
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
;
67 void uiovlDraw (void) {
68 UIOverlay
*ovl
= uiovlHead
;
71 if ((ovl
->flags
&(UIOvlFlag_MUSTDIE
|UIOvlFlag_HIDDEN
)) == 0) {
74 ovl
->esf
.vo
= ovl
->ovl
;
75 vResetClip(&ovl
->esf
);
79 if ((ovl
->flags
&(UIOvlFlag_MUSTDIE
|UIOvlFlag_HIDDEN
)) == 0) {
80 blitVO(ovl
->ovl
, ovl
->x0
, ovl
->y0
, ovl
->alpha
);
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
;
91 if (ovl
->id
) free(ovl
->id
);
99 // returns !0 if the key was eaten
100 int uiovlKey (SDL_KeyboardEvent
*key
) {
102 for (UIOverlay
*ovl
= uiovlTail
; ovl
; ovl
= ovl
->prev
) {
103 if ((ovl
->flags
&(UIOvlFlag_MUSTDIE
|UIOvlFlag_INACTIVE
)) == 0) {
105 const int res
= ovl
->keycb(ovl
, key
);
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
);
123 res
->prev
= uiovlTail
;
125 if (uiovlTail
) uiovlTail
->next
= res
; else uiovlHead
= res
;
131 void uiovlInit (void) {
132 // nothing to do here
136 void uiovlDeinit (void) {
139 UIOverlay
*ovl
= uiovlTail
;
140 uiovlTail
= ovl
->prev
;
141 ovl
->next
= NULL
; // just in case
142 if (ovl
->diecb
) ovl
->diecb(ovl
);
144 if (ovl
->id
) free(ovl
->id
);
147 uiovlHead
= uiovlTail
= NULL
;
151 ////////////////////////////////////////////////////////////////////////////////
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; } \
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; } \
166 #define JIMAPI_UIOVL_ONE_INT_ARG(vname_) do { \
167 if (argc != 3) { Jim_WrongNumArgs(interp, argc, argv, "cmd ...?"); return JIM_ERR; } \
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])); \
173 vname_ = (int)val_val_; \
177 ////////////////////////////////////////////////////////////////////////////////
183 Jim_Obj
*origlist
; // so it will stay anchored
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
;
207 // create new command
209 snprintf(namebuf
, sizeof(namebuf
), "<uioverlay:%08x>", ovl
->uid
);
210 if (Jim_CreateCommand(interp
, namebuf
, &jim_uiovl_dispatcher
, ovl
, &jimUIOvlDelProc
) != JIM_OK
) {
213 jd
->self
= Jim_NewStringObj(interp
, namebuf
, -1);
214 Jim_IncrRefCount(jd
->self
);
216 (void)Jim_GetCommand(interp
, jd
->self
, JIM_NONE
);
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
;
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);
233 Jim_SetResult(interp
, res
);
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);
247 Jim_SetResultBool(interp
, 1);
253 // ovl getuid -> uint
254 JIMAPI_UIOVL_FN(getuid
) {
255 JIMAPI_UIOVL_ARGC_EXACT(0);
256 Jim_SetResultInt(interp
, (int)ovl
->uid
);
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);
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);
281 JIMAPI_UIOVL_FN(getx
) {
282 JIMAPI_UIOVL_ARGC_EXACT(0);
283 Jim_SetResultInt(interp
, ovl
->x0
);
289 JIMAPI_UIOVL_FN(gety
) {
290 JIMAPI_UIOVL_ARGC_EXACT(0);
291 Jim_SetResultInt(interp
, ovl
->y0
);
297 JIMAPI_UIOVL_FN(getw
) {
298 JIMAPI_UIOVL_ARGC_EXACT(0);
299 Jim_SetResultInt(interp
, ovl
->ovl
->w
);
305 JIMAPI_UIOVL_FN(geth
) {
306 JIMAPI_UIOVL_ARGC_EXACT(0);
307 Jim_SetResultInt(interp
, ovl
->ovl
->h
);
312 // ovl setx value -> int
313 JIMAPI_UIOVL_FN(setx
) {
315 JIMAPI_UIOVL_ONE_INT_ARG(v
);
317 Jim_SetResultInt(interp
, v
);
322 // ovl sety value -> int
323 JIMAPI_UIOVL_FN(sety
) {
325 JIMAPI_UIOVL_ONE_INT_ARG(v
);
327 Jim_SetResultInt(interp
, v
);
332 // ovl setw value -> int
333 JIMAPI_UIOVL_FN(setw
) {
335 JIMAPI_UIOVL_ONE_INT_ARG(v
);
336 if (ovl
->ovl
) resizeVO(ovl
->ovl
, v
, ovl
->ovl
->h
);
337 Jim_SetResultInt(interp
, v
);
342 // ovl seth value -> int
343 JIMAPI_UIOVL_FN(seth
) {
345 JIMAPI_UIOVL_ONE_INT_ARG(v
);
346 if (ovl
->ovl
) resizeVO(ovl
->ovl
, ovl
->ovl
->w
, v
);
347 Jim_SetResultInt(interp
, v
);
352 ////////////////////////////////////////////////////////////////////////////////
353 JIMAPI_UIOVL_FN(isalive
) {
354 JIMAPI_UIOVL_ARGC_EXACT(0);
355 Jim_SetResultBool(interp
, (ovl
->flags
&UIOvlFlag_MUSTDIE
? 0 : 1));
360 JIMAPI_UIOVL_FN(close
) {
361 JIMAPI_UIOVL_ARGC_EXACT(0);
362 ovl
->flags
|= UIOvlFlag_MUSTDIE
;
363 Jim_SetResultBool(interp
, 1);
368 JIMAPI_UIOVL_FN(isvisible
) {
369 JIMAPI_UIOVL_ARGC_EXACT(0);
370 Jim_SetResultBool(interp
, (ovl
->flags
&(UIOvlFlag_MUSTDIE
|UIOvlFlag_HIDDEN
) ? 0 : 1));
375 JIMAPI_UIOVL_FN(hide
) {
376 JIMAPI_UIOVL_ARGC_EXACT(0);
377 ovl
->flags
|= UIOvlFlag_HIDDEN
|UIOvlFlag_INACTIVE
;
378 Jim_SetResultBool(interp
, 1);
383 JIMAPI_UIOVL_FN(show
) {
384 JIMAPI_UIOVL_ARGC_EXACT(0);
385 ovl
->flags
&= ~(UIOvlFlag_HIDDEN
|UIOvlFlag_INACTIVE
);
386 Jim_SetResultBool(interp
, 1);
391 JIMAPI_UIOVL_FN(isactive
) {
392 JIMAPI_UIOVL_ARGC_EXACT(0);
393 Jim_SetResultBool(interp
, (ovl
->flags
&(UIOvlFlag_MUSTDIE
|UIOvlFlag_INACTIVE
) ? 0 : 1));
398 JIMAPI_UIOVL_FN(activate
) {
399 JIMAPI_UIOVL_ARGC_EXACT(0);
400 ovl
->flags
&= ~UIOvlFlag_INACTIVE
;
401 Jim_SetResultBool(interp
, 1);
406 JIMAPI_UIOVL_FN(deactivate
) {
407 JIMAPI_UIOVL_ARGC_EXACT(0);
408 ovl
->flags
|= UIOvlFlag_INACTIVE
;
409 Jim_SetResultBool(interp
, 1);
414 ////////////////////////////////////////////////////////////////////////////////
415 static int juiovlGetIntArgs (int dest
[], Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int count
, int shift
) {
417 for (int f
= 0; f
< count
; ++f
) {
418 if (f
+shift
< argc
) {
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
]));
431 // ovl clear value -> true
432 JIMAPI_UIOVL_FN(clear
) {
434 JIMAPI_UIOVL_ONE_INT_ARG(v
);
436 clearVO(ovl
->ovl
, v
&0xff);
438 Jim_SetResultBool(interp
, 1);
443 // ovl fillrect x y w h clr -> true
444 JIMAPI_UIOVL_FN(fillrect
) {
446 JIMAPI_UIOVL_ARGC_EXACT(5);
447 if (juiovlGetIntArgs(iargs
, interp
, argc
, argv
, 5, 0) != JIM_OK
) return JIM_ERR
;
449 fillRectVO(ovl
->ovl
, iargs
[0], iargs
[1], iargs
[2], iargs
[3], iargs
[4]&0xff);
451 Jim_SetResultBool(interp
, 1);
456 // ovl rect x y w h clr -> true
457 JIMAPI_UIOVL_FN(rect
) {
459 JIMAPI_UIOVL_ARGC_EXACT(5);
460 if (juiovlGetIntArgs(iargs
, interp
, argc
, argv
, 5, 0) != JIM_OK
) return JIM_ERR
;
462 drawFrameVO(ovl
->ovl
, iargs
[0], iargs
[1], iargs
[2], iargs
[3], iargs
[4]&0xff);
464 Jim_SetResultBool(interp
, 1);
469 // ovl putpixel x y clr -> true
470 JIMAPI_UIOVL_FN(putpixel
) {
472 JIMAPI_UIOVL_ARGC_EXACT(3);
473 if (juiovlGetIntArgs(iargs
, interp
, argc
, argv
, 3, 0) != JIM_OK
) return JIM_ERR
;
475 putPixelVO(ovl
->ovl
, iargs
[0], iargs
[1], iargs
[2]&0xff);
477 Jim_SetResultBool(interp
, 1);
482 // ovl drawchar6 x y char fg [bg] -> true
483 JIMAPI_UIOVL_FN(drawchar6
) {
486 JIMAPI_UIOVL_ARGC_BETWEEN(4, 5);
487 if (juiovlGetIntArgs(xy
, interp
, argc
, argv
, 2, 0) != JIM_OK
) return JIM_ERR
;
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);
499 // ovl drawchar8 x y char fg [bg] -> true
500 JIMAPI_UIOVL_FN(drawchar8
) {
503 JIMAPI_UIOVL_ARGC_BETWEEN(4, 5);
504 if (juiovlGetIntArgs(xy
, interp
, argc
, argv
, 2, 0) != JIM_OK
) return JIM_ERR
;
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);
516 // ovl drawtext6 x y str fg [bg] -> true
517 JIMAPI_UIOVL_FN(drawtext6
) {
520 JIMAPI_UIOVL_ARGC_BETWEEN(4, 5);
521 if (juiovlGetIntArgs(xy
, interp
, argc
, argv
, 2, 0) != JIM_OK
) return JIM_ERR
;
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);
533 // ovl drawtext8 x y str fg [bg] -> true
534 JIMAPI_UIOVL_FN(drawtext8
) {
537 JIMAPI_UIOVL_ARGC_BETWEEN(4, 5);
538 if (juiovlGetIntArgs(xy
, interp
, argc
, argv
, 2, 0) != JIM_OK
) return JIM_ERR
;
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);
550 // ovl line x0 y0 x1 y1 clr
551 JIMAPI_UIOVL_FN(draw_line
) {
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);
561 static int jdraw_get_filled_arg (Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int idx
) {
563 if (idx
< 2 || idx
>= argc
) return 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;
573 // ovl ellipse x0 y0 x1 y1 clr [filled]
574 JIMAPI_UIOVL_FN(draw_ellipse
) {
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);
580 vDrawFilledEllipse(&ovl
->esf
, iargs
[0], iargs
[1], iargs
[2], iargs
[3], iargs
[4]&0xff);
582 vDrawEllipse(&ovl
->esf
, iargs
[0], iargs
[1], iargs
[2], iargs
[3], iargs
[4]&0xff);
584 Jim_SetResultBool(interp
, 1);
589 // ovl circle xc yc radius clr [filled]
590 JIMAPI_UIOVL_FN(draw_circle
) {
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);
596 vDrawFilledCircle(&ovl
->esf
, iargs
[0], iargs
[1], iargs
[2], iargs
[3]&0xff);
598 vDrawCircle(&ovl
->esf
, iargs
[0], iargs
[1], iargs
[2], iargs
[3]&0xff);
600 Jim_SetResultBool(interp
, 1);
605 ////////////////////////////////////////////////////////////////////////////////
606 static int jovl_do_keycb (UIOverlay
*self
, SDL_KeyboardEvent
*key
) {
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
);
615 if (key
->keysym
.unicode
>= 32 && key
->keysym
.unicode
<= 127) {
616 ss
[0] = (char)(key
->keysym
.unicode
&0xff);
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
));
634 if (Jim_GetBoolean(jd
->interp
, Jim_GetResult(jd
->interp
), &bval
) == JIM_OK
) res
= bval
;
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
) {
646 lstb
[0] = jd
->ondraw
;
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
));
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
) {
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
);
676 Jim_DeleteCommand(jd
->interp
, jd
->self
);
677 Jim_DecrRefCount(jd
->interp
, jd
->self
);
685 ////////////////////////////////////////////////////////////////////////////////
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);
698 const char *const cmd0n
[] = {
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]
744 static JimUIOvlCmdEx cmd0h
[] = {
748 jim_uioverlay_getuid
,
750 jim_uioverlay_getval
,
751 jim_uioverlay_setval
,
763 jim_uioverlay_isalive
,
766 jim_uioverlay_isvisible
,
770 jim_uioverlay_isactive
,
771 jim_uioverlay_activate
,
772 jim_uioverlay_deactivate
,
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
,
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]));
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); \
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
);
824 Jim_IncrRefCount(newlist
);
826 // collect unknown fields here
827 Jim_Obj
*otherdict
= Jim_NewDictObj(interp
, NULL
, 0);
828 Jim_IncrRefCount(otherdict
);
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
;
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
);
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
);
858 Jim_Obj
*val
= Jim_ListGetIndex(interp
, newlist
, f
+1);
860 if (strcasecmp(fldname
, "id:") == 0) {
861 ovlproto
.id
= strdup(Jim_String(val
));
862 if (!ovlproto
.id
[0]) { free(ovlproto
.id
); ovlproto
.id
= NULL
; }
866 if (strcasecmp(fldname
, "x:") == 0) {
867 UOVL_PARSE_INT_FIELD();
872 if (strcasecmp(fldname
, "y:") == 0) {
873 UOVL_PARSE_INT_FIELD();
878 if (strcasecmp(fldname
, "width:") == 0 || strcasecmp(fldname
, "w:") == 0) {
879 UOVL_PARSE_INT_FIELD();
884 if (strcasecmp(fldname
, "height:") == 0 || strcasecmp(fldname
, "h:") == 0) {
885 UOVL_PARSE_INT_FIELD();
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);
897 if (strcasecmp(fldname
, "ondraw:") == 0) {
898 jimdata
.ondraw
= val
;
902 if (strcasecmp(fldname
, "onkey:") == 0) {
907 if (strcasecmp(fldname
, "ondie:") == 0) {
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
);
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);
946 ////////////////////////////////////////////////////////////////////////////////
948 JIMAPI_FN(uiovl_findbyid
) {
949 JIMAPI_UIOVL_ARGC_EXACT(1);
950 const char *id
= Jim_String(argv
[2]);
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
));
959 Jim_SetResultBool(interp
, 0);
964 ////////////////////////////////////////////////////////////////////////////////
965 // uioverlay findbyuid uid
966 JIMAPI_FN(uiovl_findbyuid
) {
968 JIMAPI_UIOVL_ONE_INT_ARG(uid
);
970 for (UIOverlay
*ovl
= uiovlTail
; ovl
; ovl
= ovl
->prev
) {
971 if (ovl
->uid
== (uint32_t)uid
) {
972 Jim_SetResult(interp
, createUIOvlCmd(interp
, ovl
));
977 Jim_SetResultBool(interp
, 0);
982 ////////////////////////////////////////////////////////////////////////////////
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);
993 ////////////////////////////////////////////////////////////////////////////////
994 // uioverlay rgb r g b -- cidx
995 JIMAPI_FN(uiovl_rgb
) {
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
);
1005 ////////////////////////////////////////////////////////////////////////////////
1007 JIMAPI_FN(uioverlay
) {
1009 Jim_WrongNumArgs(interp
, argc
, argv
, "cmd ...?");
1013 const char *const cmd0n
[] = {
1022 Jim_CmdProc
*cmd0h
[] = {
1026 jim_uiovl_findbyuid
,
1031 if (Jim_GetEnum(interp
, argv
[1], cmd0n
, &cidx
, "uiovl static method", JIM_ERRMSG
) == JIM_OK
) {
1032 return (cmd0h
[cidx
])(interp
, argc
, argv
);
1036 UIOverlay
*ovl
= uiovlFindById(Jim_String(argv
[1]));
1038 Jim_SetResult(interp
, createUIOvlCmd(interp
, ovl
));
1041 Jim_SetResultBool(interp
, 0);
1045 jim_SetResStrf(interp
, "%s: wut?!", Jim_String(argv
[0]));
1050 ////////////////////////////////////////////////////////////////////////////////
1051 static void jimRegisterUIOverlayAPI (void) {
1052 JIMAPI_REGISTER(uioverlay
);