1 /****************************************************************************
2
3 GLUI User Interface Toolkit
4 ---------------------------
5
6 glui_list.cpp - GLUI_List control class
7
8
9 --------------------------------------------------
10
11 Copyright (c) 2004 John Kew
12
13 This program is freely distributable without licensing fees and is
14 provided without guarantee or warrantee expressed or implied. This
15 program is -not- in the public domain.
16
17 *****************************************************************************/
18
19 #include "glui_internal_control.h"
20 #include <cmath>
21 #include <sys/timeb.h>
22
23 /****************************** GLUI_List::GLUI_List() **********/
24
GLUI_List(GLUI_Node * parent,bool scroll,int id,GLUI_CB callback)25 GLUI_List::GLUI_List( GLUI_Node *parent, bool scroll,
26 int id, GLUI_CB callback
27 /*,GLUI_Control *object
28 GLUI_InterObject_CB obj_cb*/)
29 {
30 common_construct(parent, NULL, scroll, id, callback/*, object, obj_cb*/);
31 }
32
33 /****************************** GLUI_List::GLUI_List() **********/
34
GLUI_List(GLUI_Node * parent,GLUI_String & live_var,bool scroll,int id,GLUI_CB callback)35 GLUI_List::GLUI_List( GLUI_Node *parent,
36 GLUI_String& live_var, bool scroll,
37 int id,
38 GLUI_CB callback
39 /* ,GLUI_Control *object
40 ,GLUI_InterObject_CB obj_cb*/ )
41 {
42 common_construct(parent, &live_var, scroll, id, callback/*, object, obj_cb*/);
43 }
44
45 /****************************** GLUI_List::common_construct() **********/
46
common_construct(GLUI_Node * parent,GLUI_String * data,bool scroll,int id,GLUI_CB callback)47 void GLUI_List::common_construct(
48 GLUI_Node *parent,
49 GLUI_String* data, bool scroll,
50 int id,
51 GLUI_CB callback
52 /*,GLUI_Control *object
53 , GLUI_InterObject_CB obj_cb*/)
54 {
55 common_init();
56 GLUI_Node *list_panel = parent;
57
58 if (scroll) {
59 GLUI_Panel *p = new GLUI_Panel(parent,"",GLUI_PANEL_NONE);
60 p->x_off = 1;
61 list_panel = p;
62 }
63 this->ptr_val = data;
64 if (data) {
65 this->live_type = GLUI_LIVE_STRING;
66 }
67 this->user_id = id;
68 this->callback = callback;
69 this->name = "list";
70 list_panel->add_control( this );
71 if (scroll)
72 {
73 new GLUI_Column(list_panel, false);
74 scrollbar =
75 new GLUI_Scrollbar(list_panel,
76 "scrollbar",
77 GLUI_SCROLL_VERTICAL,
78 GLUI_SCROLL_INT);
79 scrollbar->set_object_callback(GLUI_List::scrollbar_callback, this);
80 scrollbar->set_alignment(GLUI_ALIGN_LEFT);
81 // scrollbar->can_activate = false; //kills ability to mouse drag too
82 }
83 init_live();
84 }
85
86 /****************************** GLUI_List::mouse_down_handler() **********/
mouse_down_handler(int local_x,int local_y)87 int GLUI_List::mouse_down_handler( int local_x, int local_y )
88 {
89 int tmp_line;
90 unsigned long int ms;
91 timeb time;
92 ftime(&time);
93 ms = time.millitm + (time.time)*1000;
94
95 tmp_line = find_line( local_x-x_abs, local_y-y_abs-5 );
96 if ( tmp_line == -1 ) {
97 if ( glui )
98 glui->deactivate_current_control( );
99 return false;
100 }
101
102 if (tmp_line < num_lines) {
103 curr_line = tmp_line;
104 if (scrollbar)
105 scrollbar->set_int_val(curr_line);
106 this->execute_callback();
107 if (associated_object != NULL)
108 if (cb_click_type == GLUI_SINGLE_CLICK) {
109 if (obj_cb) {
110 // obj_cb(associated_object, user_id);
111 obj_cb(this);
112 }
113 } else {
114 if (last_line == curr_line && (ms - last_click_time) < 300) {
115 //obj_cb(associated_object, user_id);
116 obj_cb(this);
117 } else {
118 last_click_time = ms;
119 last_line = curr_line;
120 }
121 }
122 if ( can_draw())
123 update_and_draw_text();
124 }
125
126 return true;
127 }
128
129
130
131
132 /******************************** GLUI_List::mouse_up_handler() **********/
133
mouse_up_handler(int local_x,int local_y,bool inside)134 int GLUI_List::mouse_up_handler( int local_x, int local_y, bool inside )
135 {
136 return false;
137 }
138
139
140 /***************************** GLUI_List::mouse_held_down_handler() ******/
141
mouse_held_down_handler(int local_x,int local_y,bool new_inside)142 int GLUI_List::mouse_held_down_handler( int local_x, int local_y,
143 bool new_inside)
144 {
145 return false;
146 }
147
148
149 /****************************** GLUI_List::key_handler() **********/
150
key_handler(unsigned char key,int modifiers)151 int GLUI_List::key_handler( unsigned char key,int modifiers )
152 {
153
154
155 draw_text_only = false; /** Well, hack is not yet working **/
156 update_and_draw_text();
157 draw_text_only = false;
158
159 return true;
160 }
161
162
163 /****************************** GLUI_List::activate() **********/
164
activate(int how)165 void GLUI_List::activate( int how )
166 {
167 // if ( debug )
168 // dump( stdout, "-> ACTIVATE" );
169 active = true;
170
171 if ( how == GLUI_ACTIVATE_MOUSE )
172 return; /* Don't select everything if activated with mouse */
173
174 }
175
176
177 /****************************** GLUI_List::deactivate() **********/
178
deactivate(void)179 void GLUI_List::deactivate( void )
180 {
181 active = false;
182 redraw();
183 }
184
185 /****************************** GLUI_List::draw() **********/
186
draw(int x,int y)187 void GLUI_List::draw( int x, int y )
188 {
189 int line = 0;
190 int box_width;
191 GLUI_List_Item *item;
192
193 GLUI_DRAWINGSENTINAL_IDIOM
194
195 /* Bevelled Border */
196 glBegin( GL_LINES );
197 glColor3f( .5, .5, .5 );
198 glVertex2i( 0, 0 ); glVertex2i( w, 0 );
199 glVertex2i( 0, 0 ); glVertex2i( 0, h );
200
201 glColor3f( 1., 1., 1. );
202 glVertex2i( 0, h ); glVertex2i( w, h );
203 glVertex2i( w, h ); glVertex2i( w, 0 );
204
205 if ( enabled )
206 glColor3f( 0., 0., 0. );
207 else
208 glColor3f( .25, .25, .25 );
209 glVertex2i( 1, 1 ); glVertex2i( w-1, 1 );
210 glVertex2i( 1, 1 ); glVertex2i( 1, h-1 );
211
212 glColor3f( .75, .75, .75 );
213 glVertex2i( 1, h-1 ); glVertex2i( w-1, h-1 );
214 glVertex2i( w-1, h-1 ); glVertex2i( w-1, 1 );
215 glEnd();
216
217 /* Draw Background if enabled*/
218 if (enabled) {
219 glColor3f( 1., 1., 1. );
220 glDisable( GL_CULL_FACE );
221 glBegin( GL_QUADS );
222 glVertex2i( 2, 2 ); glVertex2i( w-2, 2 );
223 glVertex2i( w-2, h-2 ); glVertex2i(2, h-2 );
224 glEnd();
225 } else {
226 glColor3f( .8, .8, .8 );
227 glDisable( GL_CULL_FACE );
228 glBegin( GL_QUADS );
229 glVertex2i( 2, 2 ); glVertex2i( w-2, 2 );
230 glVertex2i( w-2, h-2 ); glVertex2i(2, h-2 );
231 glEnd();
232 }
233
234 /* Figure out how wide the box is */
235 box_width = get_box_width();
236
237 /* Figure out which lines are visible*/
238
239 visible_lines = (int)(h-20)/15;
240
241 item = (GLUI_List_Item *) items_list.first_child();
242
243 line = 0;
244 while (item) {
245 if (line < start_line) {
246 line++;
247 item = (GLUI_List_Item *) item->next();
248 continue;
249 }
250 if (line >= start_line && line <= (start_line+visible_lines)) {
251 if (curr_line == line)
252 draw_text(item->text.c_str(),1,0,(line - start_line)*15);
253 else
254 draw_text(item->text.c_str(),0,0,(line - start_line)*15);
255 }
256 line++;
257 item = (GLUI_List_Item *) item->next();
258 }
259
260 if (scrollbar) {
261 scrollbar->set_int_limits(MAX(0,num_lines-visible_lines), 0);
262 glPushMatrix();
263 glTranslatef(scrollbar->x_abs-x_abs, scrollbar->y_abs-y_abs,0.0);
264 scrollbar->draw_scroll();
265 glPopMatrix();
266 }
267 }
268
269 /********************************* GLUI_List::draw_text() ****************/
270
draw_text(const char * t,int selected,int x,int y)271 void GLUI_List::draw_text(const char *t, int selected, int x, int y )
272 {
273 int text_x, i, x_pos;
274 int box_width;
275
276 GLUI_DRAWINGSENTINAL_IDIOM
277
278 /** Find where to draw the text **/
279
280 text_x = 2 + GLUI_LIST_BOXINNERMARGINX;
281
282 /** Draw selection area dark **/
283 if ( enabled && selected ) {
284 glColor3f( 0.0f, 0.0f, .6f );
285 glBegin( GL_QUADS );
286 glVertex2i(text_x, y+5 ); glVertex2i( w-text_x, y+5 );
287 glVertex2i(w-text_x, y+19 ); glVertex2i(text_x, y+19 );
288 glEnd();
289 }
290 box_width = get_box_width();
291
292 if ( !selected || !enabled ) { /* No current selection */
293 x_pos = text_x; /* or control disabled */
294 if ( enabled )
295 glColor3b( 0, 0, 0 );
296 else
297 glColor3b( 32, 32, 32 );
298
299 glRasterPos2i( text_x, y+15);
300 i = 0;
301 while( t[i] != '\0' && substring_width(t,0,i) < box_width) {
302 glutBitmapCharacter( get_font(), t[i] );
303 x_pos += char_width( t[i] );
304 i++;
305 }
306 }
307 else { /* There is a selection */
308 i = 0;
309 x_pos = text_x;
310 glColor3f( 1., 1., 1. );
311 glRasterPos2i( text_x, y+15);
312 while( t[i] != '\0' && substring_width(t,0,i) < box_width) {
313 glutBitmapCharacter( get_font(), t[i] );
314 x_pos += char_width( t[i] );
315 i++;
316 }
317 }
318 }
319
320
find_line(int x,int y)321 int GLUI_List::find_line(int x, int y) {
322 return start_line + ((int)(y/15));
323 }
324
get_box_width()325 int GLUI_List::get_box_width() {
326 return MAX( this->w
327 - 6 /* 2 * the two-line box border */
328 - 2 * GLUI_LIST_BOXINNERMARGINX, 0 );
329
330 }
331
332 /******************************** GLUI_List::substring_width() *********/
substring_width(const char * t,int start,int end)333 int GLUI_List::substring_width( const char *t, int start, int end )
334 {
335 int i, width;
336
337 width = 0;
338
339 for( i=start; i<=end; i++ )
340 width += char_width( t[i] );
341
342 return width;
343 }
344
345
346 /***************************** GLUI_List::update_and_draw_text() ********/
347
update_and_draw_text(void)348 void GLUI_List::update_and_draw_text( void )
349 {
350 if ( NOT can_draw() )
351 return;
352
353 //update_substring_bounds();
354 /* printf( "ss: %d/%d\n", substring_start, substring_end ); */
355
356 redraw();
357 }
358
359
360 /********************************* GLUI_List::special_handler() **********/
361
special_handler(int key,int modifiers)362 int GLUI_List::special_handler( int key,int modifiers )
363 {
364 if ( NOT glui )
365 return false;
366
367 if ( key == GLUT_KEY_DOWN ) {
368 if (curr_line < num_lines) {
369 curr_line++;
370 if (curr_line > start_line+visible_lines)
371 start_line++;
372 }
373 } else if ( key == GLUT_KEY_UP ) {
374 if (curr_line > 0) {
375 curr_line--;
376 if (curr_line < start_line)
377 start_line--;
378 }
379 }
380
381 if (scrollbar)
382 scrollbar->set_int_val(curr_line);
383 redraw();
384 return true;
385 }
386
387
388 /************************************ GLUI_List::update_size() **********/
389
update_size(void)390 void GLUI_List::update_size( void )
391 {
392 if ( NOT glui )
393 return;
394
395 if ( w < GLUI_LIST_MIN_TEXT_WIDTH )
396 w = GLUI_LIST_MIN_TEXT_WIDTH;
397 }
398
399 /**************************************** GLUI_Listbox::add_item() **********/
400
add_item(int id,const char * new_text)401 int GLUI_List::add_item( int id, const char *new_text )
402 {
403 GLUI_List_Item *new_node = new GLUI_List_Item;
404 GLUI_List_Item *head;
405
406 new_node->text = new_text;
407 new_node->id = id;
408
409 head = (GLUI_List_Item*) items_list.first_child();
410 new_node->link_this_to_parent_last( &items_list );
411
412 if ( head == NULL ) {
413 /*** This is first item added ***/
414
415 int_val = id+1; /** Different than id **/
416 // do_selection( id );
417 last_live_int = id;
418
419 if( glui )
420 glui->post_update_main_gfx();
421 }
422 num_lines++;
423 if (scrollbar)
424 scrollbar->set_int_limits(MAX(num_lines-visible_lines,0), 0);
425
426 return true;
427 }
428
429 /************************************** GLUI_Listbox::delete_() **********/
430
delete_all()431 int GLUI_List::delete_all()
432 {
433 GLUI_List_Item *item;
434
435 item = (GLUI_List_Item *) items_list.first_child();
436 while( item ) {
437 item->unlink();
438 delete item;
439 item = (GLUI_List_Item *) items_list.first_child();
440 }
441
442 num_lines = 0;
443 curr_line = 0;
444
445 return true;
446 }
447
448
449 /************************************** GLUI_Listbox::delete_item() **********/
450
delete_item(const char * text)451 int GLUI_List::delete_item( const char *text )
452 {
453 GLUI_List_Item *node = get_item_ptr( text );
454
455 if ( node ) {
456 node->unlink();
457 delete node;
458 num_lines--;
459 return true;
460 }
461 else {
462 return false;
463 }
464 }
465
466
467 /************************************** GLUI_Listbox::delete_item() **********/
468
delete_item(int id)469 int GLUI_List::delete_item( int id )
470 {
471 GLUI_List_Item *node = get_item_ptr( id );
472
473 if ( node ) {
474 node->unlink();
475 delete node;
476 num_lines--;
477 return true;
478 }
479 else {
480 return false;
481 }
482 }
483
484
485 /************************************ GLUI_Listbox::get_item_ptr() **********/
486
get_item_ptr(const char * text)487 GLUI_List_Item *GLUI_List::get_item_ptr( const char *text )
488 {
489 GLUI_List_Item *item;
490
491 item = (GLUI_List_Item *) items_list.first_child();
492 while( item ) {
493 if ( item->text == text )
494 return item;
495
496 item = (GLUI_List_Item *) item->next();
497 }
498
499 return NULL;
500 }
501
502
503 /************************************ GLUI_Listbox::get_item_ptr() **********/
504
get_item_ptr(int id)505 GLUI_List_Item *GLUI_List::get_item_ptr( int id )
506 {
507 GLUI_List_Item *item;
508
509 item = (GLUI_List_Item *) items_list.first_child();
510 while( item ) {
511 if ( item->id == id )
512 return item;
513
514 item = (GLUI_List_Item *) item->next();
515 }
516
517 return NULL;
518 }
519
520 /**************************************** GLUI_List::mouse_over() ********/
521
mouse_over(int state,int x,int y)522 int GLUI_List::mouse_over( int state, int x, int y )
523 {
524 glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
525
526 return true;
527 }
528
scrollbar_callback(GLUI_Control * my_scrollbar)529 void GLUI_List::scrollbar_callback(GLUI_Control *my_scrollbar) {
530 GLUI_Scrollbar *sb = dynamic_cast<GLUI_Scrollbar*>(my_scrollbar);
531 if (!sb) return;
532 GLUI_List* me = (GLUI_List*) sb->associated_object;
533 if (me->scrollbar == NULL)
534 return;
535 int new_start_line = sb->get_int_val(); // TODO!!
536 me->start_line = new_start_line;
537
538 if ( me->can_draw() )
539 me->update_and_draw_text();
540 }
541