FS2_Open
Open source remastering of the Freespace 2 engine
listbox.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 "globalincs/alphacolors.h"
13 #include "io/timer.h"
14 #include "ui/ui.h"
15 #include "ui/uidefs.h"
16 
17 
18 #define KEY_BUFFER_TIMEOUT 1000 // time to clear buffer in milliseconds
19 
20 #define DEFAULT_LISTBOX_ITEM_LENGTH 128
21 
22 // --------------------------------------------------------------------
23 // UI_LISTBOX::link_hotspot
24 //
25 //
26 void UI_LISTBOX::link_hotspot(int up_button_num, int down_button_num)
27 {
28  scrollbar.link_hotspot(up_button_num,down_button_num);
29 }
30 
31 // --------------------------------------------------------------------
32 // UI_LISTBOX::set_bmaps
33 //
34 // Call the UI_SCROLLBAR::set_bmaps() function for the scroll bar gadget.
35 //
36 // returns: -1 ==> error
37 // 0 ==> success
38 //
39 int UI_LISTBOX::set_bmaps(char *lbox_fname, char *b_up_fname, char *b_down_fname, char *sb_fname)
40 {
41  if (has_scrollbar) {
42  scrollbar.set_bmaps(b_up_fname, b_down_fname, sb_fname);
43  }
44 
45  // set the bitmaps for the list box rectangle
46  UI_GADGET::set_bmaps(lbox_fname);
47  uses_bmaps = 1;
48  return 0;
49 }
50 
51 void UI_LISTBOX::create(UI_WINDOW *wnd, int _x, int _y, int _w, int _h, int _numitems, char **_list, char *_check_list, int _max_items)
52 {
53 
54  int tw, th, nrows;
55  int real_h;
56 
57  gr_set_font(wnd->f_id);
58  gr_get_string_size(&tw, &th, "*");
59 
60  nrows = _h / th;
61  real_h = nrows * th;
62 
63  base_create( wnd, UI_KIND_LISTBOX, _x, _y, _w, real_h );
64 
65  max_items = _max_items;
66  list = _list;
67  num_items = _numitems;
68  check_list = _check_list;
69  num_items_displayed = nrows;
70 
71  first_item = 0;
72  current_item = -1;
73  toggled_item = -1;
74  last_scrolled = 0;
75  textheight = th;
76  dragging = 0;
77  selected_item = -1;
78  key_buffer_count = 0;
79  last_typed = timer_get_milliseconds();
80 
81  if (_numitems > nrows) {
82  scrollbar.create( wnd, _x+_w+3, _y, real_h, 0, _numitems-nrows, 0, nrows );
83  scrollbar.set_parent(this);
84  has_scrollbar = 1;
85 
86  } else {
87  has_scrollbar = 0;
88  }
89 
90  // kazan
91  draw_frame = 1;
92 }
93 
94 
96 {
97  draw_frame = mode;
98 }
99 
100 void UI_LISTBOX::draw()
101 {
102  int i, x1, y1, stop;
103  int w1, h1;
104 
105  UI_GADGET::draw();
107 
108  if (uses_bmaps) {
109  if (disabled_flag) {
110  if ( bmap_ids[LBOX_DISABLED] >= 0 ) {
111  gr_set_bitmap(bmap_ids[LBOX_DISABLED]);
113  }
114 
115  } else {
116  if ( bmap_ids[LBOX_NORMAL] >= 0 ) {
117  gr_set_bitmap(bmap_ids[LBOX_NORMAL]);
119  }
120  }
121 
122  } else {
124  gr_set_clip( x, y, w, h, GR_RESIZE_MENU );
125  ui_rect( 0, 0, w-1, h-1 );
126  gr_reset_clip();
127  if (draw_frame)
128  {
129  if (has_scrollbar) {
130  ui_draw_sunken_border( x-2, y-2, x+w+scrollbar.w+4, y+h+1 );
131 
132  } else {
133  ui_draw_sunken_border( x-2, y-2, x+w+4, y+h+1 );
134  }
135  }
136  }
137 
138  stop = first_item+num_items_displayed;
139  if (stop>num_items) stop = num_items;
140 
141  x1 = y1 = 0;
142  gr_set_clip( x, y, w, h, GR_RESIZE_MENU );
143 
144  for ( i=first_item; i<stop; i++ ) {
145  gr_get_string_size( &w1, &h1,list[i] );
146 
147  if (check_list)
148  w1 += 18;
149 
150  if (i !=current_item) {
151 /*
152  if ((current_item == -1) && (my_wnd->selected_gadget == this ) && (i == first_item) ) {
153  if ( !uses_bmaps ) {
154  gr_set_color_fast( &CBLACK );
155  gr_rect( x1, y1, w1+2, h1, GR_RESIZE_MENU_NO_OFFSET );
156  }
157  current_item = first_item;
158  gr_set_color_fast( &CBRIGHT_GREEN );
159  } else {
160  if ( !uses_bmaps ) {
161  gr_set_color_fast( &CBLACK );
162  gr_rect( x1, y1, w1+2, h1, GR_RESIZE_MENU_NO_OFFSET );
163  }
164  gr_set_color_fast( &CWHITE );
165  }
166 */
167  if (!uses_bmaps) {
169  gr_rect( x1, y1, w1+2, h1, GR_RESIZE_MENU_NO_OFFSET );
170  }
171 
173 
174  } else {
175  if (my_wnd->selected_gadget == this) {
177  gr_rect( x1, y1, w1+2, h1, GR_RESIZE_MENU_NO_OFFSET );
179 
180  } else {
182  gr_rect( x1, y1, w1+2, h1, GR_RESIZE_MENU_NO_OFFSET );
184  }
185  }
186 
187  if ( check_list ) {
188  if ( check_list[i] ) {
189  gr_string( x1+2, y1, "X", GR_RESIZE_MENU );
190  }
191 
192  gr_string( x1+16, y1, list[i], GR_RESIZE_MENU );
193 
194  } else
195  gr_string( x1+2, y1, list[i], GR_RESIZE_MENU );
196 
197  if (i==current_item)
199  else
201 
202  if ( !uses_bmaps ) {
203  ui_rect( x1+w1+2, y1, w-1, y1+h1-1 );
204  ui_rect( x1, y1, x1+1, y1+h1-1 );
205  }
206 
207  y1 += h1;
208  }
209 
210  if (stop < num_items_displayed-1 && !uses_bmaps) {
212  ui_rect( x1, y1, w-1, h-1 );
213  }
214 }
215 
216 void UI_LISTBOX::process(int focus)
217 {
218  int OnMe, mitem, kf = 0;
219  int i, j;
220 
221  selected_item = -1;
222  toggled_item = -1;
223 
224  if (disabled_flag)
225  return;
226 
227  if (my_wnd->selected_gadget == this)
228  focus = 1;
229 
230  if (has_scrollbar) {
231  scrollbar.process(0);
232  if (my_wnd->selected_gadget == &scrollbar) {
233  set_focus();
234  focus = 1;
235  }
236  }
237 
238  if (num_items < 1) {
239  current_item = -1;
240  first_item = 0;
241  old_current_item = current_item;
242  old_first_item = first_item;
243 
244 // if (my_wnd->selected_gadget == this) {
245 // my_wnd->selected_gadget == get_next();
246 // }
247 
248  return;
249  }
250 
251  old_current_item = current_item;
252  old_first_item = first_item;
253 
254  OnMe = is_mouse_on();
255 
256  if (has_scrollbar) {
257  if (scrollbar.moved) {
258  first_item = scrollbar.position;
259  Assert(first_item >= 0);
260 
261  if (current_item<first_item)
262  current_item = first_item;
263 
264  if (current_item > first_item + num_items_displayed - 1)
265  current_item = first_item + num_items_displayed - 1;
266  }
267  }
268 
269  if (!B1_PRESSED)
270  dragging = 0;
271 
272  if (B1_PRESSED && OnMe) {
273  set_focus();
274  dragging = 1;
275  }
276 
277  if ( key_buffer_count && (timer_get_milliseconds() > last_typed + KEY_BUFFER_TIMEOUT) )
278  key_buffer_count = 0;
279 
280  if (focus) {
281  if (my_wnd->keypress) {
282  kf = 0;
283 
284  switch (my_wnd->keypress) {
285  case KEY_ENTER:
286  selected_item = current_item;
287  break;
288 
289  case KEY_SPACEBAR:
290  toggled_item = current_item;
291  break;
292 
293  case KEY_UP:
294  current_item--;
295  kf = 1;
296  break;
297 
298  case KEY_DOWN:
299  current_item++;
300  kf = 1;
301  break;
302 
303  case KEY_HOME:
304  current_item = 0;
305  kf = 1;
306  break;
307 
308  case KEY_END:
309  current_item=num_items - 1;
310  kf = 1;
311  break;
312 
313  case KEY_PAGEUP:
314  current_item -= num_items_displayed;
315  kf = 1;
316  break;
317 
318  case KEY_PAGEDOWN:
319  current_item += num_items_displayed;
320  kf = 1;
321  break;
322 
323  default: // enter the key in the key buffer
324  if (my_wnd->keypress == KEY_BACKSP) {
325  key_buffer_count = 0;
326 
327  } else if (key_buffer_count < MAX_KEY_BUFFER) {
328  key_buffer[key_buffer_count++] = (char) my_wnd->keypress;
329  last_typed = timer_get_milliseconds();
330  }
331 
332  if (!key_buffer_count)
333  break;
334 
335  for (i=0; i<num_items; i++) {
336  char *current_text;
337 
338  current_text = get_string(i);
339  for (j=0; j<key_buffer_count; j++)
340  if ( (current_text[j] != ascii_table[key_buffer[j]]) && (current_text[j] != shifted_ascii_table[key_buffer[j]]) )
341  break;
342 
343  if (j == key_buffer_count) {
344  set_first_item(i - num_items_displayed / 2);
345  set_current(i);
346  break;
347  }
348  }
349  }
350  }
351 
352  if (kf == 1) {
353  if (current_item < 0)
354  current_item = 0;
355 
356  if (current_item >= num_items)
357  current_item = num_items - 1;
358 
359  if (current_item < first_item)
360  first_item = current_item;
361 
362  if (current_item >= first_item + num_items_displayed)
363  first_item = current_item - num_items_displayed + 1;
364 
365  if (num_items <= num_items_displayed ) {
366  first_item = 0;
367 
368  } else {
369  if (has_scrollbar) {
370  scrollbar.position = first_item;
371 
372  scrollbar.bar_position = scrollbar.position - scrollbar.start;
373  scrollbar.bar_position *= scrollbar.h - scrollbar.bar_size;
374  scrollbar.bar_position /= scrollbar.stop - scrollbar.start;
375 
376  if (scrollbar.bar_position < 0) {
377  scrollbar.bar_position = 0;
378  }
379 
380  if (scrollbar.bar_position > scrollbar.h - scrollbar.bar_size) {
381  scrollbar.bar_position = scrollbar.h - scrollbar.bar_size;
382  }
383  }
384 
385  }
386  }
387  }
388 
389  if (focus) {
390  if (B1_PRESSED && dragging) {
391  if (ui_mouse.y < y )
392  mitem = -1;
393  else
394  mitem = (ui_mouse.y - y)/textheight;
395 
396  if ( (mitem < 0) && (timer_get_milliseconds() > last_scrolled + 1000 / 18) ) {
397  current_item--;
398  last_scrolled = timer_get_milliseconds();
399  }
400 
401  if ( (mitem >= num_items_displayed) && (timer_get_milliseconds() > last_scrolled + 1000 / 18) ) {
402  current_item++;
403  last_scrolled = timer_get_milliseconds();
404  }
405 
406  if ((mitem >= 0) && (mitem<num_items_displayed)) {
407  current_item = mitem + first_item;
408  }
409 
410  if (current_item < 0)
411  current_item = 0;
412 
413  if (current_item >= num_items)
414  current_item = num_items - 1;
415 
416  if (current_item < first_item)
417  first_item = current_item;
418 
419  if (current_item >= first_item + num_items_displayed)
420  first_item = current_item - num_items_displayed + 1;
421 
422  if (num_items <= num_items_displayed) {
423  first_item = 0;
424 
425  } else if (has_scrollbar) {
426  scrollbar.position = first_item;
427 
428  scrollbar.bar_position = scrollbar.position - scrollbar.start;
429  scrollbar.bar_position *= scrollbar.h - scrollbar.bar_size;
430  scrollbar.bar_position /= scrollbar.stop - scrollbar.start;
431 
432  if (scrollbar.bar_position < 0) {
433  scrollbar.bar_position = 0;
434  }
435 
436  if (scrollbar.bar_position > scrollbar.h - scrollbar.bar_size) {
437  scrollbar.bar_position = scrollbar.h - scrollbar.bar_size;
438  }
439  }
440  }
441 
442  if (check_list) {
443  if (B1_JUST_RELEASED)
444  toggled_item = current_item;
445  }
446 
447  if (B1_DOUBLE_CLICKED) {
448  selected_item = current_item;
449  }
450  }
451 }
452 
454 {
455  if (check_list) {
456  return toggled_item;
457  } else {
458  return -1;
459  }
460 }
461 
463 {
464  if (check_list) {
465  return -1;
466  } else {
467  return selected_item;
468  }
469 }
470 
472 {
473  return current_item;
474 }
475 
476 void UI_LISTBOX::set_current(int _index)
477 {
478  current_item = _index;
479 }
480 
482 {
483  if (_index < 0)
484  _index = 0;
485  else if (_index > num_items)
486  _index = num_items;
487 
488  first_item = _index;
489 }
490 
491 char *UI_LISTBOX::get_string(int _index)
492 {
493  return list[_index];
494 }
495 
497 {
498  int idx;
499 
500  for ( idx=0; idx<num_items; idx++ )
501  list[idx][0] = 0;
502 
503  num_items = 0;
504  first_item = 0;
505 }
506 
507 void UI_LISTBOX::set_new_list(int _numitems, char **_list)
508 {
509  num_items = _numitems;
510  list = _list;
511  current_item = 0;
512 }
513 
515 {
516  if (num_items > num_items_displayed)
517  first_item = num_items - num_items_displayed + 1;
518 }
519 
521 {
522  for (int i = 0; i < num_items-1; i++)
523  list[i] = list[i+1];
524  num_items--;
525 }
526 
528 {
529  return max_items;
530 }
531 
533 {
534  return num_items;
535 }
536 
538 {
539  if (max_items < 0) // only if we created an "empty" listbox can we add items
540  return 0;
541 
542  else {
543  if ( (num_items == max_items - 1) || (strlen(str) > DEFAULT_LISTBOX_ITEM_LENGTH) )
544  return 0; // we've reached our limit
545 
546  else {
547  list[num_items] = vm_strdup(str);
548  num_items++;
549  return 1;
550  }
551  }
552 }
553 
555 {
556  return old_current_item == current_item ? 0 : 1;
557 }
void gr_rect(int x, int y, int w, int h, int resize_mode)
Definition: 2d.cpp:2068
void set_first_item(int _index)
Definition: listbox.cpp:481
int i
Definition: multi_pxo.cpp:466
#define GR_RESIZE_MENU_NO_OFFSET
Definition: 2d.h:686
#define KEY_DOWN
Definition: key.h:180
GLfloat GLfloat GLfloat GLfloat h
Definition: Glext.h:7280
#define KEY_PAGEDOWN
Definition: key.h:178
int is_mouse_on()
Definition: gadget.cpp:371
#define GR_RESIZE_MENU
Definition: 2d.h:684
UI_WINDOW * my_wnd
Definition: ui.h:111
int bmap_ids[MAX_BMAPS_PER_GADGET]
Definition: ui.h:118
Assert(pm!=NULL)
__inline void gr_string(int x, int y, const char *string, int resize_mode=GR_RESIZE_FULL)
Definition: 2d.h:769
#define MAX_KEY_BUFFER
Definition: ui.h:31
void create(UI_WINDOW *wnd, int _x, int _y, int _w, int _h, int _numitem, char **_list, char *_check_list=NULL, int _max_items=-1)
Definition: listbox.cpp:51
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
int h
Definition: ui.h:79
GLenum mode
Definition: Glext.h:5794
void gr_set_color_fast(color *dst)
Definition: 2d.cpp:1197
#define KEY_PAGEUP
Definition: key.h:175
void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha)
Definition: 2d.cpp:2105
void create(UI_WINDOW *wnd, int _x, int _y, int _h, int _start, int _stop, int _position, int _window_size)
Definition: scroll.cpp:73
#define B1_JUST_RELEASED
Definition: uidefs.h:50
UI_MOUSE ui_mouse
Definition: uimouse.cpp:17
__inline void gr_set_clip(int x, int y, int w, int h, int resize_mode=GR_RESIZE_FULL)
Definition: 2d.h:741
void ScrollEnd()
Definition: listbox.cpp:514
int y
Definition: uidefs.h:59
#define gr_reset_clip
Definition: 2d.h:745
int set_bmaps(char *ani_filename, int nframes=3, int start_frame=1)
Definition: gadget.cpp:71
void set_drawframe(int mode)
Definition: listbox.cpp:95
void set_current(int _index)
Definition: listbox.cpp:476
#define CWHITE
Definition: uidefs.h:25
int w
Definition: ui.h:79
int y
Definition: ui.h:79
void link_hotspot(int up_button_num, int down_button_num)
Definition: scroll.cpp:23
void ui_draw_sunken_border(int x1, int y1, int x2, int y2)
Definition: uidraw.cpp:106
#define KEY_ENTER
Definition: key.h:125
#define CGRAY
Definition: uidefs.h:23
#define vm_strdup(ptr)
Definition: pstypes.h:549
char * get_string(int _index)
Definition: listbox.cpp:491
#define CBLACK
Definition: uidefs.h:20
#define KEY_BACKSP
Definition: key.h:126
int idx
Definition: multiui.cpp:761
#define B1_DOUBLE_CLICKED
Definition: uidefs.h:51
void RemoveFirstItem()
Definition: listbox.cpp:520
int add_string(char *str)
Definition: listbox.cpp:537
int shifted_ascii_table[128]
Definition: key.cpp:83
GLint GLint GLint GLint GLint x
Definition: Glext.h:5182
int uses_bmaps
Definition: ui.h:93
#define CBRIGHT_GREEN
Definition: uidefs.h:22
int CurSize()
Definition: listbox.cpp:532
#define KEY_END
Definition: key.h:177
int MaxSize()
Definition: listbox.cpp:527
#define B1_PRESSED
Definition: uidefs.h:47
int disabled_flag
Definition: ui.h:82
int set_bmaps(char *up_button_fname, char *down_button_fname, char *line_fname)
Definition: scroll.cpp:42
void set_parent(UI_GADGET *_parent)
Definition: gadget.cpp:580
int sel_changed()
Definition: listbox.cpp:554
GLubyte GLubyte GLubyte GLubyte w
Definition: Glext.h:5679
#define KEY_BUFFER_TIMEOUT
Definition: listbox.cpp:18
#define UI_KIND_LISTBOX
Definition: ui.h:23
Definition: ui.h:584
void gr_get_string_size(int *w, int *h, const char *text, int len=9999)
Definition: font.cpp:196
int set_bmaps(char *lbox_fname, char *b_up_fname, char *b_down_fname, char *sb_fname)
Definition: listbox.cpp:39
void ui_rect(int x1, int y1, int x2, int y2)
Definition: uidraw.cpp:64
void clear_all_items()
Definition: listbox.cpp:496
int selected()
Definition: listbox.cpp:462
#define KEY_SPACEBAR
Definition: key.h:128
void set_new_list(int _numitems, char **_list)
Definition: listbox.cpp:507
void gr_bitmap(int _x, int _y, int resize_mode)
Definition: 2d.cpp:1303
#define KEY_UP
Definition: key.h:179
#define DEFAULT_LISTBOX_ITEM_LENGTH
Definition: listbox.cpp:20
#define KEY_HOME
Definition: key.h:174
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble w1
Definition: Glext.h:7779
void gr_set_font(int fontnum)
Definition: font.cpp:566
void link_hotspot(int up_button_num, int down_button_num)
Definition: listbox.cpp:26
int keypress
Definition: ui.h:622
int timer_get_milliseconds()
Definition: timer.cpp:150
int f_id
Definition: ui.h:603
int current()
Definition: listbox.cpp:471
virtual void draw()
Definition: gadget.cpp:139
int ascii_table[128]
Definition: key.cpp:72
GLint y
Definition: Gl.h:1505
int toggled()
Definition: listbox.cpp:453
UI_GADGET * selected_gadget
Definition: ui.h:610