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