/**************************************************************************** GLUI User Interface Toolkit --------------------------- glui_listbox - GLUI_ListBox control class -------------------------------------------------- Copyright (c) 1998 Paul Rademacher WWW: http://sourceforge.net/projects/glui/ Forums: http://sourceforge.net/forum/?group_id=92496 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ #include "glui_internal_control.h" /****************************** GLUI_Listbox::GLUI_Listbox() **********/ GLUI_Listbox::GLUI_Listbox( GLUI_Node *parent, const char *name, int *value_ptr, int id, GLUI_CB cb) { common_init(); set_ptr_val( value_ptr ); user_id = id; set_name( name ); callback = cb; parent->add_control( this ); init_live(); } /****************************** GLUI_Listbox::mouse_down_handler() **********/ int GLUI_Listbox::mouse_down_handler( int local_x, int local_y ) { return false; } /****************************** GLUI_Listbox::mouse_up_handler() **********/ int GLUI_Listbox::mouse_up_handler( int local_x, int local_y, bool inside ) { return false; } /****************************** GLUI_Listbox::mouse_held_down_handler() ******/ int GLUI_Listbox::mouse_held_down_handler( int local_x, int local_y, bool inside) { return false; } /****************************** GLUI_Listbox::key_handler() **********/ int GLUI_Listbox::key_handler( unsigned char key,int modifiers ) { return false; } /****************************** GLUI_Listbox::draw() **********/ void GLUI_Listbox::draw( int x, int y ) { GLUI_DRAWINGSENTINAL_IDIOM int name_x; /* draw_active_area(); */ name_x = MAX(text_x_offset - string_width(this->name) - 3,0); draw_name( name_x , 13); draw_box_inwards_outline( text_x_offset, w, 0, h ); if ( NOT active ) { draw_box( text_x_offset+3, w-2, 2, h-2, 1.0, 1.0, 1.0 ); if ( NOT enabled ) glColor3b( 32, 32, 32 ); else glColor3f( 0.0, 0.0, 0.0 ); glRasterPos2i( text_x_offset+5, 13 ); draw_string( curr_text ); } else { draw_box( text_x_offset+3, w-2, 2, h-2, .0, .0, .6 ); glColor3f( 1.0, 1.0, 1.0 ); glRasterPos2i( text_x_offset+5, 13 ); draw_string( curr_text ); } if ( enabled ) { glui->std_bitmaps. draw(GLUI_STDBITMAP_LISTBOX_UP, w-glui->std_bitmaps.width(GLUI_STDBITMAP_LISTBOX_UP)-1, 2 ); } else { glui->std_bitmaps. draw(GLUI_STDBITMAP_LISTBOX_UP_DIS, w-glui->std_bitmaps.width(GLUI_STDBITMAP_LISTBOX_UP)-1, 2 ); } } /************************************ GLUI_Listbox::update_si() **********/ void GLUI_Listbox::update_size( void ) { recalculate_item_width(); } /********************************* GLUI_Listbox::set_int_val() **************/ void GLUI_Listbox::set_int_val( int new_val ) { /* int_val = new_val; */ do_selection( new_val ); /*** Update the variable we're (possibly) pointing to, and update the main gfx ***/ output_live(true); } /**************************************** GLUI_Listbox::add_item() **********/ int GLUI_Listbox::add_item( int id, const char *new_text ) { GLUI_Listbox_Item *new_node = new GLUI_Listbox_Item; GLUI_Listbox_Item *head; new_node->text = new_text; new_node->id = id; head = (GLUI_Listbox_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(); } if (recalculate_item_width()) glui->refresh(); return true; } /************************************** GLUI_Listbox::delete_item() **********/ int GLUI_Listbox::delete_item( const char *text ) { GLUI_Listbox_Item *node = get_item_ptr(text); if (node) { node->unlink(); delete node; return true; } if (recalculate_item_width()) glui->refresh(); return false; } /************************************** GLUI_Listbox::delete_item() **********/ int GLUI_Listbox::delete_item(int id) { GLUI_Listbox_Item *node = get_item_ptr(id); if (node) { node->unlink(); delete node; return true; } if (recalculate_item_width()) glui->refresh(); return false; } /************************************** GLUI_Listbox::sort_items() **********/ int GLUI_Listbox::sort_items( void ) { return false; } /********************************************* GLUI_Listbox::dump() **********/ void GLUI_Listbox::dump( FILE *output ) { GLUI_Listbox_Item *item; /* printf( "%p\n", (char*) name ); */ fprintf( output, "Listbox: %s\n", name.c_str() ); item = (GLUI_Listbox_Item *) items_list.first_child(); while( item ) { fprintf( output, " %3d : %s\n", item->id, item->text.c_str() ); item = (GLUI_Listbox_Item *) item->next(); } } /************************************ GLUI_Listbox::get_item_ptr() **********/ GLUI_Listbox_Item *GLUI_Listbox::get_item_ptr( const char *text ) { GLUI_Listbox_Item *item; item = (GLUI_Listbox_Item *) items_list.first_child(); while( item ) { if ( item->text == text ) return item; item = (GLUI_Listbox_Item *) item->next(); } return NULL; } /************************************ GLUI_Listbox::get_item_ptr() **********/ GLUI_Listbox_Item *GLUI_Listbox::get_item_ptr( int id ) { GLUI_Listbox_Item *item; item = (GLUI_Listbox_Item *) items_list.first_child(); while( item ) { if ( item->id == id ) return item; item = (GLUI_Listbox_Item *) item->next(); } return NULL; } /************************************ GLUI_Listbox::mouse_over() **********/ static void listbox_callback( int i ) { int old_val; if ( NOT GLUI_Master.curr_left_button_glut_menu OR !GLUI_Master.curr_left_button_glut_menu->dynamicCastGLUI_Listbox() ) return; old_val = ((GLUI_Listbox*)GLUI_Master.curr_left_button_glut_menu)->int_val; ((GLUI_Listbox*)GLUI_Master.curr_left_button_glut_menu)->set_int_val(i); /**** If value changed, execute callback ****/ if ( old_val != ((GLUI_Listbox*)GLUI_Master.curr_left_button_glut_menu)->int_val ) { ((GLUI_Listbox*)GLUI_Master.curr_left_button_glut_menu)->execute_callback(); } } /*************************************** GLUI_Listbox::mouse_over() **********/ int GLUI_Listbox::mouse_over( int state, int x, int y ) { GLUI_Listbox_Item *item; /* printf( "x/y: %d/%d\n", x, y ); */ if ( state AND enabled AND x > x_abs + text_x_offset) { /**** Build a GLUT menu for this listbox ***/ /* printf( "%d %d\n", x, y ); */ glut_menu_id = glutCreateMenu(listbox_callback); item = (GLUI_Listbox_Item *) items_list.first_child(); while( item ) { glutAddMenuEntry( item->text.c_str(), item->id ); item = (GLUI_Listbox_Item *) item->next(); } glutAttachMenu( GLUT_LEFT_BUTTON); GLUI_Master.set_left_button_glut_menu_control( this ); } else if ( glut_menu_id != -1 ) { /* printf( "OUT\n" ); */ glutDetachMenu( GLUT_LEFT_BUTTON ); glutDestroyMenu( glut_menu_id ); glut_menu_id = -1; } return true; } /************************************ GLUI_Listbox::do_selection() **********/ int GLUI_Listbox::do_selection( int item_num ) { GLUI_Listbox_Item *item, *sel_item; /*** Is this item already selected? ***/ if ( item_num == int_val ) return false; sel_item = NULL; item = (GLUI_Listbox_Item *) items_list.first_child(); while( item ) { if ( item->id == item_num ) { sel_item = item; break; } item = (GLUI_Listbox_Item *) item->next(); } if ( NOT sel_item ) return false; /* printf( "-> %s\n", (char*) sel_item->text ); */ int_val = item_num; curr_text = sel_item->text; redraw(); return true; } /*********************************** GLUI_Listbox::~GLUI_Listbox() **********/ GLUI_Listbox::~GLUI_Listbox() { GLUI_Listbox_Item *item = (GLUI_Listbox_Item *) items_list.first_child(); while (item) { GLUI_Listbox_Item *tmp = item; item = (GLUI_Listbox_Item *) item->next(); delete tmp; } } /****************************** GLUI_Listbox::special_handler() **********/ int GLUI_Listbox::special_handler( int key,int modifiers ) { GLUI_Listbox_Item *node, *new_node; node = get_item_ptr( int_val ); new_node = NULL; if ( key == GLUT_KEY_DOWN ) { new_node = (GLUI_Listbox_Item*) node->next(); } else if ( key == GLUT_KEY_UP ) { new_node = (GLUI_Listbox_Item*) node->prev(); } else if ( key == GLUT_KEY_HOME ) { new_node = (GLUI_Listbox_Item*) items_list.first_child(); } else if ( key == GLUT_KEY_END ) { new_node = (GLUI_Listbox_Item*) items_list.last_child(); } if ( new_node != NULL AND new_node != node ) { node = new_node; set_int_val( node->id ); execute_callback(); return true; } else { return false; } } /************************* GLUI_Listbox::recalculate_item_width( void ) ***********/ /** Change w and return true if we need to be widened to fit the current items. */ bool GLUI_Listbox::recalculate_item_width( void ) { int item_text_size; if ( NOT glui ) return false; /* Find the title size */ text_x_offset = string_width( name ); /* Find the longest item string ***/ item_text_size = 0; GLUI_Listbox_Item *item = (GLUI_Listbox_Item *) items_list.first_child(); while( item ) { item_text_size = MAX(item_text_size,string_width(item->text)); item = (GLUI_Listbox_Item *) item->next(); } /* Sum up our layout: name, item, and drop-down marker */ int new_wid=text_x_offset+MAX(GLUI_EDITTEXT_MIN_TEXT_WIDTH,item_text_size)+20; if ( w != new_wid) { w = new_wid; return true; /* we gotta be shortened or widened */ } else { return false; /* our current width is OK */ } }