/**************************************************************************** GLUI User Interface Toolkit --------------------------- glui_list.cpp - GLUI_List control class -------------------------------------------------- Copyright (c) 2004 John Kew This program is freely distributable without licensing fees and is provided without guarantee or warrantee expressed or implied. This program is -not- in the public domain. *****************************************************************************/ #include "glui_internal_control.h" #include #include /****************************** GLUI_List::GLUI_List() **********/ GLUI_List::GLUI_List( GLUI_Node *parent, bool scroll, int id, GLUI_CB callback /*,GLUI_Control *object GLUI_InterObject_CB obj_cb*/) { common_construct(parent, NULL, scroll, id, callback/*, object, obj_cb*/); } /****************************** GLUI_List::GLUI_List() **********/ GLUI_List::GLUI_List( GLUI_Node *parent, GLUI_String& live_var, bool scroll, int id, GLUI_CB callback /* ,GLUI_Control *object ,GLUI_InterObject_CB obj_cb*/ ) { common_construct(parent, &live_var, scroll, id, callback/*, object, obj_cb*/); } /****************************** GLUI_List::common_construct() **********/ void GLUI_List::common_construct( GLUI_Node *parent, GLUI_String* data, bool scroll, int id, GLUI_CB callback /*,GLUI_Control *object , GLUI_InterObject_CB obj_cb*/) { common_init(); GLUI_Node *list_panel = parent; if (scroll) { GLUI_Panel *p = new GLUI_Panel(parent,"",GLUI_PANEL_NONE); p->x_off = 1; list_panel = p; } this->ptr_val = data; if (data) { this->live_type = GLUI_LIVE_STRING; } this->user_id = id; this->callback = callback; this->name = "list"; list_panel->add_control( this ); if (scroll) { new GLUI_Column(list_panel, false); scrollbar = new GLUI_Scrollbar(list_panel, "scrollbar", GLUI_SCROLL_VERTICAL, GLUI_SCROLL_INT); scrollbar->set_object_callback(GLUI_List::scrollbar_callback, this); scrollbar->set_alignment(GLUI_ALIGN_LEFT); // scrollbar->can_activate = false; //kills ability to mouse drag too } init_live(); } /****************************** GLUI_List::mouse_down_handler() **********/ int GLUI_List::mouse_down_handler( int local_x, int local_y ) { int tmp_line; unsigned long int ms; timeb time; ftime(&time); ms = time.millitm + (time.time)*1000; tmp_line = find_line( local_x-x_abs, local_y-y_abs-5 ); if ( tmp_line == -1 ) { if ( glui ) glui->deactivate_current_control( ); return false; } if (tmp_line < num_lines) { curr_line = tmp_line; if (scrollbar) scrollbar->set_int_val(curr_line); this->execute_callback(); if (associated_object != NULL) if (cb_click_type == GLUI_SINGLE_CLICK) { if (obj_cb) { // obj_cb(associated_object, user_id); obj_cb(this); } } else { if (last_line == curr_line && (ms - last_click_time) < 300) { //obj_cb(associated_object, user_id); obj_cb(this); } else { last_click_time = ms; last_line = curr_line; } } if ( can_draw()) update_and_draw_text(); } return true; } /******************************** GLUI_List::mouse_up_handler() **********/ int GLUI_List::mouse_up_handler( int local_x, int local_y, bool inside ) { return false; } /***************************** GLUI_List::mouse_held_down_handler() ******/ int GLUI_List::mouse_held_down_handler( int local_x, int local_y, bool new_inside) { return false; } /****************************** GLUI_List::key_handler() **********/ int GLUI_List::key_handler( unsigned char key,int modifiers ) { draw_text_only = false; /** Well, hack is not yet working **/ update_and_draw_text(); draw_text_only = false; return true; } /****************************** GLUI_List::activate() **********/ void GLUI_List::activate( int how ) { // if ( debug ) // dump( stdout, "-> ACTIVATE" ); active = true; if ( how == GLUI_ACTIVATE_MOUSE ) return; /* Don't select everything if activated with mouse */ } /****************************** GLUI_List::deactivate() **********/ void GLUI_List::deactivate( void ) { active = false; redraw(); } /****************************** GLUI_List::draw() **********/ void GLUI_List::draw( int x, int y ) { int line = 0; int box_width; GLUI_List_Item *item; GLUI_DRAWINGSENTINAL_IDIOM /* Bevelled Border */ glBegin( GL_LINES ); glColor3f( .5, .5, .5 ); glVertex2i( 0, 0 ); glVertex2i( w, 0 ); glVertex2i( 0, 0 ); glVertex2i( 0, h ); glColor3f( 1., 1., 1. ); glVertex2i( 0, h ); glVertex2i( w, h ); glVertex2i( w, h ); glVertex2i( w, 0 ); if ( enabled ) glColor3f( 0., 0., 0. ); else glColor3f( .25, .25, .25 ); glVertex2i( 1, 1 ); glVertex2i( w-1, 1 ); glVertex2i( 1, 1 ); glVertex2i( 1, h-1 ); glColor3f( .75, .75, .75 ); glVertex2i( 1, h-1 ); glVertex2i( w-1, h-1 ); glVertex2i( w-1, h-1 ); glVertex2i( w-1, 1 ); glEnd(); /* Draw Background if enabled*/ if (enabled) { glColor3f( 1., 1., 1. ); glDisable( GL_CULL_FACE ); glBegin( GL_QUADS ); glVertex2i( 2, 2 ); glVertex2i( w-2, 2 ); glVertex2i( w-2, h-2 ); glVertex2i(2, h-2 ); glEnd(); } else { glColor3f( .8, .8, .8 ); glDisable( GL_CULL_FACE ); glBegin( GL_QUADS ); glVertex2i( 2, 2 ); glVertex2i( w-2, 2 ); glVertex2i( w-2, h-2 ); glVertex2i(2, h-2 ); glEnd(); } /* Figure out how wide the box is */ box_width = get_box_width(); /* Figure out which lines are visible*/ visible_lines = (int)(h-20)/15; item = (GLUI_List_Item *) items_list.first_child(); line = 0; while (item) { if (line < start_line) { line++; item = (GLUI_List_Item *) item->next(); continue; } if (line >= start_line && line <= (start_line+visible_lines)) { if (curr_line == line) draw_text(item->text.c_str(),1,0,(line - start_line)*15); else draw_text(item->text.c_str(),0,0,(line - start_line)*15); } line++; item = (GLUI_List_Item *) item->next(); } if (scrollbar) { scrollbar->set_int_limits(MAX(0,num_lines-visible_lines), 0); glPushMatrix(); glTranslatef(scrollbar->x_abs-x_abs, scrollbar->y_abs-y_abs,0.0); scrollbar->draw_scroll(); glPopMatrix(); } } /********************************* GLUI_List::draw_text() ****************/ void GLUI_List::draw_text(const char *t, int selected, int x, int y ) { int text_x, i, x_pos; int box_width; GLUI_DRAWINGSENTINAL_IDIOM /** Find where to draw the text **/ text_x = 2 + GLUI_LIST_BOXINNERMARGINX; /** Draw selection area dark **/ if ( enabled && selected ) { glColor3f( 0.0f, 0.0f, .6f ); glBegin( GL_QUADS ); glVertex2i(text_x, y+5 ); glVertex2i( w-text_x, y+5 ); glVertex2i(w-text_x, y+19 ); glVertex2i(text_x, y+19 ); glEnd(); } box_width = get_box_width(); if ( !selected || !enabled ) { /* No current selection */ x_pos = text_x; /* or control disabled */ if ( enabled ) glColor3b( 0, 0, 0 ); else glColor3b( 32, 32, 32 ); glRasterPos2i( text_x, y+15); i = 0; while( t[i] != '\0' && substring_width(t,0,i) < box_width) { glutBitmapCharacter( get_font(), t[i] ); x_pos += char_width( t[i] ); i++; } } else { /* There is a selection */ i = 0; x_pos = text_x; glColor3f( 1., 1., 1. ); glRasterPos2i( text_x, y+15); while( t[i] != '\0' && substring_width(t,0,i) < box_width) { glutBitmapCharacter( get_font(), t[i] ); x_pos += char_width( t[i] ); i++; } } } int GLUI_List::find_line(int x, int y) { return start_line + ((int)(y/15)); } int GLUI_List::get_box_width() { return MAX( this->w - 6 /* 2 * the two-line box border */ - 2 * GLUI_LIST_BOXINNERMARGINX, 0 ); } /******************************** GLUI_List::substring_width() *********/ int GLUI_List::substring_width( const char *t, int start, int end ) { int i, width; width = 0; for( i=start; i<=end; i++ ) width += char_width( t[i] ); return width; } /***************************** GLUI_List::update_and_draw_text() ********/ void GLUI_List::update_and_draw_text( void ) { if ( NOT can_draw() ) return; //update_substring_bounds(); /* printf( "ss: %d/%d\n", substring_start, substring_end ); */ redraw(); } /********************************* GLUI_List::special_handler() **********/ int GLUI_List::special_handler( int key,int modifiers ) { if ( NOT glui ) return false; if ( key == GLUT_KEY_DOWN ) { if (curr_line < num_lines) { curr_line++; if (curr_line > start_line+visible_lines) start_line++; } } else if ( key == GLUT_KEY_UP ) { if (curr_line > 0) { curr_line--; if (curr_line < start_line) start_line--; } } if (scrollbar) scrollbar->set_int_val(curr_line); redraw(); return true; } /************************************ GLUI_List::update_size() **********/ void GLUI_List::update_size( void ) { if ( NOT glui ) return; if ( w < GLUI_LIST_MIN_TEXT_WIDTH ) w = GLUI_LIST_MIN_TEXT_WIDTH; } /**************************************** GLUI_Listbox::add_item() **********/ int GLUI_List::add_item( int id, const char *new_text ) { GLUI_List_Item *new_node = new GLUI_List_Item; GLUI_List_Item *head; new_node->text = new_text; new_node->id = id; head = (GLUI_List_Item*) items_list.first_child(); new_node->link_this_to_parent_last( &items_list ); if ( head == NULL ) { /*** This is first item added ***/ int_val = id+1; /** Different than id **/ // do_selection( id ); last_live_int = id; if( glui ) glui->post_update_main_gfx(); } num_lines++; if (scrollbar) scrollbar->set_int_limits(MAX(num_lines-visible_lines,0), 0); return true; } /************************************** GLUI_Listbox::delete_() **********/ int GLUI_List::delete_all() { GLUI_List_Item *item; item = (GLUI_List_Item *) items_list.first_child(); while( item ) { item->unlink(); delete item; item = (GLUI_List_Item *) items_list.first_child(); } num_lines = 0; curr_line = 0; return true; } /************************************** GLUI_Listbox::delete_item() **********/ int GLUI_List::delete_item( const char *text ) { GLUI_List_Item *node = get_item_ptr( text ); if ( node ) { node->unlink(); delete node; num_lines--; return true; } else { return false; } } /************************************** GLUI_Listbox::delete_item() **********/ int GLUI_List::delete_item( int id ) { GLUI_List_Item *node = get_item_ptr( id ); if ( node ) { node->unlink(); delete node; num_lines--; return true; } else { return false; } } /************************************ GLUI_Listbox::get_item_ptr() **********/ GLUI_List_Item *GLUI_List::get_item_ptr( const char *text ) { GLUI_List_Item *item; item = (GLUI_List_Item *) items_list.first_child(); while( item ) { if ( item->text == text ) return item; item = (GLUI_List_Item *) item->next(); } return NULL; } /************************************ GLUI_Listbox::get_item_ptr() **********/ GLUI_List_Item *GLUI_List::get_item_ptr( int id ) { GLUI_List_Item *item; item = (GLUI_List_Item *) items_list.first_child(); while( item ) { if ( item->id == id ) return item; item = (GLUI_List_Item *) item->next(); } return NULL; } /**************************************** GLUI_List::mouse_over() ********/ int GLUI_List::mouse_over( int state, int x, int y ) { glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); return true; } void GLUI_List::scrollbar_callback(GLUI_Control *my_scrollbar) { GLUI_Scrollbar *sb = my_scrollbar->dynamicCastGLUI_Scrollbar(); if (!sb) return; GLUI_List* me = (GLUI_List*) sb->associated_object; if (me->scrollbar == NULL) return; int new_start_line = sb->get_int_val(); // TODO!! me->start_line = new_start_line; if ( me->can_draw() ) me->update_and_draw_text(); }