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/cit/src/RCS/wrapper.c $
21  * $Revision: 1.146 $
22  * $Author: dc $
23  * $Date: 1994/11/28 06:40:50 $
24  */
25 
26 #define __WRAPPER_SRC
27 
28 #include <limits.h>
29 
30 #include "wrapper.h"
31 #include "tools.h"
32 #include "invent.h"
33 #include "invpages.h"
34 #include "gamescr.h"
35 #include "mainloop.h"
36 #include "hkeyfunc.h"
37 #include "gamewrap.h"
38 #include "saveload.h"
39 #include "colors.h"
40 #include "cybstrng.h"
41 #include "status.h"
42 #include "fullscrn.h"
43 #include "render.h"
44 #include "gametime.h"
45 #include "musicai.h"
46 #include "input.h"
47 #include "gamestrn.h"
48 #include "miscqvar.h"
49 #include "cit2d.h"
50 #include "cybmem.h"
51 #include "citres.h"
52 #include "sfxlist.h"
53 #include "criterr.h"
54 #include "gr2ss.h"
55 #include "player.h"
56 #include "popups.h"
57 #include "olhext.h"
58 #include "Xmi.h"
59 #include "Prefs.h"
60 
61 #include "OpenGL.h"
62 
63 /*
64 #include <olhext.h>
65 #include <inp6d.h>
66 #include <i6dvideo.h>
67 #include <lgsndx.h>
68 #include <joystick.h>
69 #include <config.h>
70 */
71 
72 #ifdef AUDIOLOGS
73 #include "audiolog.h"
74 #endif
75 
76 #include "mfdart.h" // for the slider bar
77 
78 #include "MacTune.h"
79 
80 extern void text_button(char *text, int xc, int yc, int col, int shad, int w, int h);
81 
82 #define LOAD_BUTTON          0
83 #define SAVE_BUTTON          1
84 #define AUDIO_BUTTON         2
85 #define INPUT_BUTTON         3
86 #define OPTIONS_BUTTON       4
87 #define VIDEO_BUTTON         5
88 #define RETURN_BUTTON        6
89 #define QUIT_BUTTON          7
90 #define AUDIO_OPT_BUTTON     8
91 #define SCREENMODE_BUTTON    9
92 #define HEAD_RECENTER_BUTTON 10
93 #define HEADSET_BUTTON       11
94 
95 #define MOUSE_DOWN (MOUSE_LDOWN | MOUSE_RDOWN | UI_MOUSE_LDOUBLE)
96 #define MOUSE_UP   (MOUSE_LUP | MOUSE_RUP)
97 #define MOUSE_LEFT (MOUSE_LDOWN | UI_MOUSE_LDOUBLE)
98 #define MOUSE_WHEEL (MOUSE_WHEELUP | MOUSE_WHEELDN)
99 
100 #define STATUS_X      4
101 #define STATUS_Y      1
102 #define STATUS_HEIGHT 20
103 #define STATUS_WIDTH  312
104 
105 LGCursor option_cursor;
106 grs_bitmap option_cursor_bmap;
107 
108 extern LGRegion *inventory_region;
109 int wrap_id = -1, wrapper_wid, wrap_key_id;
110 uchar clear_panel = TRUE, wrapper_panel_on = FALSE;
111 grs_font *opt_font;
112 uchar olh_temp;
113 static bool digi_gain = true; // enable sfx volume slider
114 errtype (*wrapper_cb)(int num_clicked);
115 errtype (*slot_callback)(int num_clicked);
116 static uchar cursor_loaded = FALSE;
117 #if defined(VFX1_SUPPORT) || defined(CTM_SUPPORT)
118 uchar headset_track = TRUE;
119 #define HEADSET_FOV_MIN 30
120 #define HEADSET_FOV_MAX 180
121 // these 3 should all be initialized for real elsewhere...
122 int inp6d_real_fov = 60;
123 int hack_headset_fov = 30;
124 #endif
125 int inp6d_curr_fov = 60;
126 
127 errtype music_slots();
128 errtype wrapper_do_save();
129 extern errtype inventory_clear(void);
130 errtype wrapper_panel_close(uchar clear_message);
131 errtype do_savegame_guts(uchar slot);
132 void wrapper_start(void (*init)(void));
133 void quit_verify_pushbutton_handler(uchar butid);
134 uchar quit_verify_slorker(uchar butid);
135 void save_verify_pushbutton_handler(uchar butid);
136 uchar save_verify_slorker(uchar butid);
137 errtype make_options_cursor(void);
138 void free_options_cursor(void);
139 
140 void input_screen_init(void);
141 void joystick_screen_init(void);
142 void sound_screen_init(void);
143 void soundopt_screen_init(void);
144 void screenmode_screen_init(void);
145 void video_screen_init(void);
146 
147 uint multi_get_curval(uchar type, void *p);
148 void multi_set_curval(uchar type, void *p, uint val, void *deal);
149 
150 extern LGCursor slider_cursor;
151 extern grs_bitmap slider_cursor_bmap;
152 extern char which_lang;
153 
154 extern void mouse_unconstrain(void);
155 
156 void options_screen_init(void);
157 void wrapper_init(void);
158 void load_screen_init(void);
159 void save_screen_init(void);
160 
161 void draw_button(uchar butid);
162 
163 #define SLOTNAME_HEIGHT 6
164 #define PANEL_MARGIN_Y 3
165 #define WRAPPER_PANEL_HEIGHT (INVENTORY_PANEL_HEIGHT - 2 * PANEL_MARGIN_Y)
166 
167 #define OPTIONS_FONT RES_tinyTechFont
168 
169 errtype (*verify_callback)(int num_clicked) = NULL;
170 char savegame_verify;
171 char comments[NUM_SAVE_SLOTS + 1][SAVE_COMMENT_LEN];
172 uchar pause_game_func(ushort keycode, uint32_t context, intptr_t data);
173 uchar really_quit_key_func(ushort keycode, uint32_t context, intptr_t data);
174 
175 // separate mouse region for regular-screen and fullscreen.
176 #define NUM_MOUSEREGION_SCREENS 2
177 LGRegion options_mouseregion[NUM_MOUSEREGION_SCREENS];
178 uchar free_mouseregion = 0;
179 
180 char save_game_name[] = "savgam00.dat";
181 
182 extern grs_canvas *pinv_canvas;
183 extern grs_canvas inv_norm_canvas;
184 extern grs_canvas inv_fullscrn_canvas;
185 extern grs_canvas inv_view360_canvas;
186 
187 #define FULL_BACK_X (GAME_MESSAGE_X - INVENTORY_PANEL_X)
188 #define FULL_BACK_Y (GAME_MESSAGE_Y - INVENTORY_PANEL_Y)
189 
190 #define BUTTON_COLOR GREEN_BASE + 2
191 #define BUTTON_SHADOW 7
192 
193 // SLIDER WIDGETS:
194 // structure for slider widget.  The slider has a pointer to a uchar,
195 // ushort, or uint, which it sets to a value in the range [0,maxval].
196 // It recalculates this value based on interpolation from the actual
197 // size of the slider.  The function dealfunc (if not NULL) is called
198 // when the value changes, and is passed the new value.  The value is
199 // updated continuously if smooth==TRUE; otherwise it is updated upon
200 // mouse-up.
201 //
202 typedef struct {
203     uchar color;
204     uchar bvalcol;
205     uchar sliderpos;
206     uchar active;
207     Ref descrip;
208     uint maxval;
209     uchar baseval;
210     uchar type;
211     uchar smooth;
212     void *curval;
213     void *dealfunc;
214 } opt_slider_state;
215 
216 // PUSHBUTTON WIDGETS:
217 // the simplest widgets.  Calls pushfunc, passing in its own button ID,
218 // upon mouse left-click upon it, or on a keyboard event corresponding
219 // to keyeq.
220 //
221 typedef struct {
222     uchar keyeq;
223     Ref descrip;
224     uchar fcolor;
225     uchar shadow;
226     void (*pushfunc)(uchar butid);
227 } opt_pushbutton_state;
228 
229 // MULTI_STATE WIDGETS:
230 // these are much like pushbuttons, but also have a pointer to a uchar,
231 // ushort, or uint, which takes on a value in the range [0,num_opts-1].
232 // The button is labelled both with its description string (descrip) and
233 // with a string offset from optbase by an amount equal to the current
234 // value of its associated variable.  Whenever its value changes, it calls
235 // dealfunc, and message-lines a string offset from feedbackbase by an
236 // amount equal to its current value.
237 //
238 typedef struct {
239     uchar keyeq;
240     uchar type;
241     uchar num_opts;
242     Ref optbase;
243     Ref descrip;
244     Ref feedbackbase;
245     void *curval;
246     void *dealfunc;
247 } opt_multi_state;
248 
249 // TEXT WIDGET
250 // nothing but a piece of text, folks.  No handler, simple draw func.
251 //
252 typedef struct {
253     Ref descrip;
254     uchar color;
255 } opt_text_state;
256 
257 // TEXTLIST WIDGET
258 // used for editing and selecting (and responding to the editing and
259 // selecting of) a list of text strings.  You provide a block of text,
260 // which is assumed to be a 2-D array of chars (you inform the widget
261 // of the dimension of the subarrays).  The widget may either be edit-
262 // allowing or not.  If not, then it calls its dealfunc whenever a
263 // text string is selected (by mouse-clicking on it or by using the
264 // keyboard to move the highlight to it and hitting ENTER).  If the
265 // strings are editable, it calls its dealfunc only when you are done
266 // selecting and editing one.  A mask may be provided of what entries
267 // on the list are valid candidates for selection, and a string resource
268 // is given to display in the place of uninitialized selections.  Different
269 // colors are provided for selectable text, currently selected text,
270 // and non-selectable text.  Note that the user is responsible for
271 // providing space for one more line of text than the widget uses, for
272 // the purposes of saving string information.
273 //
274 typedef struct {
275     char *text;
276     uchar numblocks;
277     uchar blocksiz;
278 
279     char currstring;
280     char index;
281     uchar modified;
282 
283     uchar editable;
284     ushort editmask;
285     ushort selectmask;
286     ushort initmask;
287     Ref invalidstr;
288 
289     Ref selectprompt;
290 
291     uchar validcol;
292     uchar selectcol;
293     uchar invalidcol;
294 
295     void (*dealfunc)(uchar butid, uchar index);
296 } opt_textlist_state;
297 
298 // SLORKER WIDGET
299 // used to implement default actions in the keyboard interface to options
300 // screens, slorker widgets respond to no mouse events, but will respond
301 // to any keyboard events which actually reach them by calling their function
302 // with their button id as an argument.  Thus, any keypress which is not
303 // handled by another gadget is taken by the slorker.
304 //
305 typedef uchar (*slorker)(uchar butid);
306 
307 typedef struct {
308     LGRect rect;
309     union {
310         opt_slider_state     slider_st;
311         opt_pushbutton_state pushbutton_st;
312         opt_text_state       text_st;
313         opt_multi_state      multi_st;
314         opt_textlist_state   textlist_st;
315         slorker              sl;
316     } user;
317     ulong evmask;
318     void (*drawfunc)(uchar butid);
319     uchar (*handler)(uiEvent *ev, uchar butid);
320 } opt_button;
321 
322 void verify_screen_init(void (*verify)(uchar butid), slorker slork);
323 // void verify_screen_init(void (*verify)(uchar butid), void (*slork)(uchar butid));
324 
325 #define OPT_SLIDER_BAR REF_IMG_BeamSetting
326 
327 #define MAX_OPTION_BUTTONS 12
328 #define BR(i) (OButtons[i].rect)
329 
330 #ifdef STATIC_BUTTON_STORE
331 opt_button OButtons[MAX_OPTION_BUTTONS];
332 #else
333 extern grs_canvas _offscreen_mfd;
334 opt_button *OButtons;
335 uchar fv;
336 #endif
337 
338 #define OPTIONS_COLOR RED_BROWN_BASE + 4
339 
340 // Source Code for wrapper interface and functions
341 
342 #define STORE_CLIP(a, b, c, d) \
343     a = gr_get_clip_l();       \
344     b = gr_get_clip_t();       \
345     c = gr_get_clip_r();       \
346     d = gr_get_clip_b()
347 
348 // decides on a "standard" width for our widgets based on column count
349 // of current screen.  Our desire is that uniform widgets of this size
350 // should have certain margins between them independent of column count.
351 #define CONSTANT_MARGINS
352 
353 #ifdef HALF_BUTTON_MARGINS
354 #define widget_width(t, m) (2 * INVENTORY_PANEL_WIDTH / (3 * (t) + 1))
355 #define widget_x(c, t, m)  ((3 * (t) + 1) * INVENTORY_PANEL_WIDTH / (3 * (t) + 1))
356 #endif
357 #ifdef CONSTANT_MARGINS
358 #define widget_width(t, m) ((INVENTORY_PANEL_WIDTH - ((m) * ((t) + 1))) / (t))
359 #define widget_x(c, t, m)  ((m) * ((c) + 1) + widget_width(t, m) * (c))
360 #endif
361 
362 // override get_temp_string() to support hard-coded custom strings without
363 // providing an actual resource file
364 
365 #define MIDI_OUT_STR_SIZE 1024
366 static char MIDI_STR_BUFFER[MIDI_OUT_STR_SIZE];
367 
_get_temp_string(int num)368 static char *_get_temp_string(int num) {
369     switch (num) {
370         case REF_STR_Renderer: return "Renderer";
371         case REF_STR_Software: return "Software";
372         case REF_STR_OpenGL:   return "OpenGL";
373 
374         case REF_STR_TextFilt: return "Tex Filter";
375         case REF_STR_TFUnfil:  return "Unfiltered";
376         case REF_STR_TFBilin:  return "Bilinear";
377 
378         case REF_STR_MousLook: return "Mouselook";
379         case REF_STR_MousNorm: return "Normal";
380         case REF_STR_MousInv:  return "Inverted";
381 
382         case REF_STR_Seqer:    return "Midi Player";
383         case REF_STR_ADLMIDI:  return "ADLMIDI";
384         case REF_STR_NativeMI: return "Native MIDI";
385 #ifdef USE_FLUIDSYNTH
386         case REF_STR_FluidSyn: return "FluidSynth";
387 #endif
388 
389         case REF_STR_MidiOut:  return "Midi Output";
390     }
391 
392     if (num >= REF_STR_MidiOutX && num <= (REF_STR_MidiOutX | 0x0fffffff))
393     {
394         const unsigned int midiOutputIndex = (unsigned int)num - REF_STR_MidiOutX;
395         MIDI_STR_BUFFER[0] = '\0';
396         GetOutputNameXMI(midiOutputIndex, &MIDI_STR_BUFFER[0], MIDI_OUT_STR_SIZE);
397         return &MIDI_STR_BUFFER[0];
398     }
399 
400     return get_temp_string(num);
401 }
402 
403 #define get_temp_string _get_temp_string
404 
405 //#ifdef NOT_YET //
406 
draw_button(uchar butid)407 void draw_button(uchar butid) {
408     if (OButtons[butid].drawfunc) {
409 #ifdef SVGA_SUPPORT
410         uchar old_over;
411         old_over = gr2ss_override;
412         gr2ss_override = OVERRIDE_ALL;
413 #endif
414         uiHideMouse(NULL);
415         gr_push_canvas(&inv_norm_canvas);
416         gr_set_font(opt_font);
417         OButtons[butid].drawfunc(butid);
418         gr_pop_canvas();
419         uiShowMouse(NULL);
420 #ifdef GR2SS_OVERRIDE
421         gr2ss_override = old_over;
422 #endif
423     }
424 }
425 
wrapper_draw_background(short ulx,short uly,short lrx,short lry)426 void wrapper_draw_background(short ulx, short uly, short lrx, short lry) {
427     short cx1, cx2, cy1, cy2;
428     extern grs_bitmap inv_backgnd;
429     short a1, a2, a3, a4;
430 
431 #ifdef SVGA_SUPPORT
432     uchar old_over;
433     old_over = gr2ss_override;
434     gr2ss_override = OVERRIDE_ALL;
435 #endif
436     // draw background behind the slider.
437     STORE_CLIP(cx1, cy1, cx2, cy2);
438     ss_safe_set_cliprect(ulx, uly, lrx, lry);
439     if (full_game_3d) {
440         //      gr_bitmap(&inv_view360_canvas.bm,FULL_BACK_X,FULL_BACK_Y);
441         gr_get_cliprect(&a1, &a2, &a3, &a4);
442         ss_noscale_bitmap(&inv_view360_canvas.bm, FULL_BACK_X, FULL_BACK_Y);
443     } else
444         ss_bitmap(&inv_backgnd, 0, 0);
445     RESTORE_CLIP(cx1, cy1, cx2, cy2);
446 #ifdef SVGA_SUPPORT
447     gr2ss_override = old_over;
448 #endif
449 }
450 
slider_draw_func(uchar butid)451 void slider_draw_func(uchar butid) {
452     opt_slider_state *st = &(OButtons[butid].user.slider_st);
453     short w, h, sw;
454     char *title;
455 
456 #ifdef SVGA_SUPPORT
457     uchar old_over;
458     old_over = gr2ss_override;
459     gr2ss_override = OVERRIDE_ALL;
460 #endif
461 
462     sw = res_bm_width(OPT_SLIDER_BAR);
463     gr_set_fcolor(st->color);
464     title = get_temp_string(st->descrip);
465     gr_string_size(title, &w, &h);
466 
467     // draw background behind the slider
468     wrapper_draw_background(BR(butid).ul.x - sw / 2, BR(butid).ul.y - h, BR(butid).lr.x + sw / 2, BR(butid).lr.y);
469     draw_shadowed_string(title, BR(butid).ul.x, BR(butid).ul.y - h, full_game_3d);
470 
471     gr_set_fcolor(st->bvalcol);
472     ss_vline(BR(butid).ul.x + st->baseval, BR(butid).ul.y, BR(butid).lr.y - 1);
473 
474     gr_set_fcolor(st->color);
475     ss_box(BR(butid).ul.x, BR(butid).ul.y, BR(butid).lr.x, BR(butid).lr.y);
476 
477     if (!(st->active))
478         draw_raw_resource_bm(OPT_SLIDER_BAR, BR(butid).ul.x + st->sliderpos + 1 - sw / 2, BR(butid).ul.y);
479 
480 #ifdef SVGA_SUPPORT
481     gr2ss_override = old_over;
482 #endif
483 }
484 
slider_deal(uchar butid,uchar deal)485 void slider_deal(uchar butid, uchar deal) {
486     opt_slider_state *st = &(OButtons[butid].user.slider_st);
487     uint val;
488 
489     deal = deal || st->smooth;
490 
491     val = (st->sliderpos * (st->maxval + 1)) / (BR(butid).lr.x - BR(butid).ul.x - 3);
492     if (val > st->maxval) val = st->maxval;
493 
494     multi_set_curval(st->type, st->curval, val, deal ? st->dealfunc : NULL);
495 }
496 
497 //
498 // every time you find yourself,
499 // you lose a little bit of me, from within
500 //
501 
slider_handler(uiEvent * ev,uchar butid)502 uchar slider_handler(uiEvent *ev, uchar butid) {
503     opt_slider_state *st = &(OButtons[butid].user.slider_st);
504 
505     switch (ev->type) {
506     case UI_EVENT_MOUSE_MOVE:
507         if (ev->mouse_data.buttons) {
508             st->sliderpos = ev->pos.x - BR(butid).ul.x;
509             slider_deal(butid, TRUE);
510             draw_button(butid);
511         }
512         break;
513     case UI_EVENT_MOUSE:
514         if (ev->mouse_data.action & MOUSE_WHEELUP) {
515             st->sliderpos = st->sliderpos <= 5 ? 0 : st->sliderpos - 5;
516         } else if (ev->mouse_data.action & MOUSE_WHEELDN) {
517             uchar max = BR(butid).lr.x - BR(butid).ul.x - 3;
518             st->sliderpos = lg_min(st->sliderpos + 5, max);
519         } else {
520             st->sliderpos = ev->pos.x - BR(butid).ul.x;
521         }
522         slider_deal(butid, TRUE);
523         draw_button(butid);
524         return TRUE;
525     default:
526         break;
527     }
528     return FALSE;
529 }
530 
slider_init(uchar butid,Ref descrip,uchar type,uchar smooth,void * var,uint maxval,uchar baseval,void * dealfunc,LGRect * r)531 void slider_init(uchar butid, Ref descrip, uchar type, uchar smooth, void *var, uint maxval, uchar baseval,
532                  void *dealfunc, LGRect *r) {
533     opt_slider_state *st = &OButtons[butid].user.slider_st;
534     uint val;
535 
536     if (maxval)
537     {
538         val = ((r->lr.x - r->ul.x - 3) * multi_get_curval(type, var)) / maxval;
539     }
540     else
541     {
542         // just put it in the middle
543         val = (r->lr.x - r->ul.x - 3) / 2;
544     }
545 
546     st->color = BUTTON_COLOR;
547     st->bvalcol = GREEN_YELLOW_BASE + 1;
548     st->sliderpos = val;
549     st->baseval = baseval;
550     st->maxval = maxval;
551     st->active = FALSE;
552     st->descrip = descrip;
553     st->type = type;
554     // note that in these settings, we don't care what size of
555     // variable we're dealing with, 'cause we secretly know that
556     // all pointers are represented the same and we don't
557     // have to actually dereference these.
558     st->dealfunc = dealfunc;
559     st->curval = var;
560     st->smooth = smooth;
561 
562     OButtons[butid].evmask = UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE;
563     OButtons[butid].drawfunc = slider_draw_func;
564     OButtons[butid].handler = slider_handler;
565     OButtons[butid].rect = *r;
566 }
567 
pushbutton_draw_func(uchar butid)568 void pushbutton_draw_func(uchar butid) {
569     char *btext;
570     short w, h;
571     opt_pushbutton_state *st = &OButtons[butid].user.pushbutton_st;
572 
573     w = BR(butid).lr.x - BR(butid).ul.x;
574     h = BR(butid).lr.y - BR(butid).ul.y;
575 
576     btext = get_temp_string(st->descrip);
577     gr_string_wrap(btext, BR(butid).lr.x - BR(butid).ul.x - 3);
578     text_button(btext, BR(butid).ul.x, BR(butid).ul.y, st->fcolor, st->shadow, -w, -h);
579     gr_font_string_unwrap(btext);
580 }
581 
pushbutton_handler(uiEvent * ev,uchar butid)582 uchar pushbutton_handler(uiEvent *ev, uchar butid) {
583     if (((ev->type == UI_EVENT_MOUSE) && (ev->subtype & MOUSE_DOWN)) ||
584         ((ev->type == UI_EVENT_KBD_COOKED) &&
585          ((ev->cooked_key_data.code & 0xFF) == OButtons[butid].user.pushbutton_st.keyeq))) {
586         OButtons[butid].user.pushbutton_st.pushfunc(butid);
587         return TRUE;
588     }
589     return FALSE;
590 }
591 
pushbutton_init(uchar butid,uchar keyeq,Ref descrip,void (* pushfunc)(uchar butid),LGRect * r)592 void pushbutton_init(uchar butid, uchar keyeq, Ref descrip, void (*pushfunc)(uchar butid), LGRect *r) {
593     opt_pushbutton_state *st = &OButtons[butid].user.pushbutton_st;
594 
595     OButtons[butid].rect = *r;
596     OButtons[butid].evmask = UI_EVENT_MOUSE | UI_EVENT_KBD_COOKED;
597     OButtons[butid].drawfunc = pushbutton_draw_func;
598     OButtons[butid].handler = pushbutton_handler;
599     st->fcolor = BUTTON_COLOR;
600     st->shadow = BUTTON_SHADOW;
601     st->keyeq = keyeq;
602     st->descrip = descrip;
603     st->pushfunc = pushfunc;
604 }
605 
dim_pushbutton(uchar butid)606 void dim_pushbutton(uchar butid) {
607     opt_pushbutton_state *st = &OButtons[butid].user.pushbutton_st;
608     OButtons[butid].evmask = 0;
609     st->fcolor += 4;
610     st->shadow -= 3;
611 }
612 
bright_pushbutton(uchar butid)613 void bright_pushbutton(uchar butid) {
614     opt_pushbutton_state *st = &OButtons[butid].user.pushbutton_st;
615     OButtons[butid].evmask = 0;
616     st->fcolor -= 2;
617     st->shadow += 2;
618 }
619 
620 // text widget
text_draw_func(uchar butid)621 void text_draw_func(uchar butid) {
622     opt_text_state *st = &OButtons[butid].user.text_st;
623     char *s = get_temp_string(st->descrip);
624 
625     gr_string_wrap(s, BR(butid).lr.x - BR(butid).ul.x);
626     gr_set_fcolor(st->color);
627     draw_shadowed_string(s, BR(butid).ul.x, BR(butid).ul.y, full_game_3d);
628     gr_font_string_unwrap(s);
629 }
630 
textwidget_init(uchar butid,uchar color,Ref descrip,LGRect * r)631 void textwidget_init(uchar butid, uchar color, Ref descrip, LGRect *r) {
632     opt_text_state *st = &OButtons[butid].user.text_st;
633 
634     OButtons[butid].rect = *r;
635     st->descrip = descrip;
636     st->color = color;
637     OButtons[butid].drawfunc = text_draw_func;
638     OButtons[butid].handler = NULL;
639     OButtons[butid].evmask = 0;
640 }
641 
642 // a keywidget is just like a pushbutton, but invisible.
643 //
keywidget_init(uchar butid,uchar keyeq,void (* pushfunc)(uchar butid))644 void keywidget_init(uchar butid, uchar keyeq, void (*pushfunc)(uchar butid)) {
645     opt_pushbutton_state *st = &OButtons[butid].user.pushbutton_st;
646 
647     OButtons[butid].evmask = UI_EVENT_KBD_COOKED;
648     OButtons[butid].drawfunc = NULL;
649     OButtons[butid].handler = pushbutton_handler;
650     st->keyeq = keyeq;
651     st->pushfunc = pushfunc;
652 }
653 
654 // gets the current "value" of a multi-option widget, whatever size
655 // thing that may be.
multi_get_curval(uchar type,void * p)656 uint multi_get_curval(uchar type, void *p) {
657     uint val = 0;
658 
659     switch (type) {
660     case sizeof(uchar):
661         val = *((uchar *)p);
662         break;
663     case sizeof(ushort):
664         val = *((ushort *)p);
665         break;
666     case sizeof(uint):
667         val = *((uint *)p);
668         break;
669     }
670     return val;
671 }
672 
673 // sets the current value pointed to by a multi-option widget.
multi_set_curval(uchar type,void * p,uint val,void * deal)674 void multi_set_curval(uchar type, void *p, uint val, void *deal) {
675     switch (type) {
676     case sizeof(uchar):
677         *((uchar *)p) = (uchar)val;
678         if (deal)
679             ((void (*)(uchar))deal)((uchar)val);
680         break;
681     case sizeof(ushort):
682         *((ushort *)p) = (ushort)val;
683         if (deal)
684             ((void (*)(ushort))deal)((ushort)val);
685         break;
686     case sizeof(uint):
687         *((uint *)p) = (uint)val;
688         if (deal)
689             ((void (*)(uint))deal)((uint)val);
690         break;
691     }
692 }
693 
multi_draw_func(uchar butid)694 void multi_draw_func(uchar butid) {
695     char *btext;
696     short w, h, x, y;
697     uint val = 0;
698     opt_multi_state *st = &OButtons[butid].user.multi_st;
699 
700     gr_set_fcolor(BUTTON_COLOR);
701     ss_rect(BR(butid).ul.x, BR(butid).ul.y, BR(butid).lr.x, BR(butid).lr.y);
702     gr_set_fcolor(BUTTON_COLOR + BUTTON_SHADOW);
703     ss_rect(BR(butid).ul.x + 1, BR(butid).ul.y + 1, BR(butid).lr.x - 1, BR(butid).lr.y - 1);
704     gr_set_fcolor(BUTTON_COLOR);
705     x = (BR(butid).lr.x + BR(butid).ul.x) / 2;
706     y = (BR(butid).lr.y + BR(butid).ul.y) / 2;
707     btext = get_temp_string(st->descrip);
708     gr_string_size(btext, &w, &h);
709     ss_string(btext, x - w / 2, y - h);
710     val = multi_get_curval(st->type, st->curval);
711     btext = get_temp_string(st->optbase + val);
712     gr_string_size(btext, &w, &h);
713     ss_string(btext, x - w / 2, y);
714 }
715 
multi_handler(uiEvent * ev,uchar butid)716 uchar multi_handler(uiEvent *ev, uchar butid) {
717     uint val = 0, delta = 0;
718     opt_multi_state *st = &OButtons[butid].user.multi_st;
719 
720     if (ev->type == UI_EVENT_MOUSE) {
721         if (ev->subtype & MOUSE_LEFT)
722             delta = 1;
723         else if (ev->subtype & MOUSE_RDOWN)
724             delta = st->num_opts - 1;
725     } else if (ev->type == UI_EVENT_KBD_COOKED) {
726 	short code = ev->cooked_key_data.code;
727         if (tolower(code & 0xFF) == st->keyeq) {
728             if (isupper(code & 0xFF))
729                 delta = st->num_opts - 1;
730             else
731                 delta = 1;
732         }
733     }
734 
735     if (delta) {
736         val = multi_get_curval(st->type, st->curval);
737         val = (val + delta) % (st->num_opts);
738         multi_set_curval(st->type, st->curval, val, st->dealfunc);
739         draw_button(butid);
740         if (st->feedbackbase) {
741             string_message_info(st->feedbackbase + val);
742         }
743         return TRUE;
744     }
745     return FALSE;
746 }
747 
multi_init(uchar butid,uchar key,Ref descrip,Ref optbase,Ref feedbase,uchar type,void * var,uchar num_opts,void * dealfunc,LGRect * r)748 void multi_init(uchar butid, uchar key, Ref descrip, Ref optbase, Ref feedbase, uchar type, void *var, uchar num_opts,
749                 void *dealfunc, LGRect *r) {
750     opt_multi_state *st = &OButtons[butid].user.multi_st;
751 
752     OButtons[butid].rect = *r;
753     OButtons[butid].drawfunc = multi_draw_func;
754     OButtons[butid].handler = multi_handler;
755     OButtons[butid].evmask = UI_EVENT_MOUSE | UI_EVENT_KBD_COOKED;
756     st->descrip = descrip;
757     st->optbase = optbase;
758     st->feedbackbase = feedbase;
759     st->type = type;
760     st->keyeq = key;
761     st->num_opts = num_opts;
762     // note that in these settings, we don't care what size of
763     // variable we're dealing with, 'cause we secretly know that
764     // all pointers are represented the same and we don't
765     // have to actually dereference these.
766     st->dealfunc = dealfunc;
767     st->curval = var;
768 }
769 
770 #pragma disable_message(202)
keyslork_handler(uiEvent * ev,uchar butid)771 uchar keyslork_handler(uiEvent *ev, uchar butid) {
772     slorker *slork = &OButtons[butid].user.sl;
773 
774     return ((*slork)(butid));
775 }
776 #pragma enable_message(202)
777 
slork_init(uchar butid,slorker slork)778 void slork_init(uchar butid, slorker slork) {
779     LG_memset(&OButtons[butid].rect, 0, sizeof(LGRect));
780     OButtons[butid].user.sl = slork;
781     OButtons[butid].evmask = UI_EVENT_KBD_COOKED;
782     OButtons[butid].drawfunc = NULL;
783     OButtons[butid].handler = keyslork_handler;
784 }
785 
textlist_string(opt_textlist_state * st,int ind)786 char *textlist_string(opt_textlist_state *st, int ind) { return (st->text + ind * (st->blocksiz)); }
787 
textlist_draw_line(opt_textlist_state * st,int line,uchar butid)788 void textlist_draw_line(opt_textlist_state *st, int line, uchar butid) {
789     short w, h;
790     LGRect scrrect;
791     LGRect r;
792     char *s;
793     uchar col;
794 #ifdef SVGA_SUPPORT
795     uchar old_over;
796 #endif
797 
798     scrrect = BR(butid);
799     scrrect.ul.x += INVENTORY_PANEL_X;
800     scrrect.ul.y += INVENTORY_PANEL_Y;
801     scrrect.lr.x += INVENTORY_PANEL_X;
802     scrrect.lr.y += INVENTORY_PANEL_Y;
803 
804     if (((1 << line) & (st->initmask)) || (line == st->currstring && st->index >= 0))
805         s = textlist_string(st, line);
806     else
807         s = get_temp_string(st->invalidstr);
808 
809     if (line == st->currstring)
810         col = st->selectcol;
811     else if (st->selectmask & (1 << line))
812         col = st->validcol;
813     else
814         col = st->invalidcol;
815     gr_push_canvas(&inv_norm_canvas);
816     gr_set_fcolor(col);
817 
818     gr_set_font(opt_font);
819     gr_string_size(s, &w, &h);
820     r.ul.x = BR(butid).ul.x;
821     r.ul.y = BR(butid).ul.y + h * line;
822     r.lr.x = BR(butid).lr.x;
823     r.lr.y = r.ul.y + h;
824 
825     uiHideMouse(&scrrect);
826 #ifdef SVGA_SUPPORT
827     old_over = gr2ss_override;
828     gr2ss_override = OVERRIDE_ALL;
829 #endif
830     wrapper_draw_background(r.ul.x, r.ul.y, r.lr.x, r.lr.y);
831     draw_shadowed_string(s, r.ul.x, r.ul.y, full_game_3d);
832 #ifdef SVGA_SUPPORT
833     gr2ss_override = old_over;
834 #endif
835     uiShowMouse(&scrrect);
836     gr_pop_canvas();
837 }
838 
textlist_draw_func(uchar butid)839 void textlist_draw_func(uchar butid) {
840     int i;
841     opt_textlist_state *st = &OButtons[butid].user.textlist_st;
842 
843     for (i = 0; i < st->numblocks; i++) {
844         textlist_draw_line(st, i, butid);
845     }
846 }
847 
textlist_cleanup(opt_textlist_state * st)848 void textlist_cleanup(opt_textlist_state *st) {
849     if (st->editable && st->currstring >= 0 && st->index >= 0) {
850         strcpy(textlist_string(st, st->currstring), textlist_string(st, st->numblocks));
851         st->index = -1;
852     }
853 }
854 
855 #ifdef WE_USED_THIS
textlist_edit_line(opt_textlist_state * st,uchar butid,uchar line,uchar end)856 void textlist_edit_line(opt_textlist_state *st, uchar butid, uchar line, uchar end) {
857     char *s, *bak;
858     char tmp;
859 
860     gr_push_canvas(&inv_norm_canvas);
861     s = textlist_string(st, line);
862     bak = textlist_string(st, st->numblocks);
863     tmp = st->currstring;
864     st->currstring = line;
865     if (tmp >= 0) {
866         strcpy(textlist_string(st, tmp), bak);
867         textlist_draw_line(st, tmp, butid);
868     }
869     strcpy(bak, s);
870     st->index = end ? strlen(s) : 0;
871     s[0] = '\0';
872     textlist_draw_line(st, line, butid);
873     gr_pop_canvas();
874 }
875 #endif
876 
textlist_select_line(opt_textlist_state * st,uchar butid,uchar line,uchar deal)877 void textlist_select_line(opt_textlist_state *st, uchar butid, uchar line, uchar deal) {
878     char tmp;
879 
880     gr_push_canvas(&inv_norm_canvas);
881     tmp = st->currstring;
882     st->currstring = line;
883     st->index = -1;
884     if (tmp >= 0)
885         textlist_draw_line(st, tmp, butid);
886     textlist_draw_line(st, line, butid);
887     gr_pop_canvas();
888     if (deal)
889         st->dealfunc(butid, line);
890 }
891 
textlist_handler(uiEvent * ev,uchar butid)892 uchar textlist_handler(uiEvent *ev, uchar butid) {
893     uchar line;
894     opt_textlist_state *st = &OButtons[butid].user.textlist_st;
895 
896     if ((ev->type == UI_EVENT_MOUSE) && (ev->subtype & MOUSE_DOWN)) {
897         short w, h;
898 
899         gr_set_font(opt_font);
900         gr_char_size('X', &w, &h);
901 
902         line = (ev->pos.y - BR(butid).ul.y) / h;
903 
904         if (st->editable && (st->editmask & (1 << line))) {
905             // this is how you would do this if you wanted right-click to select
906             // a line w/ confirm, which would be the right thing to do, instead
907             // of confirm without selection, which is what Harvey at Origin wants.
908             //
909             //          if(st->selectprompt)
910             //             textlist_select_line(st,butid,line,FALSE);
911             //          textlist_select_line(st,butid,line,(ev->subtype&MOUSE_RDOWN)!=0);
912             //
913             if (ev->subtype & MOUSE_RDOWN) {
914                 if (st->currstring >= 0)
915                     st->dealfunc(butid, st->currstring);
916             } else if (!st->modified) {
917                 string_message_info(st->selectprompt);
918                 if (st->selectprompt)
919                     textlist_select_line(st, butid, line, FALSE);
920             }
921         } else if (st->selectmask & (1 << line)) {
922             textlist_select_line(st, butid, line, TRUE);
923         }
924         return TRUE;
925     } else if (ev->type == UI_EVENT_KBD_COOKED) {
926 	short code = ev->cooked_key_data.code;
927         char k = code & 0xFF;
928         uint keycode = code & ~KB_FLAG_DOWN;
929         uchar special = ((code & KB_FLAG_SPECIAL) != 0);
930         char *s;
931         char upness = 0;
932         char cur = st->currstring;
933 
934         // explicitly do not deal with alt-x, but leave
935         // it to more capable hands.
936         if (keycode == (KB_FLAG_ALT | 'x'))
937             return FALSE;
938         if (cur >= 0)
939             s = textlist_string(st, cur);
940         if (st->editable && cur >= 0 && !special && kb_isprint(keycode)) {
941             if (st->index < 0) {
942                 strcpy(textlist_string(st, st->numblocks), textlist_string(st, st->currstring));
943                 st->index = 0;
944             }
945             if (st->index + 1 < st->blocksiz) {
946                 s[st->index] = k;
947                 st->index++;
948                 s[st->index] = '\0';
949                 textlist_draw_line(st, cur, butid);
950             }
951             st->modified = TRUE;
952             return TRUE;
953         }
954         switch (keycode) {
955         case KEY_BS:
956             if (st->editable && cur >= 0) {
957                 if (st->index < 0) {
958                     strcpy(textlist_string(st, st->numblocks), textlist_string(st, st->currstring));
959                     st->index = strlen(s);
960                 }
961                 if (st->index > 0)
962                     st->index--;
963                 s[st->index] = '\0';
964                 textlist_draw_line(st, cur, butid);
965             }
966             break;
967         case KEY_UP:
968             upness = st->numblocks - 1;
969             break;
970         case KEY_DOWN:
971             upness = 1;
972             break;
973         case KEY_ENTER:
974             if (st->currstring >= 0) {
975                 st->dealfunc(butid, cur);
976                 return TRUE;
977             }
978             break;
979         case KEY_ESC:
980             // on ESC, clean up but pass the event through.
981             textlist_cleanup(st);
982             wrapper_panel_close(TRUE);
983             return FALSE;
984         }
985         if (upness != 0) {
986             char newstring;
987             uchar safety = 0;
988 
989             newstring = cur;
990             if (newstring < 0)
991                 newstring = (upness == 1) ? st->numblocks - 1 : 0;
992             do {
993                 newstring = (newstring + upness) % st->numblocks;
994                 safety++;
995             } while (safety < st->numblocks && !((1 << newstring) & st->selectmask));
996             if (safety >= st->numblocks)
997                 newstring = cur;
998             if (newstring != cur) {
999                 textlist_cleanup(st);
1000                 st->currstring = newstring;
1001                 if (cur >= 0 && cur < st->numblocks)
1002                     textlist_draw_line(st, cur, butid);
1003                 textlist_draw_line(st, newstring, butid);
1004             }
1005         }
1006         return TRUE;
1007     }
1008     return TRUE;
1009 }
1010 
textlist_init(uchar butid,char * text,uchar numblocks,uchar blocksiz,uchar editable,ushort editmask,ushort selectmask,ushort initmask,Ref invalidstr,uchar validcol,uchar selectcol,uchar invalidcol,Ref selectprompt,void (* dealfunc)(uchar butid,uchar index),LGRect * r)1011 void textlist_init(uchar butid, char *text, uchar numblocks, uchar blocksiz, uchar editable, ushort editmask,
1012                    ushort selectmask, ushort initmask, Ref invalidstr, uchar validcol, uchar selectcol,
1013                    uchar invalidcol, Ref selectprompt, void (*dealfunc)(uchar butid, uchar index), LGRect *r) {
1014     opt_textlist_state *st = &OButtons[butid].user.textlist_st;
1015 
1016     if (r == NULL) {
1017         BR(butid).ul.x = 2;
1018         BR(butid).ul.y = 2;
1019         BR(butid).lr.x = INVENTORY_PANEL_WIDTH;
1020         BR(butid).lr.y = INVENTORY_PANEL_HEIGHT;
1021     } else
1022         OButtons[butid].rect = *r;
1023     OButtons[butid].drawfunc = textlist_draw_func;
1024     OButtons[butid].handler = textlist_handler;
1025     OButtons[butid].evmask = UI_EVENT_MOUSE | UI_EVENT_KBD_COOKED;
1026     st->text = text;
1027     st->numblocks = numblocks;
1028     st->blocksiz = blocksiz;
1029     st->editable = editable;
1030     st->editmask = editmask;
1031     st->selectmask = selectmask;
1032     st->initmask = initmask;
1033     st->invalidstr = invalidstr;
1034     st->validcol = validcol;
1035     st->selectcol = selectcol;
1036     st->invalidcol = invalidcol;
1037     st->dealfunc = dealfunc;
1038     st->selectprompt = selectprompt;
1039 
1040     st->currstring = -1;
1041     st->index = -1;
1042     st->modified = FALSE;
1043 }
1044 
1045 // One, true mouse handler for all options panel mouse events.
1046 // checks all options panel widgets which enclose point of mouse
1047 // event to see if they want to deal with it.
1048 //
1049 #pragma disable_message(202)
opanel_mouse_handler(uiEvent * ev,LGRegion * r,intptr_t user_data)1050 uchar opanel_mouse_handler(uiEvent *ev, LGRegion *r, intptr_t user_data) {
1051     int b;
1052     uiEvent mev = *ev;
1053 
1054     if (!(ev->type & (UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE)))
1055         return FALSE;
1056     if (ev->type == UI_EVENT_MOUSE && !(ev->subtype & (MOUSE_DOWN | MOUSE_UP | MOUSE_WHEEL)))
1057         return FALSE;
1058 
1059     mev.pos.x -= inventory_region->r->ul.x;
1060     mev.pos.y -= inventory_region->r->ul.y;
1061 
1062     for (b = 0; b < MAX_OPTION_BUTTONS; b++) {
1063         if (RECT_TEST_PT(&BR(b), mev.pos) && (ev->type & OButtons[b].evmask)) {
1064             if (OButtons[b].handler && OButtons[b].handler((uiEvent *)(&mev), b))
1065                 return TRUE;
1066         }
1067     }
1068     return TRUE;
1069 }
1070 
1071 // One, true keyboard handler for all options mode events.
1072 // checks all options panel widgets to see if they want to deal.
1073 //
opanel_kb_handler(uiEvent * ev,LGRegion * r,intptr_t user_data)1074 uchar opanel_kb_handler(uiEvent *ev, LGRegion *r, intptr_t user_data) {
1075     int b;
1076     short code = ev->cooked_key_data.code;
1077 
1078     if (!(code & KB_FLAG_DOWN))
1079         return TRUE;
1080 
1081     for (b = 0; b < MAX_OPTION_BUTTONS; b++) {
1082         if ((ev->type & OButtons[b].evmask) && OButtons[b].handler && OButtons[b].handler(ev, b))
1083             return TRUE;
1084     }
1085     // if no-one else has hooked KEY_ESC, it defaults to closing
1086     // the wrapper panel.
1087     //
1088     if ((code & 0xFF) == KEY_ESC)
1089         wrapper_panel_close(TRUE);
1090     return TRUE;
1091 }
1092 #pragma enable_message(202)
1093 
clear_obuttons()1094 void clear_obuttons() {
1095     uiCursorStack *cs;
1096     extern uiSlab *uiCurrentSlab;
1097 
1098     uiGetSlabCursorStack(uiCurrentSlab, &cs);
1099     uiPopCursorEvery(cs, &slider_cursor);
1100     mouse_unconstrain();
1101     LG_memset(OButtons, 0, MAX_OPTION_BUTTONS * sizeof(opt_button));
1102 }
1103 
opanel_redraw(uchar back)1104 void opanel_redraw(uchar back) {
1105     extern grs_bitmap inv_backgnd;
1106     int but;
1107     LGRect r = {{INVENTORY_PANEL_X, INVENTORY_PANEL_Y},
1108                 {INVENTORY_PANEL_X + INVENTORY_PANEL_WIDTH, INVENTORY_PANEL_Y + INVENTORY_PANEL_HEIGHT}};
1109 #ifdef SVGA_SUPPORT
1110     uchar old_over = gr2ss_override;
1111     gr2ss_override = OVERRIDE_ALL; // Since we are really going straight to screen in our heart of hearts
1112 #endif
1113     if (!full_game_3d)
1114         inventory_clear();
1115     gr_push_canvas(&inv_norm_canvas);
1116     uiHideMouse(NULL);
1117     gr_set_font(opt_font);
1118     if (back) {
1119         if (full_game_3d)
1120             ss_noscale_bitmap(&inv_view360_canvas.bm, FULL_BACK_X, FULL_BACK_Y);
1121         else
1122             ss_bitmap(&inv_backgnd, 0, 0);
1123     }
1124 
1125     for (but = 0; but < MAX_OPTION_BUTTONS; but++) {
1126         if (OButtons[but].drawfunc) {
1127             OButtons[but].drawfunc(but);
1128         }
1129     }
1130     uiShowMouse(&r);
1131     gr_pop_canvas();
1132 #ifdef SVGA_SUPPORT
1133     gr2ss_override = old_over;
1134 #endif
1135 }
1136 
1137 // fills in the Rect r with one of the "standard" button rects,
1138 // assuming buttons in three columns, ro rows, high enough for
1139 // a specified number of lines of text.
1140 //
standard_button_rect(LGRect * r,uchar butid,uchar lines,uchar ro,uchar mar)1141 void standard_button_rect(LGRect *r, uchar butid, uchar lines, uchar ro, uchar mar) {
1142     short w, h;
1143     char i = butid;
1144 
1145     gr_set_font(opt_font);
1146     gr_string_size("X", &w, &h);
1147 
1148     h *= lines;
1149 
1150     r->ul.x = widget_x(i % 3, 3, mar);
1151     r->lr.x = r->ul.x + widget_width(3, mar);
1152     r->ul.y = INVENTORY_PANEL_HEIGHT * (i / 3 + 1) / (ro + 1) - h / 2;
1153     if (ro > 2)
1154         r->ul.y += (3 * ((i / 3) - 1));
1155     r->lr.y = r->ul.y + h + 2;
1156 }
1157 
standard_slider_rect(LGRect * r,uchar butid,uchar ro,uchar mar)1158 void standard_slider_rect(LGRect *r, uchar butid, uchar ro, uchar mar) {
1159     short sh, sw;
1160 
1161     standard_button_rect(r, butid, 2, ro, mar);
1162 
1163     sh = res_bm_height(OPT_SLIDER_BAR);
1164     sw = res_bm_height(OPT_SLIDER_BAR);
1165     r->ul.x += sw / 2;
1166     r->lr.x -= sw / 2;
1167     r->ul.y = r->lr.y - sh;
1168 }
1169 
wrapper_panel_close(uchar clear_message)1170 errtype wrapper_panel_close(uchar clear_message) {
1171     uiCursorStack *cs;
1172     extern uiSlab *uiCurrentSlab;
1173     int i;
1174     extern void mfd_force_update_single(int which_mfd);
1175 #ifdef SVGA_SUPPORT
1176     extern errtype mfd_clear_all();
1177 #endif
1178 
1179     if (!wrapper_panel_on)
1180         return ERR_NOEFFECT;
1181     mouse_unconstrain();
1182     if (clear_message)
1183         message_info("");
1184     wrapper_panel_on = FALSE;
1185     SavePrefs();
1186     inventory_page = inv_last_page;
1187     if (inventory_page < 0 && inventory_page != INV_3DVIEW_PAGE)
1188         inventory_page = 0;
1189     pause_game_func(0, 0, 0);
1190     uiGetSlabCursorStack(uiCurrentSlab, &cs);
1191     uiPopCursorEvery(cs, &slider_cursor);
1192     uiReleaseFocus(inventory_region, UI_EVENT_KBD_COOKED | UI_EVENT_MOUSE);
1193     uiRemoveRegionHandler(inventory_region, wrap_id);
1194     uiRemoveRegionHandler(inventory_region, wrap_key_id);
1195 #ifndef STATIC_BUTTON_STORE
1196     full_visible = fv;
1197 #endif
1198     inventory_clear();
1199     inventory_draw();
1200 #ifdef SVGA_SUPPORT
1201     mfd_clear_all();
1202 #endif
1203     for (i = 0; i < NUM_MFDS; i++)
1204         mfd_force_update_single(i);
1205     ResUnlock(OPTIONS_FONT);
1206     resume_game_time();
1207     return (OK);
1208 }
1209 
1210 extern uchar game_paused;
1211 
can_save()1212 uchar can_save() {
1213     uchar gp = game_paused;
1214     if (global_fullmap->cyber) {
1215         // spoof the game as not being paused so that the message won't go to the
1216         // phantom message line in full screen mode, where it will stay only for a frame.
1217         game_paused = FALSE;
1218         string_message_info(REF_STR_NoCyberSave);
1219         game_paused = gp;
1220         return (FALSE);
1221     }
1222     if (input_cursor_mode == INPUT_OBJECT_CURSOR) {
1223         string_message_info(REF_STR_CursorObjSave);
1224         return (FALSE);
1225     }
1226     return (TRUE);
1227 }
1228 
1229 //
1230 // THE TOP LEVEL OPTIONS: Initialization, handler
1231 //
1232 
wrapper_pushbutton_func(uchar butid)1233 void wrapper_pushbutton_func(uchar butid) {
1234     switch (butid) {
1235     case LOAD_BUTTON: // Load Game
1236 #ifdef DEMO
1237         wrapper_panel_close(FALSE);
1238 #else
1239         load_screen_init();
1240         string_message_info(REF_STR_LoadSlot);
1241 #endif
1242         break;
1243     case SAVE_BUTTON: // Save Game
1244 #ifdef DEMO
1245         wrapper_panel_close(FALSE);
1246 #else
1247         if (can_save()) {
1248             save_screen_init();
1249             string_message_info(REF_STR_SaveSlot);
1250         } else
1251             wrapper_panel_close(FALSE);
1252 #endif
1253         break;
1254     case AUDIO_BUTTON: // Audio
1255         sound_screen_init();
1256         break;
1257     case INPUT_BUTTON: // Input
1258         input_screen_init();
1259         break;
1260     case VIDEO_BUTTON: // Input
1261         video_screen_init();
1262         break;
1263 #ifdef SVGA_SUPPORT
1264     case SCREENMODE_BUTTON: // Input
1265         screenmode_screen_init();
1266         break;
1267     case HEAD_RECENTER_BUTTON: // Input
1268     {
1269         // extern uchar recenter_headset(ushort keycode, uint32_t context, intptr_t data);
1270         // recenter_headset(0,0,0);
1271     } break;
1272     case HEADSET_BUTTON:
1273         // headset_screen_init();
1274         break;
1275 #endif
1276     case AUDIO_OPT_BUTTON:
1277         soundopt_screen_init();
1278         break;
1279     case OPTIONS_BUTTON: // Options
1280         options_screen_init();
1281         break;
1282     case RETURN_BUTTON: // Return
1283         wrapper_panel_close(TRUE);
1284         break;
1285     case QUIT_BUTTON: // Quit
1286         verify_screen_init(quit_verify_pushbutton_handler, quit_verify_slorker);
1287         string_message_info(REF_STR_QuitConfirm);
1288         break;
1289     }
1290     return;
1291 }
1292 
wrapper_init(void)1293 void wrapper_init(void) {
1294     LGRect r;
1295     int i;
1296     char *keyequivs;
1297 
1298     keyequivs = get_temp_string(REF_STR_KeyEquivs0);
1299 
1300     clear_obuttons();
1301     for (i = 0; i < 8; i++) {
1302         standard_button_rect(&r, i, 2, 3, 5);
1303         pushbutton_init(i, keyequivs[i], REF_STR_WrapperText + i, wrapper_pushbutton_func, &r);
1304     }
1305 #ifdef DEMO
1306     dim_pushbutton(LOAD_BUTTON);
1307     dim_pushbutton(SAVE_BUTTON);
1308 #endif
1309     opanel_redraw(TRUE);
1310 }
1311 
1312     //
1313     // THE VERIFY SCREEN: Initialization, handlers
1314     //
1315 
1316 #pragma disable_message(202)
quit_verify_pushbutton_handler(uchar butid)1317 void quit_verify_pushbutton_handler(uchar butid) { really_quit_key_func(0, 0, 0); }
1318 
quit_verify_slorker(uchar butid)1319 uchar quit_verify_slorker(uchar butid) {
1320     wrapper_panel_close(TRUE);
1321     return TRUE;
1322 }
1323 
save_verify_pushbutton_handler(uchar butid)1324 void save_verify_pushbutton_handler(uchar butid) { do_savegame_guts(savegame_verify); }
1325 
save_verify_slorker(uchar butid)1326 uchar save_verify_slorker(uchar butid) {
1327     strcpy(comments[savegame_verify], comments[NUM_SAVE_SLOTS]);
1328     wrapper_panel_close(TRUE);
1329     return TRUE;
1330 }
1331 #pragma enable_message(202)
1332 
verify_screen_init(void (* verify)(uchar butid),slorker slork)1333 void verify_screen_init(void (*verify)(uchar butid), slorker slork) {
1334     LGRect r;
1335 
1336     clear_obuttons();
1337 
1338     standard_button_rect(&r, 1, 2, 2, 5);
1339     pushbutton_init(0, tolower(get_temp_string(REF_STR_VerifyText)[0]), REF_STR_VerifyText, verify, &r);
1340 
1341     standard_button_rect(&r, 4, 2, 2, 5);
1342     pushbutton_init(1, tolower(get_temp_string(REF_STR_VerifyText + 1)[0]), (REF_STR_VerifyText + 1), (void (*)(uchar))slork, &r);
1343 
1344     slork_init(2, slork);
1345 
1346     opanel_redraw(TRUE);
1347 }
1348 
quit_verify_init(void)1349 void quit_verify_init(void) { verify_screen_init(quit_verify_pushbutton_handler, quit_verify_slorker); }
1350 
1351 //
1352 // THE SOUND OPTIONS SCREEN: Initialization, update funcs
1353 
1354 uchar curr_vol_lev = 100;
1355 uchar curr_sfx_vol = 100;
1356 uchar curr_alog_vol = 100;
1357 
recompute_music_level(ushort vol)1358 void recompute_music_level(ushort vol) {
1359     //   curr_vol_lev=long_sqrt(100*vol);
1360     curr_vol_lev = QVAR_TO_VOLUME(vol);
1361     if (vol == 0) {
1362         music_on = FALSE;
1363         // stop_music_func(0,0,0);
1364     } else {
1365         if (!music_on) {
1366             music_on = TRUE;
1367             // start_music_func(0,0,0);
1368         }
1369         // mlimbs_change_master_volume(curr_vol_lev);
1370     }
1371     MacTuneUpdateVolume();
1372 }
1373 
recompute_digifx_level(ushort vol)1374 void recompute_digifx_level(ushort vol) {
1375     sfx_on = (vol != 0);
1376     curr_sfx_vol = QVAR_TO_VOLUME(vol);
1377     if (sfx_on) {
1378 #ifdef DEMO
1379         play_digi_fx(73, 1);
1380 #else
1381         // play a sample (if not alreay playing)
1382         if (!digi_fx_playing(SFX_NEAR_1, NULL))
1383             play_digi_fx(SFX_NEAR_1, 1);
1384         // update volume (main loop is not running at this point)
1385         extern void sound_frame_update(void);
1386         sound_frame_update();
1387 #endif
1388     } else {
1389 #ifdef AUDIOLOGS
1390         audiolog_stop();
1391 #endif
1392         stop_digi_fx();
1393     }
1394 }
1395 
1396 #ifdef AUDIOLOGS
recompute_audiolog_level(ushort vol)1397 void recompute_audiolog_level(ushort vol) {
1398     curr_alog_vol = QVAR_TO_VOLUME(vol);
1399     extern void sound_frame_update(void);
1400     sound_frame_update();
1401 }
1402 #endif
1403 
1404 #pragma disable_message(202)
digi_toggle_deal(uchar offon)1405 void digi_toggle_deal(uchar offon) {
1406     int vol;
1407     vol = (sfx_on) ? 100 : 0;
1408     recompute_digifx_level(vol);
1409     QUESTVAR_SET(SFX_VOLUME_QVAR, vol);
1410 }
1411 
1412 #ifdef AUDIOLOGS
audiolog_dealfunc(short val)1413 void audiolog_dealfunc(short val) {
1414     if (!val)
1415         audiolog_stop();
1416     QUESTVAR_SET(ALOG_OPT_QVAR, audiolog_setting);
1417 }
1418 #endif
1419 
1420 char hack_digi_channels = 1;
1421 
digichan_dealfunc(short val)1422 void digichan_dealfunc(short val) {
1423     hack_digi_channels = val;
1424     switch (hack_digi_channels) {
1425     case 0:
1426         cur_digi_channels = 2;
1427         break;
1428     case 1:
1429         cur_digi_channels = 4;
1430         break;
1431     case 2:
1432         cur_digi_channels = 8;
1433         break;
1434     }
1435     QUESTVAR_SET(DIGI_CHANNELS_QVAR, hack_digi_channels);
1436     // snd_set_digital_channels(cur_digi_channels);
1437 }
1438 
seqer_dealfunc(short val)1439 static void seqer_dealfunc(short val) {
1440 //    INFO("Selected MIDI device %d", val);
1441     gShockPrefs.soMidiOutput = 0;
1442     ReloadDecXMI(); // Reload Midi decoder
1443     soundopt_screen_init();
1444     (void)val;
1445 }
1446 
midi_output_dealfunc(short val)1447 static void midi_output_dealfunc(short val) {
1448 //    INFO("Selected MIDI output %d", val);
1449     ReloadDecXMI(); // Reload Midi decoder
1450     soundopt_screen_init();
1451     (void)val;
1452 }
1453 
1454 #pragma enable_message(202)
1455 
1456 #define SLIDER_OFFSET_3 0
soundopt_screen_init()1457 void soundopt_screen_init() {
1458     LGRect r;
1459     char retkey;
1460     int i = 0;
1461 
1462     clear_obuttons();
1463 
1464     standard_button_rect(&r, i, 2, 2, 5);
1465     retkey = tolower(get_temp_string(REF_STR_AilThreeText)[0]);
1466     multi_init(i, retkey, REF_STR_AilThreeText, REF_STR_DigiChannelState, ID_NULL, sizeof(hack_digi_channels),
1467                &hack_digi_channels, 3, digichan_dealfunc, &r);
1468     i++;
1469 
1470     standard_button_rect(&r, i, 2, 2, 5);
1471     retkey = tolower(get_temp_string(REF_STR_AilThreeText + 1)[0]);
1472     // multi_init(i, retkey, REF_STR_AilThreeText+1, REF_STR_StereoReverseState, NULL,
1473     //   sizeof(snd_stereo_reverse), &snd_stereo_reverse, 2, NULL, &r);
1474     // i++;
1475 
1476 #ifdef AUDIOLOGS
1477     standard_button_rect(&r, i, 2, 2, 5);
1478     retkey = tolower(get_temp_string(REF_STR_MusicText + 3)[0]);
1479     multi_init(i, retkey, REF_STR_MusicText + 3, REF_STR_AudiologState, ID_NULL, sizeof(audiolog_setting),
1480                &audiolog_setting, 3, audiolog_dealfunc, &r);
1481     i++;
1482 #endif
1483 
1484     standard_button_rect(&r, i, 2, 2, 5);
1485     multi_init(i, 'p', REF_STR_Seqer, REF_STR_ADLMIDI, ID_NULL,
1486                sizeof(gShockPrefs.soMidiBackend), &gShockPrefs.soMidiBackend, OPT_SEQ_Max, seqer_dealfunc, &r);
1487     i++;
1488 /* standard button is too narrow, so use a slider instead
1489     const unsigned int numMidiOutputs = GetOutputCountXMI();
1490     INFO("numMidiOutputs=%d", numMidiOutputs);
1491     standard_button_rect(&r, i, 2, 2, 5);
1492     multi_init(i, 'o', REF_STR_MidiOut, REF_STR_MidiOutX, ID_NULL,
1493                sizeof(gShockPrefs.soMidiOutput), &gShockPrefs.soMidiOutput, numMidiOutputs, midi_output_dealfunc, &r);
1494     i++;
1495 */
1496     unsigned int midiOutputCount = GetOutputCountXMI();
1497     if (midiOutputCount > 1)
1498     {
1499         standard_slider_rect(&r, i, 2, 5);
1500         // this makes it double-wide i guess?
1501         r.lr.x += (r.lr.x - r.ul.x);
1502         slider_init(i, REF_STR_MidiOutX + gShockPrefs.soMidiOutput, sizeof(gShockPrefs.soMidiOutput), FALSE, &gShockPrefs.soMidiOutput, midiOutputCount - 1,
1503                     0, midi_output_dealfunc, &r);
1504         i++;
1505     }
1506     else if (midiOutputCount == 1)
1507     {
1508         // just show a text label
1509         standard_button_rect(&r, i, 1, 2, 10);
1510         textwidget_init(i, BUTTON_COLOR, REF_STR_MidiOutX, &r);
1511         i++;
1512     }
1513 
1514     standard_button_rect(&r, 5, 2, 2, 5);
1515     retkey = tolower(get_temp_string(REF_STR_MusicText + 2)[0]);
1516     pushbutton_init(RETURN_BUTTON, retkey, REF_STR_MusicText + 2, wrapper_pushbutton_func, &r);
1517 
1518     // FIXME: Cannot pass a keycode with modifier flags as uchar
1519     keywidget_init(QUIT_BUTTON, /*KB_FLAG_ALT |*/ 'x', wrapper_pushbutton_func);
1520     opanel_redraw(TRUE);
1521 }
1522 
sound_screen_init(void)1523 void sound_screen_init(void) {
1524     LGRect r;
1525     uchar sliderbase;
1526     char retkey;
1527     char slider_offset = 0;
1528 #ifdef AUDIOLOGS
1529     slider_offset = 10;
1530 #endif
1531 
1532     clear_obuttons();
1533 
1534     if (music_card) {
1535         standard_slider_rect(&r, 0, 2, 5);
1536         // let's double the width of these things, eh?
1537         r.lr.x += (r.lr.x - r.ul.x);
1538         r.ul.y -= slider_offset;
1539         r.lr.y -= slider_offset;
1540         sliderbase = r.lr.x - r.ul.x - 2;
1541         slider_init(0, REF_STR_MusicText, sizeof(ushort), TRUE, &player_struct.questvars[MUSIC_VOLUME_QVAR], 100,
1542                     sliderbase, recompute_music_level, &r);
1543     } else {
1544         standard_button_rect(&r, 0, 2, 2, 5);
1545         r.lr.x += (r.lr.x - r.ul.x);
1546         r.ul.y -= slider_offset / 2;
1547         r.lr.y -= slider_offset / 2;
1548         textwidget_init(0, BUTTON_COLOR, REF_STR_MusicFeedbackText + 2, &r);
1549     }
1550 
1551     if (digi_gain) {
1552         standard_slider_rect(&r, 3, 2, 5);
1553         r.lr.x += (r.lr.x - r.ul.x);
1554         r.ul.y -= slider_offset;
1555         r.lr.y -= slider_offset;
1556         slider_init(1, REF_STR_MusicText + 1, sizeof(ushort), FALSE, &player_struct.questvars[SFX_VOLUME_QVAR], 100,
1557                     sliderbase, recompute_digifx_level, &r);
1558     } else {
1559         standard_button_rect(&r, 3, 2, 2, 5);
1560         r.ul.y -= slider_offset;
1561         r.lr.y -= slider_offset;
1562         multi_init(1, get_temp_string(REF_STR_MusicText + 1)[0], REF_STR_MusicText + 1, REF_STR_OffonText,
1563                    REF_STR_MusicFeedbackText + 5, sizeof(sfx_on), &sfx_on, 2, digi_toggle_deal, &r);
1564     }
1565 
1566 #ifdef AUDIOLOGS
1567     standard_slider_rect(&r, 6, 2, 5);
1568     r.lr.x += (r.lr.x - r.ul.x);
1569     r.ul.y -= slider_offset;
1570     r.lr.y -= slider_offset;
1571     slider_init(2, REF_STR_MusicText + 4, sizeof(ushort), FALSE, &player_struct.questvars[ALOG_VOLUME_QVAR], 100,
1572                 sliderbase, recompute_audiolog_level, &r);
1573 #endif
1574 
1575     standard_button_rect(&r, 2, 2, 2, 5);
1576     retkey = tolower(get_temp_string(REF_STR_AilThreeText + 2)[0]);
1577     pushbutton_init(AUDIO_OPT_BUTTON, retkey, REF_STR_AilThreeText + 2, wrapper_pushbutton_func, &r);
1578 
1579     standard_button_rect(&r, 5, 2, 2, 5);
1580     retkey = tolower(get_temp_string(REF_STR_MusicText + 2)[0]);
1581     pushbutton_init(RETURN_BUTTON, retkey, REF_STR_MusicText + 2, wrapper_pushbutton_func, &r);
1582 
1583     // FIXME: Cannot pass a keycode with modifier flags as uchar
1584     keywidget_init(QUIT_BUTTON, /*KB_FLAG_ALT |*/ 'x', wrapper_pushbutton_func);
1585 
1586     opanel_redraw(TRUE);
1587 }
1588 
1589     //
1590     // THE OPTIONS SCREEN: Initialization, update funcs
1591     //
1592 
1593     /*void gamma_dealfunc(ushort gamma_qvar)
1594     {
1595        fix gamma;
1596 
1597     //   gamma=FIX_UNIT-fix_make(0,gamma_qvar);
1598     //   gamma=fix_mul(gamma,gamma)+(FIX_UNIT/2);
1599        gamma=QVAR_TO_GAMMA(gamma_qvar);
1600        gr_set_gamma_pal(0,256,gamma);
1601     }*/
1602 
1603 #ifdef SVGA_SUPPORT
1604 uchar wrapper_screenmode_hack = FALSE;
screenmode_change(uchar new_mode)1605 void screenmode_change(uchar new_mode) {
1606     extern short mode_id;
1607     mode_id = new_mode;
1608     QUESTVAR_SET(SCREENMODE_QVAR, new_mode);
1609     change_mode_func(0, 0, _current_loop);
1610     wrapper_screenmode_hack = TRUE;
1611 
1612     INFO("Changed screen mode to %i\n", mode_id);
1613     wrapper_panel_close(TRUE);
1614 }
1615 #endif
1616 
language_change(uchar lang)1617 void language_change(uchar lang) {
1618     extern int string_res_file, mfdart_res_file;
1619     extern char *mfdart_files[];
1620     extern char *language_files[];
1621     extern void invent_language_change(void);
1622     extern void mfd_language_change(void);
1623     extern void side_icon_language_change(void);
1624 
1625     ResCloseFile(string_res_file);
1626     ResCloseFile(mfdart_res_file);
1627 
1628     mfdart_res_file = ResOpenFile(mfdart_files[lang]);
1629     if (mfdart_res_file < 0)
1630         critical_error(CRITERR_RES | 2);
1631 
1632     string_res_file = ResOpenFile(language_files[lang]);
1633     if (string_res_file < 0)
1634         critical_error(CRITERR_RES | 0);
1635 
1636     QUESTVAR_SET(LANGUAGE_QVAR, lang);
1637 
1638     // in case we got here from interpret_qvars, and thus
1639     // haven't set this yet
1640     which_lang = lang;
1641 
1642     invent_language_change();
1643     mfd_language_change();
1644     side_icon_language_change();
1645     // free_options_cursor();
1646     make_options_cursor();
1647 }
1648 
language_dealfunc(uchar lang)1649 void language_dealfunc(uchar lang) {
1650     language_change(lang);
1651 
1652     render_run();
1653     opanel_redraw(FALSE);
1654 }
1655 
dclick_dealfunc(ushort dclick_qvar)1656 void dclick_dealfunc(ushort dclick_qvar) {
1657     uiDoubleClickDelay = QVAR_TO_DCLICK(dclick_qvar, 0);
1658     uiDoubleClickTime = QVAR_TO_DCLICK(dclick_qvar, 1);
1659 }
1660 
joysens_dealfunc(ushort joysens_qvar)1661 void joysens_dealfunc(ushort joysens_qvar) {
1662     extern fix inpJoystickSens;
1663 
1664     inpJoystickSens = QVAR_TO_JOYSENS(joysens_qvar);
1665 }
1666 
1667 #pragma disable_message(202)
center_joy_go(uchar butid)1668 void center_joy_go(uchar butid) {
1669     extern uchar recenter_joystick(ushort keycode, uint32_t context, intptr_t data);
1670 
1671     // recenter_joystick(0,0,0);
1672     joystick_screen_init();
1673 }
1674 #pragma enable_message(202)
1675 
center_joy_pushbutton_func(uchar butid)1676 void center_joy_pushbutton_func(uchar butid) {
1677     int i;
1678     string_message_info(REF_STR_CenterJoyPrompt);
1679 
1680     // take over this button, null the other buttons
1681     // except for RETURN and QUIT;
1682 
1683     for (i = 0; i < MAX_OPTION_BUTTONS; i++) {
1684         if (i == butid)
1685             keywidget_init(i, KEY_ENTER, center_joy_go);
1686         else if (i != RETURN_BUTTON && i != QUIT_BUTTON)
1687             OButtons[i].evmask = 0;
1688     }
1689 }
1690 
renderer_dealfunc(bool unused)1691 static void renderer_dealfunc(bool unused) {
1692     uiHideMouse(NULL);
1693     render_run();
1694     if (full_game_3d) {
1695         // update stored background bitmap and redraw menu
1696         ss_get_bitmap(&inv_view360_canvas.bm, GAME_MESSAGE_X, GAME_MESSAGE_Y);
1697         opanel_redraw(FALSE);
1698     }
1699     uiShowMouse(NULL);
1700     // recalculate menu in case a button needs to be added or removed
1701     video_screen_init();
1702     // suppress compiler warning
1703     (void)unused;
1704 }
1705 
detail_dealfunc(uchar det)1706 void detail_dealfunc(uchar det) {
1707     extern errtype change_detail_level(byte new_level);
1708 
1709     change_detail_level(det);
1710     uiHideMouse(NULL);
1711     render_run();
1712     if (full_game_3d)
1713         opanel_redraw(FALSE);
1714     uiShowMouse(NULL);
1715 }
1716 
mousehand_dealfunc(ushort lefty)1717 void mousehand_dealfunc(ushort lefty) {
1718     // mouse_set_lefty(lefty);
1719 }
1720 
1721 #if defined(VFX1_SUPPORT) || defined(CTM_SUPPORT)
1722 #pragma disable_message(202)
headset_stereo_dealfunc(uchar st_on)1723 void headset_stereo_dealfunc(uchar st_on) {
1724     extern uchar inp6d_headset;
1725     extern uchar inp6d_stereo;
1726     //   extern uchar ui_stereo_on;
1727     if ((inp6d_headset) && (i6d_device != I6D_ALLPRO)) {
1728         //      ui_stereo_on = inp6d_stereo;
1729         if (!inp6d_stereo)
1730             i6_video(I6VID_CLOSEDOWN, NULL); // this will want to be I6VID_STR_CLOSE at some point
1731         else {
1732             if (i6_video(I6VID_STR_START, NULL)) {
1733                 Warning(("Headset stereo startup failed!\n"));
1734                 return;
1735             }
1736         }
1737     }
1738 }
1739 
headset_tracking_dealfunc(uchar tr_on)1740 void headset_tracking_dealfunc(uchar tr_on) {
1741     Warning(("tracking now %d!\n", tr_on));
1742     return;
1743 }
1744 
headset_fov_dealfunc(int hackval)1745 void headset_fov_dealfunc(int hackval) {
1746     inp6d_curr_fov = hack_headset_fov + HEADSET_FOV_MIN;
1747     Warning(("FOV now %d!\n", inp6d_curr_fov));
1748     return;
1749 }
1750 #pragma enable_message(202)
1751 #endif
1752 
1753 #pragma disable_message(202)
olh_dealfunc(uchar olh)1754 void olh_dealfunc(uchar olh) {
1755     extern uchar toggle_olh_func(ushort keycode, uint32_t context, intptr_t data);
1756 
1757     toggle_olh_func(0, 0, 0);
1758 }
1759 #pragma enable_message(202)
1760 
1761 #ifdef STEREO_SUPPORT
1762 #define INITIAL_OCULAR_DIST fix_make(3, 0x4000)
1763 #endif
1764 
1765 ushort wrap_joy_type = 0;
1766 ushort high_joy_flags;
joystick_type_func(ushort new_joy_type)1767 void joystick_type_func(ushort new_joy_type) {
1768     extern uchar joystick_count;
1769     // joystick_count = joy_init(high_joy_flags | new_joy_type);
1770     // config_set_single_value("joystick",CONFIG_INT_TYPE,(config_valtype)(high_joy_flags|new_joy_type));
1771     joystick_screen_init();
1772 }
1773 
joystick_screen_init(void)1774 void joystick_screen_init(void) {
1775     LGRect r;
1776     int i = 0;
1777     char *keys;
1778     extern uchar inp6d_headset;
1779     uchar sliderbase;
1780 
1781     extern uchar joystick_count;
1782     keys = get_temp_string(REF_STR_KeyEquivs6);
1783     clear_obuttons();
1784 
1785     standard_button_rect(&r, i, 2, 2, 1);
1786     multi_init(i, keys[i], REF_STR_JoystickType, REF_STR_JoystickTypes, ID_NULL, sizeof(wrap_joy_type),
1787                &wrap_joy_type, 4, joystick_type_func, &r);
1788     i++;
1789 
1790     standard_button_rect(&r, i, 2, 2, 1);
1791     pushbutton_init(i, keys[i], REF_STR_CenterJoy, center_joy_pushbutton_func, &r);
1792     if (!joystick_count && !inp6d_headset) {
1793         dim_pushbutton(i);
1794     }
1795     i++;
1796 
1797     if (joystick_count) {
1798         standard_slider_rect(&r, i, 2, 1);
1799         sliderbase = (r.lr.x - r.ul.x - 2) >> 1;
1800         slider_init(i, REF_STR_JoystickSens, sizeof(ushort), FALSE, &player_struct.questvars[JOYSENS_QVAR], 256,
1801                     sliderbase, joysens_dealfunc, &r);
1802     }
1803     i++;
1804 
1805     standard_button_rect(&r, 5, 2, 2, 1);
1806     pushbutton_init(RETURN_BUTTON, keys[i], REF_STR_OptionsText + 5, wrapper_pushbutton_func, &r);
1807 
1808     // FIXME: Cannot pass a keycode with modifier flags as uchar
1809     keywidget_init(QUIT_BUTTON, /*KB_FLAG_ALT |*/ 'x', wrapper_pushbutton_func);
1810 
1811     opanel_redraw(TRUE);
1812 }
1813 
1814 #pragma disable_message(202)
joystick_button_func(uchar butid)1815 void joystick_button_func(uchar butid) { joystick_screen_init(); }
1816 #pragma enable_message(202)
1817 
input_screen_init(void)1818 void input_screen_init(void) {
1819     LGRect r;
1820     char *keys;
1821     int i = 0;
1822     uchar sliderbase;
1823     extern uchar inp6d_headset;
1824 
1825     keys = get_temp_string(REF_STR_KeyEquivs1);
1826     clear_obuttons();
1827 
1828     standard_button_rect(&r, i, 2, 2, 1);
1829     r.ul.x -= 1;
1830     multi_init(i, keys[0], REF_STR_OptionsText + 0, REF_STR_OffonText, REF_STR_PopupCursFeedback, sizeof(popup_cursors),
1831                &popup_cursors, 2, NULL, &r);
1832     i++;
1833 
1834     standard_button_rect(&r, i, 2, 2, 1);
1835     multi_init(i, keys[1], REF_STR_OptionsText + 1, REF_STR_MouseHand, REF_STR_HandFeedback,
1836                sizeof(player_struct.questvars[MOUSEHAND_QVAR]), &player_struct.questvars[MOUSEHAND_QVAR], 2,
1837                mousehand_dealfunc, &r);
1838     i++;
1839 
1840     standard_slider_rect(&r, i, 2, 1);
1841     r.ul.x -= 1;
1842     sliderbase = ((r.lr.x - r.ul.x - 3) * (FIX_UNIT / 3)) / USHRT_MAX;
1843     slider_init(i, REF_STR_DoubleClick, sizeof(ushort), FALSE, &player_struct.questvars[DCLICK_QVAR], USHRT_MAX,
1844                 sliderbase, dclick_dealfunc, &r);
1845     i++;
1846 
1847     standard_button_rect(&r, i, 2, 2, 1);
1848     r.ul.x -= 1;
1849     pushbutton_init(i, keys[2], REF_STR_Joystick, joystick_button_func, &r);
1850     i++;
1851 
1852     standard_button_rect(&r, i, 2, 2, 1);
1853     r.ul.x -= 1;
1854     multi_init(i, keys[3], REF_STR_MousLook, REF_STR_MousNorm, ID_NULL,
1855                sizeof(gShockPrefs.goInvertMouseY), &gShockPrefs.goInvertMouseY, 2, NULL, &r);
1856     i++;
1857 
1858     standard_button_rect(&r, 5, 2, 2, 1);
1859     pushbutton_init(RETURN_BUTTON, keys[3], REF_STR_OptionsText + 5, wrapper_pushbutton_func, &r);
1860 
1861     // FIXME: Cannot pass a keycode with modifier flags as uchar
1862     keywidget_init(QUIT_BUTTON, /*KB_FLAG_ALT |*/ 'x', wrapper_pushbutton_func);
1863 
1864     opanel_redraw(TRUE);
1865 }
1866 
1867 //gamma param not used here; see SetSDLPalette() in Shock.c
gamma_slider_dealfunc(ushort gamma_qvar)1868 void gamma_slider_dealfunc(ushort gamma_qvar) {
1869     gr_set_gamma_pal(0, 256, 0);
1870 
1871     uiHideMouse(NULL);
1872     render_run();
1873     if (full_game_3d)
1874         opanel_redraw(FALSE);
1875     uiShowMouse(NULL);
1876 }
1877 
video_screen_init(void)1878 void video_screen_init(void) {
1879     LGRect r;
1880     int i;
1881     char *keys;
1882 #ifdef SVGA_SUPPORT
1883     extern short mode_id;
1884 #endif
1885     uchar sliderbase;
1886 #ifdef STEREO_SUPPORT
1887     extern uchar inp6d_headset;
1888 #endif
1889 
1890     keys = get_temp_string(REF_STR_KeyEquivs3);
1891     clear_obuttons();
1892     i = 0;
1893 
1894 #ifdef USE_OPENGL
1895     // renderer
1896     if(can_use_opengl()) {
1897         standard_button_rect(&r, i, 2, 2, 2);
1898         multi_init(i, 'g', REF_STR_Renderer, REF_STR_Software, ID_NULL,
1899                    sizeof(gShockPrefs.doUseOpenGL), &gShockPrefs.doUseOpenGL, 2, renderer_dealfunc, &r);
1900         i++;
1901     }
1902 #endif
1903 
1904 #ifdef SVGA_SUPPORT
1905     // video mode
1906     standard_button_rect(&r, i, 2, 2, 2);
1907     pushbutton_init(SCREENMODE_BUTTON, keys[0], REF_STR_VideoText, wrapper_pushbutton_func, &r);
1908     i++;
1909 #endif
1910 
1911     // detail level
1912     standard_button_rect(&r, i, 2, 2, 2);
1913     r.lr.x += 2;
1914     multi_init(i, keys[1], REF_STR_OptionsText + 4, REF_STR_DetailLvl, REF_STR_DetailLvlFeedback,
1915                sizeof(_fr_global_detail), &_fr_global_detail, 4, detail_dealfunc, &r);
1916     i++;
1917 
1918     // gamma
1919     standard_slider_rect(&r, i, 2, 2);
1920     r.ul.x = r.ul.x + 1;
1921     sliderbase = ((r.lr.x - r.ul.x - 1) * 29 / 100);
1922     slider_init(i, REF_STR_OptionsText + 3, sizeof(ushort), TRUE, &(gShockPrefs.doGamma), 100,
1923                 sliderbase, gamma_slider_dealfunc, &r);
1924     i++;
1925 
1926 #if defined(VFX1_SUPPORT) || defined(CTM_SUPPORT)
1927     standard_button_rect(&r, i, 2, 2, 2);
1928     pushbutton_init(HEADSET_BUTTON, keys[2], REF_STR_HeadsetText, wrapper_pushbutton_func, &r);
1929     if (!inp6d_headset)
1930         dim_pushbutton(HEADSET_BUTTON);
1931     i++;
1932 #endif
1933 
1934 #ifdef USE_OPENGL
1935     // textre filter
1936     if(can_use_opengl() && gShockPrefs.doUseOpenGL) {
1937         standard_button_rect(&r, i, 2, 2, 2);
1938         multi_init(i, 't', REF_STR_TextFilt, REF_STR_TFUnfil, ID_NULL,
1939                    sizeof(gShockPrefs.doTextureFilter), &gShockPrefs.doTextureFilter, 2, renderer_dealfunc, &r);
1940         i++;
1941     }
1942 #endif
1943 
1944     // return (fixed at position 5)
1945     standard_button_rect(&r, 5, 2, 2, 2);
1946     pushbutton_init(RETURN_BUTTON, keys[3], REF_STR_OptionsText + 5, wrapper_pushbutton_func, &r);
1947 
1948     // FIXME: Cannot pass a keycode with modifier flags as uchar
1949     keywidget_init(QUIT_BUTTON, /*KB_FLAG_ALT |*/ 'x', wrapper_pushbutton_func);
1950 
1951     opanel_redraw(TRUE);
1952 }
1953 
1954 #if defined(VFX1_SUPPORT) || defined(CTM_SUPPORT)
headset_screen_init(void)1955 void headset_screen_init(void) {
1956     LGRect r;
1957     int i;
1958     char *keys;
1959 #ifdef STEREO_SUPPORT
1960     extern uchar inp6d_stereo;
1961     extern int inp6d_stereo_div;
1962 #endif
1963 
1964     keys = get_temp_string(REF_STR_KeyEquivs5);
1965 
1966     clear_obuttons();
1967 
1968     i = 0;
1969 
1970     standard_button_rect(&r, i, 2, 2, 2);
1971     pushbutton_init(HEAD_RECENTER_BUTTON, keys[0], REF_STR_HeadsetText + 1, wrapper_pushbutton_func, &r);
1972 
1973 #ifdef STEREO_SUPPORT
1974     i++;
1975     standard_slider_rect(&r, i, 2, 2);
1976     r.ul.x -= 1;
1977     slider_init(i, REF_STR_HeadsetText + 2, sizeof(inp6d_stereo_div), FALSE, &inp6d_stereo_div, fix_make(10, 0),
1978                 INITIAL_OCULAR_DIST, NULL, &r);
1979 
1980     i++;
1981     standard_button_rect(&r, i, 2, 2, 2);
1982     multi_init(i, keys[1], REF_STR_HeadsetText + 3, REF_STR_OffonText, ID_NULL, sizeof(inp6d_stereo),
1983                &inp6d_stereo, 2, headset_stereo_dealfunc, &r);
1984 
1985     if (i6d_device == I6D_ALLPRO)
1986         dim_pushbutton(i);
1987 
1988     i++;
1989     standard_button_rect(&r, i, 2, 2, 2);
1990     multi_init(i, keys[3], REF_STR_MoreHeadset + 1, REF_STR_OffonText, ID_NULL, sizeof(headset_track),
1991                &headset_track, 2, headset_tracking_dealfunc, &r);
1992 
1993     i++;
1994     standard_slider_rect(&r, i, 2, 2);
1995     r.ul.x -= 1;
1996     slider_init(i, REF_STR_MoreHeadset, sizeof(hack_headset_fov), FALSE, &hack_headset_fov,
1997                 HEADSET_FOV_MAX - HEADSET_FOV_MIN, inp6d_real_fov - HEADSET_FOV_MIN, headset_fov_dealfunc, &r);
1998 #endif
1999 
2000     // Standard return button and other bureaucracy
2001     standard_button_rect(&r, 5, 2, 2, 2);
2002     pushbutton_init(RETURN_BUTTON, keys[2], REF_STR_OptionsText + 5, wrapper_pushbutton_func, &r);
2003     keywidget_init(QUIT_BUTTON, KB_FLAG_ALT | 'x', wrapper_pushbutton_func);
2004     opanel_redraw(TRUE);
2005 }
2006 #endif
2007 
2008 #ifdef SVGA_SUPPORT
screenmode_screen_init(void)2009 void screenmode_screen_init(void) {
2010     LGRect r;
2011     int i;
2012     char *keys;
2013 
2014     if (wrapper_screenmode_hack && !(can_use_opengl() && gShockPrefs.doUseOpenGL)) {
2015         uiHideMouse(NULL);
2016         render_run();
2017         uiShowMouse(NULL);
2018         wrapper_screenmode_hack = FALSE;
2019     }
2020 
2021     keys = get_temp_string(REF_STR_KeyEquivs4);
2022 
2023     clear_obuttons();
2024 
2025     for (i = 0; i < 5; i++) {
2026         extern short svga_mode_data[];
2027         uchar mode_ok = FALSE;
2028         char j = 0;
2029         standard_button_rect(&r, i, 2, 2, 2);
2030         pushbutton_init(i, keys[i], REF_STR_ScreenModeText + i, screenmode_change, &r);
2031         while ((grd_info.modes[j] != -1) && !mode_ok) {
2032             if (grd_info.modes[j] == svga_mode_data[i])
2033                 mode_ok = TRUE;
2034             j++;
2035         }
2036         if (!mode_ok)
2037             dim_pushbutton(i);
2038         else if (i == convert_use_mode)
2039             bright_pushbutton(i);
2040     }
2041 
2042     standard_button_rect(&r, 5, 2, 2, 2);
2043     pushbutton_init(RETURN_BUTTON, keys[2], REF_STR_OptionsText + 5, wrapper_pushbutton_func, &r);
2044 
2045     // FIXME: Cannot pass a keycode with modifier flags as uchar
2046     keywidget_init(QUIT_BUTTON, /*KB_FLAG_ALT |*/ 'x', wrapper_pushbutton_func);
2047 
2048     opanel_redraw(TRUE);
2049 }
2050 #endif
2051 
options_screen_init(void)2052 void options_screen_init(void) {
2053     LGRect r;
2054     char *keys;
2055     int i = 0;
2056 
2057     keys = get_temp_string(REF_STR_KeyEquivs2);
2058     clear_obuttons();
2059 
2060     // olh_temp=(QUESTBIT_GET(OLH_QBIT)==0);
2061 
2062     olh_temp = olh_active;
2063 
2064     // okay, I admit it, we're going to tweak these "standard"
2065     // button rects a little bit.
2066 
2067     standard_button_rect(&r, 0, 2, 2, 2);
2068     r.ul.x -= 2;
2069     multi_init(i, keys[i], REF_STR_OptionsText + 2, REF_STR_TerseText, REF_STR_TerseFeedback,
2070                sizeof(gShockPrefs.goMsgLength), &(gShockPrefs.goMsgLength), 2, NULL, &r);
2071     i++;
2072 
2073     i++;
2074 
2075     standard_button_rect(&r, 1, 2, 2, 2);
2076     multi_init(i, keys[i], REF_STR_OnlineHelp, REF_STR_OffonText, ID_NULL, sizeof(olh_temp), &olh_temp, 2,
2077                olh_dealfunc, &r);
2078     i++;
2079 
2080     i++;
2081 
2082     standard_button_rect(&r, 2, 2, 2, 2);
2083     multi_init(i, keys[i], REF_STR_Language, REF_STR_Languages, ID_NULL, sizeof(which_lang), &which_lang, 3,
2084                language_dealfunc, &r);
2085     i++;
2086 
2087     standard_button_rect(&r, 5, 2, 2, 2);
2088     r.lr.x += 2;
2089     pushbutton_init(RETURN_BUTTON, keys[i], REF_STR_OptionsText + 5, wrapper_pushbutton_func, &r);
2090 
2091     // FIXME: Cannot pass a keycode with modifier flags as uchar
2092     keywidget_init(QUIT_BUTTON, /*KB_FLAG_ALT |*/ 'x', wrapper_pushbutton_func);
2093 
2094     opanel_redraw(TRUE);
2095 }
2096 
2097 #pragma disable_message(202)
wrapper_options_func(ushort keycode,uint32_t context,intptr_t data)2098 uchar wrapper_options_func(ushort keycode, uint32_t context, intptr_t data) {
2099     wrapper_start(wrapper_init);
2100     return (OK);
2101 }
2102 #pragma enable_message(202);
2103 
2104 //
2105 // THE LOAD GAME SCREEN: Initialization, update funcs
2106 //
2107 
2108 extern void spoof_mouse_event();
2109 
2110 #pragma disable_message(202)
load_dealfunc(uchar butid,uchar index)2111 void load_dealfunc(uchar butid, uchar index) {
2112     begin_wait();
2113     Poke_SaveName(index);
2114     // Spew(DSRC_EDITOR_Save,("attempting to load from %s\n",save_game_name));
2115 
2116     if (load_game(save_game_name) != OK) {
2117         WARN("%s: Load game failed!", __FUNCTION__);
2118     } else {
2119         INFO("Game %d loaded!", index);
2120         // Spew(DSRC_EDITOR_Restore,("Game %d loaded!\n",index));
2121     }
2122     end_wait();
2123     // spoof_mouse_event();
2124     wrapper_panel_close(TRUE);
2125 }
2126 #pragma enable_message(202)
2127 
load_screen_init(void)2128 void load_screen_init(void) {
2129     extern uchar valid_save;
2130 
2131     clear_obuttons();
2132 
2133     textlist_init(0, *comments, NUM_SAVE_SLOTS, SAVE_COMMENT_LEN, FALSE, 0, valid_save, valid_save, REF_STR_UnusedSave,
2134                   BUTTON_COLOR, WHITE, BUTTON_COLOR + 2, 0, load_dealfunc, NULL);
2135 
2136     // FIXME: Cannot pass a keycode with modifier flags as uchar
2137     keywidget_init(QUIT_BUTTON, /*KB_FLAG_ALT |*/ 'x', wrapper_pushbutton_func);
2138 
2139     opanel_redraw(TRUE);
2140 }
2141 
2142 //
2143 // THE SAVE GAME SCREEN: Initialization, update funcs
2144 //
2145 
save_dealfunc(uchar butid,uchar index)2146 void save_dealfunc(uchar butid, uchar index) {
2147     if (!ObjSysOkay()) {
2148         string_message_info(REF_STR_ObjSysBad);
2149         savegame_verify = index;
2150         verify_screen_init(save_verify_pushbutton_handler, save_verify_slorker);
2151     } else {
2152         message_info("");
2153         do_savegame_guts(index);
2154     }
2155 }
2156 
save_screen_init(void)2157 void save_screen_init(void) {
2158     extern uchar valid_save;
2159 
2160     clear_obuttons();
2161 
2162     textlist_init(0, *comments, NUM_SAVE_SLOTS, SAVE_COMMENT_LEN, TRUE, 0xFFFF, 0xFFFF, valid_save, REF_STR_UnusedSave,
2163                   BUTTON_COLOR, WHITE, BUTTON_COLOR + 2, REF_STR_EnterSaveString, save_dealfunc, NULL);
2164 
2165     // FIXME: Cannot pass a keycode with modifier flags as uchar
2166     keywidget_init(QUIT_BUTTON, /*KB_FLAG_ALT |*/ 'x', wrapper_pushbutton_func);
2167 
2168     opanel_redraw(TRUE);
2169 }
2170 
wrapper_start(void (* init)(void))2171 void wrapper_start(void (*init)(void)) {
2172     extern void reset_input_system(void);
2173     extern errtype change_detail_level(byte new_level);
2174 
2175     if (wrapper_panel_on)
2176         return;
2177     inv_last_page = inventory_page;
2178     if (!game_paused)
2179         pause_game_func(0, 0, 0);
2180     if (!full_game_3d)
2181         message_info("");
2182     inventory_page = -1;
2183     wrapper_panel_on = TRUE;
2184     suspend_game_time();
2185     opt_font = ResLock(OPTIONS_FONT);
2186 #ifndef STATIC_BUTTON_STORE
2187     OButtons = (opt_button *)(_offscreen_mfd.bm.bits);
2188     fv = full_visible;
2189     full_visible = 0;
2190 #endif
2191     render_run(); //move here to fix ghost mouse cursor
2192     uiHideMouse(NULL);
2193     if (full_game_3d) {
2194 #ifdef SVGA_SUPPORT
2195         uchar old_over = gr2ss_override;
2196 #endif
2197         gr_push_canvas(grd_screen_canvas);
2198 #ifdef SVGA_SUPPORT
2199         gr2ss_override = OVERRIDE_ALL;
2200 #endif
2201         ss_get_bitmap(&inv_view360_canvas.bm, GAME_MESSAGE_X, GAME_MESSAGE_Y);
2202 #ifdef SVGA_SUPPORT
2203         gr2ss_override = old_over;
2204 #endif
2205         gr_pop_canvas();
2206     } else
2207         inventory_clear();
2208     uiShowMouse(NULL);
2209     uiInstallRegionHandler(inventory_region, UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE, opanel_mouse_handler, 0,
2210                            &wrap_id);
2211     uiInstallRegionHandler(inventory_region, UI_EVENT_KBD_COOKED, opanel_kb_handler, 0, &wrap_key_id);
2212     uiGrabFocus(inventory_region, UI_EVENT_KBD_COOKED | UI_EVENT_MOUSE);
2213     region_set_invisible(inventory_region, FALSE);
2214     reset_input_system();
2215     init();
2216 }
2217 
2218 #define NEEDED_DISKSPACE 630000
check_free_diskspace(int * needed)2219 errtype check_free_diskspace(int *needed) {
2220     /*struct diskfree_t freespace;
2221     _dos_getdiskfree(0, &freespace);
2222     if (freespace.avail_clusters * freespace.sectors_per_cluster * freespace.bytes_per_sector < NEEDED_DISKSPACE)
2223     {
2224        *needed = NEEDED_DISKSPACE - (freespace.avail_clusters * freespace.sectors_per_cluster *
2225     freespace.bytes_per_sector); return(ERR_NOMEM);
2226     }
2227     *needed = 0;*/
2228     return (OK);
2229 }
2230 
do_savegame_guts(uchar slot)2231 errtype do_savegame_guts(uchar slot) {
2232     extern uchar valid_save;
2233     errtype retval = OK;
2234 
2235     begin_wait();
2236     if (!(valid_save & (1 << slot))) {
2237         int needed;
2238         //      char buf1[128],buf2[128];
2239         if (check_free_diskspace(&needed) == ERR_NOMEM) {
2240             //         lg_sprintf(buf2, get_string(REF_STR_InsufficientDisk, buf1, 128), needed);
2241             string_message_info(REF_STR_InsufficientDisk);
2242             retval = ERR_NOMEM;
2243         }
2244     }
2245     if (retval == OK) {
2246         Poke_SaveName(slot);
2247         if (save_game(save_game_name, comments[slot]) != OK) {
2248             ERROR("Save game failed!");
2249             message_info("Game save failed!");
2250             //      strcpy(comments[comment_mode], original_comment);
2251             retval = ERR_NOEFFECT;
2252             valid_save &= ~(1 << slot);
2253         } else
2254             // Spew(DSRC_EDITOR_Save, ("Game %d saved!\n", slot));
2255             if (retval == OK)
2256             valid_save |= 1 << slot;
2257     }
2258     end_wait();
2259     // spoof_mouse_event();
2260     if (retval == OK)
2261         wrapper_panel_close(TRUE);
2262     return (retval);
2263 }
2264 
2265     //#endif // NOT_YET
2266 
2267 #pragma disable_message(202)
wrapper_region_mouse_handler(uiEvent * ev,LGRegion * r,intptr_t data)2268 uchar wrapper_region_mouse_handler(uiEvent *ev, LGRegion *r, intptr_t data) {
2269     /*if (global_fullmap->cyber)
2270     {
2271        uiSetRegionDefaultCursor(r,NULL);
2272        return FALSE;
2273     }
2274     else*/
2275 
2276     uiSetRegionDefaultCursor(r, &option_cursor);
2277 
2278     if (ev->mouse_data.action & MOUSE_DOWN) {
2279         wrapper_options_func(0, 0, TRUE);
2280         return TRUE;
2281     }
2282     return FALSE;
2283 }
2284 #pragma enable_message(202)
2285 
make_options_cursor(void)2286 errtype make_options_cursor(void) {
2287     char *s;
2288     short w, h;
2289     LGPoint hot = {0, 0};
2290     grs_canvas cursor_canv;
2291     short orig_w;
2292     extern uchar svga_options_cursor_bits[];
2293     uchar old_over = gr2ss_override;
2294     gr2ss_override = OVERRIDE_ALL;
2295 
2296     orig_w = w = res_bm_width(REF_IMG_bmOptionCursor);
2297     h = res_bm_height(REF_IMG_bmOptionCursor);
2298     ss_point_convert(&w, &h, FALSE);
2299     gr_init_bm(&option_cursor_bmap, svga_options_cursor_bits, BMT_FLAT8, BMF_TRANS, w, h);
2300     gr_make_canvas(&option_cursor_bmap, &cursor_canv);
2301     gr_push_canvas(&cursor_canv);
2302     gr_clear(0);
2303     s = get_temp_string(REF_STR_ClickForOptions);
2304     gr_set_font(ResLock(OPTIONS_FONT));
2305     gr_string_wrap(s, orig_w - 3);
2306     gr_string_size(s, &w, &h);
2307     gr_set_fcolor(0xB8);
2308     ss_rect(1, 1, w + 2, h + 2);
2309     gr_set_fcolor(0xD3);
2310     ss_string(s, 2, 1);
2311     gr_font_string_unwrap(s);
2312     uiMakeBitmapCursor(&option_cursor, &option_cursor_bmap, hot);
2313     gr_pop_canvas();
2314     ResUnlock(OPTIONS_FONT);
2315     cursor_loaded = TRUE;
2316     gr2ss_override = old_over;
2317 
2318     return OK;
2319 }
2320 
2321 /*void free_options_cursor(void)
2322 {
2323 #ifndef SVGA_SUPPORT
2324    if(cursor_loaded)
2325       Free(option_cursor_bmap.bits);
2326 #endif
2327 }*/
2328 
wrapper_create_mouse_region(LGRegion * root)2329 errtype wrapper_create_mouse_region(LGRegion *root) {
2330     errtype err;
2331     int id;
2332     LGRect r = {{0, 0}, {STATUS_X, STATUS_HEIGHT}};
2333     LGRegion *reg = &(options_mouseregion[free_mouseregion++]);
2334 
2335     err = region_create(root, reg, &r, 2, 0, REG_USER_CONTROLLED | AUTODESTROY_FLAG, NULL, NULL, NULL, NULL);
2336     if (err != OK)
2337         return err;
2338     err = uiInstallRegionHandler(reg, UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE, wrapper_region_mouse_handler,
2339                                  0, &id);
2340     if (err != OK)
2341         return err;
2342     if (!cursor_loaded) {
2343         err = make_options_cursor();
2344         if (err != OK)
2345             return err;
2346     }
2347     uiSetRegionDefaultCursor(reg, &option_cursor);
2348     return OK;
2349 }
2350 
2351 //#ifdef NOT_YET //
2352 #pragma disable_message(202)
saveload_hotkey_func(ushort keycode,uint32_t context,intptr_t data)2353 uchar saveload_hotkey_func(ushort keycode, uint32_t context, intptr_t data) {
2354 #ifdef DEMO
2355     return (TRUE);
2356 #else
2357     if ((!data) && (!can_save()))
2358         return (TRUE);
2359     wrapper_start(data ? load_screen_init : save_screen_init);
2360     string_message_info(data ? REF_STR_LoadSlot : REF_STR_SaveSlot);
2361     return (TRUE);
2362 #endif
2363 }
2364 
demo_quit_func(ushort keycode,uint32_t context,intptr_t data)2365 uchar demo_quit_func(ushort keycode, uint32_t context, intptr_t data) {
2366     wrapper_start(quit_verify_init);
2367     string_message_info(REF_STR_QuitConfirm);
2368     return (TRUE);
2369 }
2370 #pragma enable_message(202)
2371 
2372 //#endif // NOT_YET
2373