1 /*
2
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4
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, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 */
19 /*
20 * $Source: r:/prj/lib/src/ui/RCS/cursors.c $
21 * $Revision: 1.24 $
22 * $Author: mahk $
23 * $Date: 1994/08/24 08:55:41 $
24 *
25 * $Log: cursors.c $
26 * Revision 1.24 1994/08/24 08:55:41 mahk
27 * Cursor stacks and invisible regions.
28 *
29 * Revision 1.23 1994/08/22 04:19:08 mahk
30 * Made real anal cursor_stack spew.
31 *
32 * Revision 1.22 1994/02/10 08:15:25 mahk
33 * Actually caused uiSetDefaultSlabCursor or whatever to actually work as specified instead
34 * of obliterating the top of the cursor stack.
35 *
36 * Revision 1.21 1994/02/07 16:14:43 mahk
37 * Changed the canvas to be more renderer/compatible.
38 *
39 * Revision 1.20 1994/02/06 06:05:03 mahk
40 * Fixed stupid uiPopSlabCursor bug.
41 *
42 * Revision 1.19 1994/01/19 20:52:11 mahk
43 * Fixed black cursor bug yay.
44 *
45 * Revision 1.18 1994/01/16 04:37:40 mahk
46 * Fixed hide/show logic
47 *
48 * Revision 1.17 1993/12/16 07:44:07 kaboom
49 * Moved code actually called from interrupt handler to another
50 * file and made relevant statics public.
51 *
52 * Revision 1.16 1993/10/20 05:13:00 mahk
53 * No longer do we push a canvas in an interrupt.
54 *
55 * Revision 1.15 1993/10/11 20:26:32 dc
56 * Angle is fun, fun fun fun
57 *
58 * Revision 1.14 1993/09/09 19:20:10 mahk
59 * Fixed heap trashage.
60 *
61 * Revision 1.13 1993/08/16 18:24:28 xemu
62 * fixed some spew
63 *
64 * Revision 1.12 1993/08/02 14:21:10 mahk
65 * Save under now grows whenever a bitmap cursor is made
66 *
67 * Revision 1.11 1993/06/08 23:59:36 mahk
68 * Cursors now clip.
69 *
70 * Revision 1.10 1993/05/27 12:49:01 mahk
71 * Lock out reentrance in interrupt mouse drawing.
72 * Mouse rectangle stack grows in size if necessary.
73 *
74 * Revision 1.9 1993/05/26 16:33:55 mahk
75 * Added REAL mouse tolerance.
76 *
77 * Revision 1.8 1993/05/26 03:21:54 mahk
78 * Added way-cool rectangle protection for mousehide, and pixel move tolerance for cursor
79 * draw.
80 *
81 * Revision 1.7 1993/05/25 19:55:14 mahk
82 * Fixed mousehide and show to not leave droppings.
83 *
84 * Revision 1.6 1993/04/28 15:59:23 mahk
85 * conversion to libdbg
86 *
87 * Revision 1.5 1993/04/28 14:39:52 mahk
88 * Preparing for second exodus
89 *
90 * Revision 1.4 1993/04/13 23:18:35 mahk
91 * Added lots of debugging spews.
92 *
93 * Revision 1.3 1993/04/08 17:52:07 mahk
94 * The interrupt handler callback, now, in fact, no longer draws the
95 * mouse cursor when it is hidden. Go Figure.
96 *
97 * Revision 1.2 1993/04/05 23:36:01 unknown
98 * Added hide/show and slab support.
99 *
100 * Revision 1.1 1993/03/31 23:17:24 mahk
101 * Initial revision
102 */
103
104 #include <stdlib.h>
105 #include <string.h>
106
107 #include "lg.h"
108 #include "2d.h"
109 #include "cursors.h"
110 #include "curtyp.h"
111 //#include <libdbg.h>
112 #include "vmouse.h"
113 #include <stdio.h> // printf()
114
115 #define SPEW_ANAL Spew
116
117 #define BMT_SAVEUNDER BMT_FLAT8
118 #define MAPSIZE(x,y) ((x)*(y))
119 #define CURSOR_STACKSIZE 5
120 #define STARTING_SAVEUNDER_WD 16
121 #define STARTING_SAVEUNDER_HT 16
122
123 // -------------------
124 // DEFINES AND GLOBALS
125 // -------------------
126
127 // Global: the saveunder for bitmap cursors
128 struct _cursor_saveunder SaveUnder;
129
130 extern uiSlab* uiCurrentSlab;
131 #define RootCursorRegion (uiCurrentSlab->creg)
132
133 // The region currently occupied by the cursor, and the current cursor to be drawn
134
135 LGRegion* CursorRegion = NULL;
136 LGCursor* CurrentCursor = NULL;
137
138
139 // The last cursor region, for when we undraw.
140
141 LGPoint LastCursorPos;
142 LGRegion* LastCursorRegion = NULL;
143 LGCursor* LastCursor = NULL;
144
145
146 // A semaphore which tells the mouse interrupt handler that the mouse is hidden
147 int MouseLock = 0;
148
149 // A protected rectangle stack for mouse hide/show
150 #define INITIAL_RECT_STACK 5
151 LGRect* HideRect;
152 int numhiderects = INITIAL_RECT_STACK;
153 int curhiderect = 0;
154
155
156 // The canvas used by cursors
157 grs_canvas DefaultCursorCanvas;
158 grs_canvas* CursorCanvas = &DefaultCursorCanvas;
159
160
161 // Number of pixels to move before interrupt handler draws
162 int CursorMoveTolerance = 0;
163
164
165 // ------------------
166 // INTERNAL PROTOTYPES
167 // ------------------
168 typedef struct _cursor_callback_state
169 {
170 LGCursor** out;
171 LGRegion** reg;
172 } cstate;
173
174 uchar cursor_get_callback(LGRegion* reg, LGRect* rect, void* vp);
175
176 errtype ui_init_cursor_stack(uiSlab* slab, LGCursor* default_cursor);
177 errtype ui_init_cursors(void);
178 errtype ui_shutdown_cursors(void);
179 uchar ui_set_current_cursor(LGPoint pos);
180 void ui_update_cursor(LGPoint pos);
181
182
183 // ------------------
184 // INTERNAL FUNCTIONS
185 // ------------------
186
187 // KLC - now just allocates a bitmap at the beginning and never actually grows it.
grow_save_under(short x,short y)188 static errtype grow_save_under(short x, short y)
189 {
190 int sz = MAPSIZE(x,y);
191 if (SaveUnder.mapsize >= sz) return ERR_NOEFFECT;
192
193 // Clear out old SaveUnder
194 if(SaveUnder.mapsize > 0) {
195 free(SaveUnder.bm.bits);
196 }
197
198 // Grow bigger than we actually need so that this doesn't happen all the time
199 int newsize = sz * 2;
200 SaveUnder.bm.bits = (uchar *)malloc(newsize);
201 SaveUnder.mapsize = newsize;
202 return OK;
203 }
204
205
cursor_get_callback(LGRegion * reg,LGRect * rect,void * vp)206 uchar cursor_get_callback(LGRegion* reg, LGRect* rect, void *vp)
207 {
208 cstate *s = (cstate *)vp;
209 cursor_stack* cs = (cursor_stack*)(reg->cursors);
210 uchar anal = FALSE;
211 //DBG(DSRC_UI_Anal, { anal = TRUE;});
212 //if (anal) SPEW_ANAL(DSRC_UI_Cursor_Stack,("cursor_get_callback(%x,%x,%x)\n",reg,rect,s));
213 if (cs == NULL) *(s->out) = NULL;
214 else
215 {
216 *(s->out) = cs->stack[cs->fullness-1];
217 *(s->reg) = reg;
218 }
219 if (*(s->out) == NULL && uiCurrentSlab != NULL)
220 {
221 //if (anal) SPEW_ANAL(DSRC_UI_Cursor_Stack,("cursor_get_callback(): using global default\n"));
222 *(s->out) = uiCurrentSlab->cstack.stack[0];
223 }
224 return *(s->out) != NULL;
225 }
226
227 #define cstack_init uiMakeCursorStack
228
uiMakeCursorStack(cursor_stack * res)229 errtype uiMakeCursorStack(cursor_stack* res)
230 {
231 // Spew(DSRC_UI_Cursor_Stack,("cstack_init(%x)\n",res));
232 if (res == NULL)
233 return ERR_NULL;
234 res->size = CURSOR_STACKSIZE;
235 res->stack = (LGCursor**)malloc(sizeof(LGCursor*) * res->size);
236 if (res->stack == NULL)
237 {
238 free(res);
239 return ERR_NOMEM;
240 }
241 res->fullness = 1;
242 res->stack[0] = NULL;
243 return OK;
244 }
245
246 #define ui_destroy_cursor_stack uiDestroyCursorStack
247
248
uiDestroyCursorStack(cursor_stack * cstack)249 errtype uiDestroyCursorStack(cursor_stack* cstack)
250 {
251 // Spew(DSRC_UI_Cursor_Stack,("ui_destroy_cursor_stack(%x) \n",cstack));
252 if (cstack == NULL) return ERR_NULL;
253 if (cstack->size== 0) return ERR_NOEFFECT;
254 cstack->size = 0;
255 free(cstack->stack);
256 return OK;
257 }
258
259
260
uiSetRegionCursorStack(LGRegion * r,uiCursorStack * cs)261 errtype uiSetRegionCursorStack(LGRegion* r, uiCursorStack* cs)
262 {
263 if (r == NULL) return ERR_NULL;
264 r->cursors = cs;
265 return OK;
266 }
267
uiGetSlabCursorStack(uiSlab * slab,uiCursorStack ** cs)268 errtype uiGetSlabCursorStack(uiSlab* slab, uiCursorStack** cs)
269 {
270 if (slab == NULL) return ERR_NULL;
271 *cs = &slab->cstack;
272 return OK;
273 }
274
uiSetDefaultCursor(uiCursorStack * cs,LGCursor * c)275 errtype uiSetDefaultCursor(uiCursorStack* cs, LGCursor* c)
276 {
277 if (cs == NULL) return ERR_NULL;
278 cs->stack[0] = c;
279 return OK;
280 }
281
282
uiGetDefaultCursor(uiCursorStack * cs,LGCursor ** c)283 errtype uiGetDefaultCursor(uiCursorStack* cs, LGCursor** c)
284 {
285 if (cs == NULL) return ERR_NULL;
286 *c = cs->stack[0];
287 return OK;
288 }
289
290
291 #define cs_push uiPushCursor
292
uiPushCursor(cursor_stack * cs,LGCursor * c)293 errtype uiPushCursor(cursor_stack* cs, LGCursor* c)
294 {
295 if (cs == NULL) return ERR_NULL;
296 if (cs->fullness >= cs->size)
297 {
298 LGCursor** tmp = (LGCursor**)malloc(cs->size*2*sizeof(LGCursor*));
299 //SPEW_ANAL(DSRC_UI_Cursor_Stack,("cs_push(%x,%x), growing stack\n",cs,c));
300 if (tmp == NULL) return ERR_NOMEM;
301 LG_memcpy(tmp,cs->stack,cs->size*sizeof(LGCursor*));
302 free(cs->stack);
303 cs->stack = tmp;
304 cs->size *= 2;
305 }
306 cs->stack[cs->fullness++] = c;
307 return OK;
308 }
309
310
uiPopCursor(uiCursorStack * cs)311 errtype uiPopCursor(uiCursorStack* cs)
312 {
313 if (cs == NULL) return ERR_NULL;
314 if (cs->fullness <= 1) return ERR_DUNDERFLOW;
315 cs->fullness--;
316 return OK;
317 }
318
uiGetTopCursor(uiCursorStack * cs,LGCursor ** c)319 errtype uiGetTopCursor(uiCursorStack* cs, LGCursor** c)
320 {
321 if (cs == NULL) return ERR_NULL;
322 if (cs->fullness <= 1)
323 return ERR_DUNDERFLOW;
324 *c = cs->stack[cs->fullness-1];
325 return OK;
326 }
327
328
uiPushCursorOnce(uiCursorStack * cs,LGCursor * c)329 errtype uiPushCursorOnce(uiCursorStack* cs, LGCursor* c)
330 {
331 LGCursor* top = NULL;
332 errtype err = uiGetTopCursor(cs,&top);
333 if (err == ERR_DUNDERFLOW) top = NULL;
334 else if (err != OK) return err;
335 if (top != c)
336 err = uiPushCursor(cs,c);
337 return err;
338 }
339
340 // I wish I had time to implement a non-boneheaded recursive version.
uiPopCursorEvery(uiCursorStack * cs,LGCursor * c)341 errtype uiPopCursorEvery(uiCursorStack* cs, LGCursor* c)
342 {
343 LGCursor* top = NULL;
344 errtype err = uiGetTopCursor(cs,&top);
345 if (err == ERR_DUNDERFLOW) return OK;
346 else if (err != OK) return err;
347 uiPopCursor(cs);
348 err = uiPopCursorEvery(cs,c);
349 if (top != c)
350 {
351 errtype newerr = uiPushCursor(cs,top);
352 if (newerr != OK) return newerr;
353 }
354 return err;
355 }
356
357
358 #define get_region_stack uiGetRegionCursorStack
359
get_region_stack(LGRegion * r,cursor_stack ** cs)360 errtype get_region_stack(LGRegion*r, cursor_stack** cs)
361 {
362 cursor_stack* res = (cursor_stack*)(r->cursors);
363 if (res == NULL)
364 {
365 errtype err;
366 //SPEW_ANAL(DSRC_UI_Cursor_Stack,("get_region_stack(%x,%x), creating stack\n",r,cs));
367 r->cursors = res = (cursor_stack *)malloc(sizeof(cursor_stack));
368 if (res == NULL)
369 return ERR_NOMEM;
370 err = cstack_init(res);
371 if (err != OK) return err;
372 }
373 *cs = res;
374 return OK;
375 }
376
377 // --------------------
378 // UI Toolkit internals
379 // --------------------
380
381
382 static int uiCursorCallbackId;
383
ui_init_cursor_stack(uiSlab * slab,LGCursor * default_cursor)384 errtype ui_init_cursor_stack(uiSlab* slab, LGCursor* default_cursor)
385 {
386 errtype err = cstack_init(&slab->cstack);
387 // Spew(DSRC_UI_Cursor_Stack,("ui_init_cursor_stack(%x,%x) err = %d\n",slab,default_cursor,err));
388 if (err != OK) return err;
389 slab->cstack.stack[0] = default_cursor;
390 return OK;
391 }
392
393 extern void cursor_draw_callback(ss_mouse_event* e, void* data);
394 extern void bitmap_cursor_drawfunc(int cmd, LGRegion* r, LGCursor* c, LGPoint pos);
395
ui_init_cursors(void)396 errtype ui_init_cursors(void)
397 {
398 errtype err;
399 // Spew(DSRC_UI_Cursors ,("ui_init_cursors()\n"));
400 grow_save_under(STARTING_SAVEUNDER_WD,STARTING_SAVEUNDER_HT);
401 // KLC - just initalize it to a sizeable bitmap, and leave it that way.
402 //SaveUnder.bm.bits = (uchar *)malloc(6144);
403 //SaveUnder.mapsize = 6144;
404
405 LastCursor = NULL;
406 MouseLock = 0;
407
408 gr_init_sub_canvas(grd_scr_canv,&DefaultCursorCanvas,0,0,grd_cap->w,grd_cap->h);
409 gr_cset_cliprect(&DefaultCursorCanvas,
410 0,0,grd_cap->w,grd_cap->h);
411 err = mouse_set_callback(cursor_draw_callback,NULL,&uiCursorCallbackId);
412 if (err != OK) return err;
413 HideRect = (LGRect *)malloc(sizeof(LGRect)*INITIAL_RECT_STACK);
414 HideRect[0].ul.x = -32768;
415 HideRect[0].ul.y = -32768;
416 HideRect[0].lr = HideRect[0].ul;
417 return OK;
418 }
419
uiUpdateScreenSize(LGPoint size)420 errtype uiUpdateScreenSize(LGPoint size)
421 {
422 short w = size.x;
423 short h = size.y;
424 if (size.x == UI_DETECT_SCREEN_SIZE.x)
425 w = grd_screen_canvas->bm.w;
426 if (size.y == UI_DETECT_SCREEN_SIZE.y)
427 h = grd_screen_canvas->bm.h;
428
429 gr_init_sub_canvas(grd_scr_canv,&DefaultCursorCanvas,0,0,w,h);
430 gr_cset_cliprect(&DefaultCursorCanvas,0,0,w,h);
431 // mouse_set_screensize(w,h);
432 // mouse_constrain_xy(0,0,w,h);
433 return(OK);
434 }
435
ui_shutdown_cursors(void)436 errtype ui_shutdown_cursors(void)
437 {
438 errtype err;
439 // Spew(DSRC_UI_Cursors,("ui_shutdown_cursors()\n"));
440 free(SaveUnder.bm.bits);
441 err = mouse_unset_callback(uiCursorCallbackId);
442 return err;
443 }
444
ui_set_current_cursor(LGPoint pos)445 uchar ui_set_current_cursor(LGPoint pos)
446 {
447 cstate s;
448 uchar result = FALSE;
449
450 ui_mouse_do_conversion(&(pos.x),&(pos.y),TRUE);
451 // Spew(DSRC_UI_Cursors,("ui_set_current_cursor(<%d,%d>)\n",pos.x,pos.y));
452 if (uiCurrentSlab == NULL)
453 {
454 //SPEW_ANAL(DSRC_UI_Cursors,("ui_set_current_cursor(): no current slab\n"));
455 result = FALSE;
456 goto out;
457 }
458 if (uiCurrentSlab->cstack.fullness > 1)
459 {
460 CurrentCursor = uiCurrentSlab->cstack.stack[uiCurrentSlab->cstack.fullness-1];
461 CursorRegion = (uiCurrentSlab->creg);
462 result = CurrentCursor != NULL;
463 goto out;
464 }
465 if (RootCursorRegion == NULL)
466 {
467 //SPEW_ANAL(DSRC_UI_Cursors,("ui_set_current_cursor(): no root region\n"));
468 result = FALSE;
469 goto out;
470 }
471 s.out = &CurrentCursor;
472 s.reg = &CursorRegion;
473
474 result = region_traverse_point(RootCursorRegion,pos,cursor_get_callback,TOP_TO_BOTTOM,&s);
475 out:
476 // Spew(DSRC_UI_Cursors,("ui_set_current_cursor(): current cursor = %x\n",CurrentCursor));
477 return result;
478 }
479
ui_update_cursor(LGPoint pos)480 void ui_update_cursor(LGPoint pos)
481 {
482 uchar show = ui_set_current_cursor(pos);
483 // ui_mouse_do_conversion(&(pos.x),&(pos.y),FALSE);
484 if (show && LastCursor != NULL && !PointsEqual(pos,LastCursorPos))
485 {
486 MouseLock++;
487 LastCursor->func(CURSOR_UNDRAW,LastCursorRegion,LastCursor,LastCursorPos);
488 LastCursorPos = pos;
489 LastCursorPos.x -= CurrentCursor->hotspot.x;
490 LastCursorPos.y -= CurrentCursor->hotspot.y;
491 CurrentCursor->func(CURSOR_DRAW,
492 CursorRegion,
493 CurrentCursor,
494 LastCursorPos);
495 LastCursor = CurrentCursor;
496 LastCursorRegion = CursorRegion;
497 MouseLock--;
498 }
499 }
500
501
502 // -------------
503 // API FUNCTIONS
504 // -------------
505
506
uiSetCursor(void)507 errtype uiSetCursor(void)
508 {
509 LGPoint pos;
510 uchar show = MouseLock == 0;
511 errtype retval = OK;
512 // Spew(DSRC_UI_Cursors,("uiSetCursor(), MouseLock = %d\n",MouseLock));
513 if (!ui_set_current_cursor(pos))
514 {
515 retval = ERR_NULL;
516 }
517 if (MouseLock > 0) // KLC - added to keep MouseLock from going negative.
518 MouseLock--;
519 if (show && CurrentCursor != LastCursor)
520 {
521 uiShowMouse(NULL);
522 }
523 return(retval);
524 }
525
uiSetRegionDefaultCursor(LGRegion * r,LGCursor * c)526 errtype uiSetRegionDefaultCursor(LGRegion* r, LGCursor* c)
527 {
528 cursor_stack* cs;
529 errtype err = get_region_stack(r,&cs);
530 // Spew(DSRC_UI_Cursor_Stack,("uiSetRegionDefaultCursor(%x,%x)\n",r,c));
531 if (err != OK) return err;
532 cs->stack[0] = c;
533 uiSetCursor();
534 return OK;
535 }
536
uiPushRegionCursor(LGRegion * r,LGCursor * c)537 errtype uiPushRegionCursor(LGRegion* r, LGCursor* c)
538 {
539 cursor_stack* cs;
540 errtype err = get_region_stack(r,&cs);
541 // Spew(DSRC_UI_Cursor_Stack,("uiPushRegionCursor(%x,%x)\n",r,c));
542 if (err != OK) return err;
543 err = cs_push(cs,c);
544 if (err != OK) return err;
545 return uiSetCursor();
546 }
547
548
uiPopRegionCursor(LGRegion * r)549 errtype uiPopRegionCursor(LGRegion* r)
550 {
551 cursor_stack *cs;
552 if (r == NULL) return ERR_NULL;
553 cs = (cursor_stack*)(r->cursors);
554 if (cs == NULL)
555 return ERR_DUNDERFLOW;
556 else
557 {
558 //Spew(DSRC_UI_Cursor_Stack,("uiPopRegionCursor(%x)\n",r));
559 if (cs->fullness <= 1) return ERR_DUNDERFLOW;
560 cs->fullness--;
561 uiSetCursor();
562 }
563 return OK;
564 }
565
uiGetRegionCursor(LGRegion * r,LGCursor ** c)566 errtype uiGetRegionCursor(LGRegion* r,LGCursor** c)
567 {
568 cursor_stack *cs;
569 if (r == NULL) return ERR_NULL;
570 cs = (cursor_stack*)(r->cursors);
571 if (cs == NULL)
572 {
573 *c = NULL;
574 }
575 else
576 {
577 //Spew(DSRC_UI_Cursor_Stack,("uiGetRegionCursor(%x,%x)\n",r,c));
578 *c = cs->stack[cs->fullness-1];
579 }
580 return OK;
581 }
582
583
uiShutdownRegionCursors(LGRegion * r)584 errtype uiShutdownRegionCursors(LGRegion* r)
585 {
586 cursor_stack* cs = (cursor_stack*)(r->cursors);
587 // Spew(DSRC_UI_Cursor_Stack,("uiShutdownRegionCursors(%x)\n",r));
588 if (cs == NULL) return ERR_NOEFFECT;
589 free(cs->stack);
590 free(cs);
591 r->cursors = NULL;
592 uiSetCursor();
593 return OK;
594 }
595
uiSetSlabDefaultCursor(uiSlab * slab,LGCursor * c)596 errtype uiSetSlabDefaultCursor(uiSlab* slab, LGCursor* c)
597 {
598 // Spew(DSRC_UI_Cursor_Stack,("uiSetSlabDefaultCursor(%x,%x)\n",slab,c));
599 if (slab == NULL) return ERR_NULL;
600 slab->cstack.stack[0] = c;
601 uiSetCursor();
602 return OK;
603 }
604
uiSetGlobalDefaultCursor(LGCursor * c)605 errtype uiSetGlobalDefaultCursor(LGCursor* c)
606 {
607 return uiSetSlabDefaultCursor(uiCurrentSlab,c);
608 }
609
uiPushSlabCursor(uiSlab * slab,LGCursor * c)610 errtype uiPushSlabCursor(uiSlab* slab, LGCursor* c)
611 {
612 errtype err;
613 // Spew(DSRC_UI_Cursor_Stack,("uiPushSlabCursor(%x,%x)\n",slab,c));
614 if (slab == NULL) return ERR_NULL;
615 err = cs_push(&slab->cstack,c);
616 uiSetCursor();
617 return err;
618 }
619
uiPushGlobalCursor(LGCursor * c)620 errtype uiPushGlobalCursor(LGCursor* c)
621 {
622 return uiPushSlabCursor(uiCurrentSlab,c);
623 }
624
uiPopSlabCursor(uiSlab * slab)625 errtype uiPopSlabCursor(uiSlab* slab)
626 {
627 // Spew(DSRC_UI_Cursor_Stack,("uiPopSlabCursor(%x)\n",slab));
628 if (slab == NULL) return ERR_NULL;
629 if (slab->cstack.fullness <= 1)
630 return ERR_DUNDERFLOW;
631 slab->cstack.fullness--;
632 uiSetCursor();
633 return OK;
634 }
635
uiPopGlobalCursor(void)636 errtype uiPopGlobalCursor(void)
637 {
638 return uiPopSlabCursor(uiCurrentSlab);
639 }
640
uiGetSlabCursor(uiSlab * slab,LGCursor ** c)641 errtype uiGetSlabCursor(uiSlab* slab, LGCursor** c)
642 {
643 // Spew(DSRC_UI_Cursor_Stack,("uiGetSlabCursor(%x,%x)\n",slab,c));
644 if (slab == NULL) return ERR_NULL;
645 *c = slab->cstack.stack[slab->cstack.fullness-1];
646 uiSetCursor();
647 return OK;
648 }
649
uiGetGlobalCursor(LGCursor ** c)650 errtype uiGetGlobalCursor(LGCursor** c)
651 {
652 return uiGetSlabCursor(uiCurrentSlab,c);
653 }
654
uiHideMouse(LGRect * r)655 errtype uiHideMouse(LGRect* r)
656 {
657 LGRect mr;
658 uchar hide = r == NULL || LastCursor == NULL;
659 MouseLock++; // hey, don't move the mouse while we're doing this.
660 if (!hide)
661 {
662 mr.ul = LastCursorPos;
663 ui_mouse_do_conversion(&(mr.ul.x),&(mr.ul.y),TRUE);
664 if (LastCursor != NULL)
665 {
666 mr.lr.x = LastCursorPos.x + LastCursor->w;
667 mr.lr.y = LastCursorPos.y + LastCursor->h;
668 ui_mouse_do_conversion(&mr.lr.x,&mr.lr.y,TRUE);
669 }
670 else mr.lr = mr.ul;
671 curhiderect++;
672 if (curhiderect >= numhiderects)
673 {
674 LGRect* tmp = HideRect;
675 HideRect = (LGRect *)malloc(numhiderects*2*sizeof(LGRect));
676 memcpy(HideRect,tmp,numhiderects*sizeof(LGRect));
677 numhiderects *= 2;
678 free(tmp);
679 }
680 if (curhiderect == 1) HideRect[curhiderect] = *r;
681 else RECT_UNION(&HideRect[curhiderect-1],r,&HideRect[curhiderect]);
682 hide = RECT_TEST_SECT(&HideRect[curhiderect],&mr);
683 }
684 // Undraw the mouse.
685 if (hide)
686 {
687 if (LastCursor != NULL)
688 {
689 LastCursor->func(CURSOR_UNDRAW,LastCursorRegion,LastCursor,LastCursorPos);
690 }
691 LastCursor = NULL;
692 }
693
694 //#define FREEZE_ON_HIDE
695 #ifndef FREEZE_ON_HIDE
696 else
697 {
698 MouseLock--;
699 return ERR_NOEFFECT;
700 }
701 #endif
702 return OK;
703 }
704
uiShowMouse(LGRect * r)705 errtype uiShowMouse(LGRect* r)
706 {
707 errtype ret;
708 LGRect mr;
709 uchar show = LastCursor == NULL || r == NULL;
710 MouseLock++;
711 if (!show)
712 {
713 mr.ul = LastCursorPos;
714 ui_mouse_do_conversion(&(mr.ul.x),&(mr.ul.y),TRUE);
715 if (LastCursor != NULL)
716 {
717 mr.lr.x = LastCursorPos.x + LastCursor->w;
718 mr.lr.y = LastCursorPos.y + LastCursor->h;
719 ui_mouse_do_conversion(&mr.lr.x,&mr.lr.y,TRUE);
720 }
721 else mr.lr = mr.ul;
722 show = RECT_TEST_SECT(r,&mr);
723 }
724 if (show)
725 {
726 if (MouseLock <= 2)
727 {
728 MouseLock = 2;
729 if (LastCursor != NULL)
730 {
731 LastCursor->func(CURSOR_UNDRAW,LastCursorRegion,LastCursor,LastCursorPos);
732 }
733 mouse_get_xy(&LastCursorPos.x,&LastCursorPos.y);
734 if (ui_set_current_cursor(LastCursorPos))
735 {
736 LastCursorPos.x -= CurrentCursor->hotspot.x;
737 LastCursorPos.y -= CurrentCursor->hotspot.y;
738 CurrentCursor->func(CURSOR_DRAW,
739 CursorRegion,
740 CurrentCursor,
741 LastCursorPos);
742 LastCursor = CurrentCursor;
743 LastCursorRegion = CursorRegion;
744 }
745 else LastCursor = NULL;
746 }
747 MouseLock--;
748 ret = OK;
749 }
750 #ifndef FREEZE_ON_HIDE
751 else
752 {
753 ret = ERR_NOEFFECT;
754 }
755 #else
756 else
757 {
758 if (MouseLock <= 2) MouseLock = 2;
759 MouseLock--;
760 }
761 #endif
762 if (--curhiderect < 0) curhiderect = 0;
763 MouseLock--;
764
765 // KLC - I have no idea what MouseLock is doing. I'll just set it to zero - shown - duh!
766 MouseLock = 0;
767
768 return ret;
769 }
770
uiMakeBitmapCursor(LGCursor * c,grs_bitmap * bm,LGPoint hotspot)771 errtype uiMakeBitmapCursor(LGCursor* c,grs_bitmap* bm, LGPoint hotspot)
772 {
773 // Spew(DSRC_UI_Cursors,("uiMakeBitmapCursor(%x,%x,<%d %d>)\n",c,bm,hotspot.x,hotspot.y));
774
775 if(c == NULL) {
776 printf("FIXME uiMakeBitmapCursor tried to make a null cursor!\n");
777 return ERR_NOEFFECT;
778 }
779
780 grow_save_under(bm->w,bm->h);
781 c->func = bitmap_cursor_drawfunc;
782 c->state = bm;
783 c->hotspot = hotspot;
784 c->w = bm->w;
785 c->h = bm->h;
786 return OK;
787 }
788