FS2_Open
Open source remastering of the Freespace 2 engine
gadget.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 #include "anim/animplay.h"
13 #include "bmpman/bmpman.h"
14 #include "ui/ui.h"
15 #include "ui/uidefs.h"
16 
17 
18 // constructor
20 {
21  bm_filename = NULL;
22 }
23 
24 // destructor
26 {
27 }
28 
30 {
31  if (!linked_to_hotspot)
32  return -1;
33 
34  return hotspot_num;
35 }
36 
38 {
39  m_flags = 0;
40 }
41 
43 {
44  return hidden;
45 }
46 
47 // --------------------------------------------------------------------
48 // Links a hotspot (palette index in mask) to the given gadget.
49 //
51 {
52  hotspot_num = num;
54 }
55 
56 // --------------------------------------------------------------------
57 // Extract MAX_BMAPS_PER_CONTROL bitmaps for the different states of the control.
58 //
59 // The bitmap ids are stored in the bmap_ids[] array. If you don't want to store
60 // from the zero index, fill in the offset parameter. offset is a default parameter
61 // with a default value of zero.
62 //
63 // NOTE: The bitmaps stored in a .ani file. What each frame is used for
64 // is left up to the component to decide.
65 //
66 
67 // loads nframes bitmaps, starting at index start_frame.
68 // anything < start_frame will not be loaded.
69 // this keeps the loading code from trying to load bitmaps which don't exist
70 // and taking an unnecessary disk hit.
71 int UI_GADGET::set_bmaps(char *ani_fname, int nframes, int start_frame)
72 {
73  int first_frame, i;
74  char full_name[MAX_FILENAME_LEN] = "";
75  char tmp[33];
76  int idx, s_idx;
77  int num_digits;
78  int its_all_good = 0;
79 
80  // clear out all frames
81  for(idx=0; idx<MAX_BMAPS_PER_GADGET; idx++){
82  bmap_ids[idx] = -1;
83  }
84 
85  // load all the bitmaps
86  bm_filename = ani_fname;
87 
88  Assertion(nframes < MAX_BMAPS_PER_GADGET, "Too many frames specified (%d), must be less than MAX_BMAPS_PER_GADGET", nframes);
89  m_num_frames = nframes;
90  for(idx=start_frame; idx<nframes; idx++){
91  // clear the string
92  strcpy_s(full_name, "");
93 
94  // get the # of digits for this index
95  num_digits = (idx < 10) ? 1 : (idx < 100) ? 2 : (idx < 1000) ? 3 : 4;
96 
97  // build the actual filename
98  strcpy_s(full_name, ani_fname);
99  for(s_idx=0; s_idx<(4-num_digits); s_idx++){
100  strcat_s(full_name, NOX("0"));
101  }
102  sprintf(tmp, "%d", idx);
103  strcat_s(full_name, tmp);
104 
105  // try and load the bitmap
106  bmap_ids[idx] = bm_load(full_name);
107  if(bmap_ids[idx] != -1){
108 
109  its_all_good = 1;
110  }
111  }
112 
113  // done
114  if(its_all_good){
115  uses_bmaps = 1;
116  return 0;
117  }
118 
119  // no go, so try and load as an ani. try and load as an .ani
120  first_frame = bm_load_animation(ani_fname, &m_num_frames);
121  if((first_frame >= 0) && (m_num_frames <= MAX_BMAPS_PER_GADGET)){
122  // seems pretty stupid that we didn't just use a variable for the first frame and access all
123  // other frames offset from it instead of accessing this bmap_ids[] array, but probably too
124  // much trouble to go through and change this anymore. How sad..
125  for ( i=0; i<m_num_frames; i++ ) {
126  bmap_ids[i] = first_frame + i;
127  }
128  }
129 
130  // flag that this control is using bitmaps for art
131  uses_bmaps = 1;
132  return 0;
133 }
134 
135 // Handle drawing of all children of the gadget. Since this the base of all other gadgets,
136 // it doesn't have any look to it (kind of like a soul. Can you see someone's soul?) and thus
137 // doesn't actually render itself.
138 //
140 {
141  UI_GADGET *cur;
142 
143  // if hidden, hide children as well
144  if (hidden){
145  return;
146  }
147 
148  if (children) {
149  cur = children;
150  do {
151  cur->draw();
152  cur = cur->next;
153 
154  } while (cur != children);
155  }
156 }
157 
158 // Free up bitmaps used by the gadget, and call children to destroy themselves as well.
159 //
161 {
162  int i;
163  UI_GADGET *cur;
164 
165  for ( i=0; i<m_num_frames; i++ ) {
166  if (bmap_ids[i] != -1) {
167  // we need to unload here rather than release since some controls
168  // may still need access to the bitmap slot. if it can be released
169  // then the child should do it - taylor
170  bm_unload(bmap_ids[i]);
171  bmap_ids[i] = -1;
172  }
173  }
174 
175  if (children) {
176  cur = children;
177  do {
178  cur->destroy();
179  cur = cur->next;
180 
181  } while (cur != children);
182  }
183 }
184 
185 // Use this if you need to change the size and position of a gadget after you have created it.
186 //
187 void UI_GADGET::update_dimensions(int _x, int _y, int _w, int _h)
188 {
189  if ( _x != -1 ) x = _x;
190  if ( _y != -1 ) y = _y;
191  if ( _w != -1 ) w = _w;
192  if ( _h != -1 ) h = _h;
193 }
194 
195 void UI_GADGET::get_dimensions(int *x_, int *y_, int *w_, int *h_)
196 {
197  *x_ = x;
198  *y_ = y;
199  *w_ = w;
200  *h_ = h;
201 }
202 
203 // Hide (or show) a gadget.
204 // n != 0: Hide gadget
205 // n == 0: Show gadget
206 //
208 {
209  hidden = n ? 1 : 0;
210 }
211 
213 {
214  hidden = 1;
215 }
216 
218 {
219  hidden = 0;
220 }
221 
222 // Capture mouse with this gadget, which basically means only this gadget will get process()
223 // called on it until the mouse button 1 is released.
224 //
226 {
227  my_wnd->capture_mouse(this);
228 }
229 
230 // Check if (return true if):
231 // mouse_captured(): this gadget has the mouse captured.
232 // mouse_captured(x): gadget x has the mouse captured.
233 //
235 {
236  if (!gadget)
237  gadget = this;
238 
239  return (my_wnd->mouse_captured_gadget == gadget);
240 }
241 
242 // Set up the gadget and registers it with the UI window
243 //
244 void UI_GADGET::base_create(UI_WINDOW *wnd, int _kind, int _x, int _y, int _w, int _h)
245 {
246  int i;
247 
248  // initialize data with passed values
249  kind = _kind;
250  x = _x;
251  y = _y;
252  w = _w;
253  h = _h;
254 
255  // set up reference to UI window and initialize as having no family
256  my_wnd = wnd;
257  parent = NULL;
258  children = NULL;
259  next = prev = this;
260 
261  // this actually links the gadget into the UI window's top level family (as the youngest gadget)
262  set_parent(NULL);
263 
264  // initialize variables
265  hotkey = -1;
266  user_function = NULL;
267  disabled_flag = 0;
268  base_dragging = 0;
269  base_drag_x = base_drag_y = 0;
270  hotspot_num = -1;
271  hidden = 0;
272  linked_to_hotspot = 0;
273  uses_bmaps = 0;
274  m_num_frames = 0;
275  for ( i=0; i<MAX_BMAPS_PER_GADGET; i++ ) {
276  bmap_ids[i] = -1;
277  }
278 }
279 
281 {
282  hotkey = key;
283 }
284 
285 // Far as I can tell, the callback function is handled differently for each gadget type, if
286 // handled by a given gadget type at all.
287 //
288 void UI_GADGET::set_callback(void (*_user_function)(void))
289 {
290  user_function = _user_function;
291 }
292 
293 // get the next enabled gadget in sibling list or self if none
294 //
296 {
297  UI_GADGET *tmp;
298 
299  tmp = next;
300  while ((tmp != this) && tmp->disabled_flag)
301  tmp = tmp->next;
302 
303  return tmp;
304 }
305 
306 // get the previous enabled gadget in sibling list or self if none
307 //
309 {
310  UI_GADGET *tmp;
311 
312  tmp = prev;
313  while ((tmp != this) && tmp->disabled_flag)
314  tmp = tmp->prev;
315 
316  return tmp;
317 }
318 
319 // Set this gadget as the focus (selected gadget) of the UI window
320 //
322 {
323  my_wnd->selected_gadget = this;
324 }
325 
326 // Make no gadget have focus in the UI window.
327 //
329 {
330  my_wnd->selected_gadget = NULL;
331 }
332 
333 // Return true or false if this gadget currently has the focus
335 {
336  return my_wnd->selected_gadget == this ? 1 : 0;
337 }
338 
339 // get mouse pointer position relative to gadget's origin (UL corner)
340 //
341 void UI_GADGET::get_mouse_pos(int *xx, int *yy)
342 {
343  if (xx)
344  *xx = ui_mouse.x - x;
345  if (yy)
346  *yy = ui_mouse.y - y;
347 }
348 
349 // Call process() for all children of gadget. As a base gadget for all other gadget types,
350 // it doesn't actually do anything for itself.
351 //
352 void UI_GADGET::process(int focus)
353 {
354  UI_GADGET *tmp;
355 
356  if (disabled_flag)
357  return;
358 
359  tmp = children; // process all children of gadget
360  if (tmp) {
361  do {
362  tmp->process();
363  tmp = tmp->next;
364 
365  } while (tmp != children);
366  }
367 }
368 
369 // Check if the mouse is over the gadget's area or not,
370 //
372 {
373  int offset, pixel_val;
374  ubyte *mask_data;
375  int mask_w, mask_h;
376 
377  // if linked to a hotspot, use the mask for determination
378  if (linked_to_hotspot) {
379  mask_data = (ubyte*)my_wnd->get_mask_data(&mask_w, &mask_h);
380  if ( mask_data == NULL ) {
381  nprintf(("Warning", "No mask defined, but control is linked to hotspot\n"));
382  Int3();
383  return 0;
384  }
385 
386  // if the mouse values are out of range of the bitmap
387  // NOTE : this happens when using smaller mask bitmaps than the screen resolution (during development)
388  if((ui_mouse.x < 0) || (ui_mouse.x >= mask_w) || (ui_mouse.y < 0) || (ui_mouse.y >= mask_h)){
389  return 0;
390  }
391 
392  // check the pixel value under the mouse
393  offset = ui_mouse.y * mask_w + ui_mouse.x;
394  pixel_val = *(mask_data + offset);
395  if (pixel_val == hotspot_num){
396  return 1;
397  } else {
398  return 0;
399  }
400  // otherwise, we just check the bounding box area
401  } else {
402  if ((ui_mouse.x >= x) && (ui_mouse.x < x + w) && (ui_mouse.y >= y) && (ui_mouse.y < y + h) ){
403  return 1;
404  } else {
405  return 0;
406  }
407  }
408 }
409 
410 // check if mouse is over any child of this gadget
411 //
413 {
414  UI_GADGET *tmp;
415 
416  tmp = children;
417  if (tmp) {
418  do {
419  if (tmp->is_mouse_on())
420  return 1;
421  if (tmp->is_mouse_on_children())
422  return 1;
423 
424  tmp = tmp->next;
425 
426  } while (tmp != children);
427  }
428 
429  return 0;
430 }
431 
433 {
434  disabled_flag = 1;
435 }
436 
437 // Enables (or possibly disables) the gadget. n is an optional argument. If not supplied,
438 // enables the garget. If supplied, enables garget if n is true, disables it if n is false.
439 //
441 {
442  disabled_flag = n ? 0 : 1;
443 }
444 
445 // Check if gadget is disabled
446 //
448 {
449  return disabled_flag;
450 }
451 
452 // Check if gadget is enabled
453 //
455 {
456  return !disabled_flag;
457 }
458 
459 void UI_GADGET::drag_with_children( int dx, int dy )
460 {
461  UI_GADGET *tmp;
462 
463  x = dx + base_start_x;
464  y = dy + base_start_y;
465 
466  tmp = children;
467  if (tmp) {
468  do {
469  tmp->drag_with_children(dx, dy);
470  tmp = tmp->next;
471 
472  } while (tmp != children);
473  }
474 }
475 
477 {
478  UI_GADGET *tmp;
479 
480  base_dragging = 1;
481  base_start_x = x;
482  base_start_y = y;
483 
484  tmp = children;
485  if (tmp) {
486  do {
488  tmp = tmp->next;
489 
490  } while (tmp != children);
491  }
492 }
493 
495 {
496  UI_GADGET *tmp;
497 
498  base_dragging = 0;
499  tmp = children;
500  if (tmp) {
501  do {
503  tmp = tmp->next;
504 
505  } while (tmp != children);
506  }
507 }
508 
509 // Returns 1 if moving
511 {
512  #if 0
513  if ( parent != NULL ) return base_dragging;
514 
515  if ( !base_dragging ) {
516 
517  if ( B2_JUST_PRESSED ) {
518  if ( is_mouse_on() || is_mouse_on_children() ) {
522  return 1;
523  } else {
524  return 0;
525  }
526  } else
527  return 0;
528  } else {
530  nprintf(( "UI", "UI: X=%d, Y=%d, Delta=(%d,%d)\n", x, y, (ui_mouse.x - base_drag_x), (ui_mouse.y - base_drag_y) ));
531  if (B2_RELEASED) {
533  }
534  return 1;
535  }
536  #endif
537  return 0;
538 }
539 
540 // Take gadget out of family. Children of this gadget stay with gadget, though.
541 //
542 // A family is basically the whole parent/sibling/children hierarchy for gadgets. Any gadget
543 // that is linked to another gadget by one of these pointers is said to be in the same family
544 // as that gadget. This function, therefore, caused all references to a gadget by it's
545 // family's gadgets' sibling or children pointers to be broken, and all references to any of them
546 // by this gadget's parent or sibling pointers to also be broken. This isolates the gadget and
547 // it's children into a new family.
548 //
550 {
551  if (parent) {
552  if (parent->children == this) {
553  if (next == this) // an only child?
554  parent->children = NULL; // if so, parent now has no children
555  else
556  parent->children = next; // next sibling is now the eldest
557  }
558 
559  } else {
560  if (my_wnd->first_gadget == this) {
561  if (next == this) // an only child?
562  my_wnd->first_gadget = NULL; // if so, parent now has no children
563  else
564  my_wnd->first_gadget = next; // next sibling is now the eldest
565  }
566  }
567 
568  parent = NULL;
569  if (next != this) { // does gadget have siblings?
570  next->prev = prev;
571  prev->next = next;
572  }
573 
574  next = prev = this;
575 }
576 
577 // Put gadget into a new family (removing from old one if needed first).
578 // See remove_from_family() for definition of what a family is.
579 //
581 {
583  parent = daddy;
584 
585  if (!daddy) {
586  if (!my_wnd->first_gadget) {
587  my_wnd->first_gadget = this;
588 
589  } else {
590  UI_GADGET *eldest_sibling, *youngest_sibling;
591 
592  eldest_sibling = my_wnd->first_gadget;
593  youngest_sibling = eldest_sibling->prev;
594 
595  next = eldest_sibling;
596  prev = youngest_sibling;
597 
598  eldest_sibling->prev = this;
599  youngest_sibling->next = this;
600  }
601 
602  return;
603  }
604 
605  if (!daddy->children) {
606  daddy->children = this;
607 
608  } else {
609  UI_GADGET *eldest_sibling, *youngest_sibling;
610 
611  eldest_sibling = daddy->children;
612  youngest_sibling = eldest_sibling->prev;
613 
614  next = eldest_sibling;
615  prev = youngest_sibling->prev;
616 
617  eldest_sibling->prev = this;
618  youngest_sibling->next = this;
619  }
620 }
UI_GADGET * get_next()
Definition: gadget.cpp:295
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
int enabled()
Definition: gadget.cpp:454
int i
Definition: multi_pxo.cpp:466
void reset()
Definition: gadget.cpp:37
virtual ~UI_GADGET()
Definition: gadget.cpp:25
int hotkey
Definition: ui.h:78
GLfloat GLfloat GLfloat GLfloat h
Definition: Glext.h:7280
int base_start_x
Definition: ui.h:85
virtual void process(int focus=0)
Definition: gadget.cpp:352
int is_mouse_on()
Definition: gadget.cpp:371
int base_start_y
Definition: ui.h:85
int mouse_captured(UI_GADGET *gadget=NULL)
Definition: gadget.cpp:234
int check_move()
Definition: gadget.cpp:510
UI_WINDOW * my_wnd
Definition: ui.h:111
char * bm_filename
Definition: ui.h:76
int bmap_ids[MAX_BMAPS_PER_GADGET]
Definition: ui.h:118
virtual void unhide()
Definition: gadget.cpp:217
UI_GADGET * children
Definition: ui.h:101
Definition: ui.h:61
void clear_focus()
Definition: gadget.cpp:328
void set_focus()
Definition: gadget.cpp:321
void base_create(UI_WINDOW *wnd, int _kind, int _x, int _y, int _w, int _h)
Definition: gadget.cpp:244
#define Assertion(expr, msg,...)
Definition: clang.h:41
void set_callback(void(*_user_function)(void))
Definition: gadget.cpp:288
int h
Definition: ui.h:79
int key
#define Int3()
Definition: pstypes.h:292
int linked_to_hotspot
Definition: ui.h:89
UI_GADGET()
Definition: gadget.cpp:19
UI_GADGET * prev
Definition: ui.h:102
int hotspot_num
Definition: ui.h:90
int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type)
Loads a bitmap sequance so we can draw with it.
Definition: bmpman.cpp:1420
int m_num_frames
Definition: ui.h:94
UI_MOUSE ui_mouse
Definition: uimouse.cpp:17
#define B2_JUST_PRESSED
Definition: uidefs.h:55
UI_GADGET * first_gadget
Definition: ui.h:609
int y
Definition: uidefs.h:59
int set_bmaps(char *ani_filename, int nframes=3, int start_frame=1)
Definition: gadget.cpp:71
virtual void destroy()
Definition: gadget.cpp:160
GLintptr offset
Definition: Glext.h:5497
int base_dragging
Definition: ui.h:83
UI_GADGET * mouse_captured_gadget
Definition: ui.h:611
void get_dimensions(int *_x, int *_y, int *_w, int *_h)
Definition: gadget.cpp:195
#define nprintf(args)
Definition: pstypes.h:239
int w
Definition: ui.h:79
int disabled()
Definition: gadget.cpp:447
int y
Definition: ui.h:79
int x
Definition: ui.h:79
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
int base_drag_y
Definition: ui.h:84
UI_GADGET * next
Definition: ui.h:103
void remove_from_family()
Definition: gadget.cpp:549
int idx
Definition: multiui.cpp:761
#define MAX_BMAPS_PER_GADGET
Definition: ui.h:33
GLint GLint GLint GLint GLint x
Definition: Glext.h:5182
int uses_bmaps
Definition: ui.h:93
GLclampd n
Definition: Glext.h:7286
unsigned char ubyte
Definition: pstypes.h:62
int x
Definition: uidefs.h:59
int base_drag_x
Definition: ui.h:84
int is_mouse_on_children()
Definition: gadget.cpp:412
#define NOX(s)
Definition: pstypes.h:473
#define B2_RELEASED
Definition: uidefs.h:54
UI_GADGET * get_prev()
Definition: gadget.cpp:308
void set_hotkey(int keycode)
Definition: gadget.cpp:280
int get_hotspot()
Definition: gadget.cpp:29
void capture_mouse()
Definition: gadget.cpp:225
int hidden
Definition: ui.h:86
int bm_load(const char *real_filename)
Loads a bitmap so we can draw with it later.
Definition: bmpman.cpp:1119
int disabled_flag
Definition: ui.h:82
void update_dimensions(int _x, int _y, int _w, int _h)
Definition: gadget.cpp:187
void set_parent(UI_GADGET *_parent)
Definition: gadget.cpp:580
GLuint GLuint num
Definition: Glext.h:9089
UI_GADGET * parent
Definition: ui.h:100
void link_hotspot(int num)
Definition: gadget.cpp:50
ubyte * get_mask_data(int *w_md, int *h_md)
Definition: ui.h:643
#define strcat_s(...)
Definition: safe_strings.h:68
GLubyte GLubyte GLubyte GLubyte w
Definition: Glext.h:5679
int m_flags
Definition: ui.h:80
int kind
Definition: ui.h:77
Definition: ui.h:584
void capture_mouse(UI_GADGET *gadget=NULL)
Definition: window.cpp:466
void enable(int n=1)
Definition: gadget.cpp:440
virtual void hide()
Definition: gadget.cpp:212
void start_drag_with_children()
Definition: gadget.cpp:476
void drag_with_children(int dx, int dy)
Definition: gadget.cpp:459
int has_focus()
Definition: gadget.cpp:334
void get_mouse_pos(int *xx, int *yy)
Definition: gadget.cpp:341
void stop_drag_with_children()
Definition: gadget.cpp:494
void(* user_function)(void)
Definition: ui.h:81
int bm_unload(int handle, int clear_render_targets, bool nodebug)
Unloads a bitmap's data, but not the bitmap info.
Definition: bmpman.cpp:2890
void disable()
Definition: gadget.cpp:432
virtual void draw()
Definition: gadget.cpp:139
virtual int is_hidden()
Definition: gadget.cpp:42
GLint y
Definition: Gl.h:1505
#define strcpy_s(...)
Definition: safe_strings.h:67
UI_GADGET * selected_gadget
Definition: ui.h:610