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