Permalink
Switch branches/tags
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
557 lines (429 sloc) 13.1 KB
/****************************************************************************
GLUI User Interface Toolkit
---------------------------
glui_list.cpp - GLUI_List control class
--------------------------------------------------
Copyright (c) 2004 John Kew
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*****************************************************************************/
#include "glui_internal_control.h"
#include <algorithm>
#include <cmath>
#include <sys/timeb.h>
/****************************** 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;
uint64_t 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 && last_click_time && (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()
{
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(std::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 GLUI_String &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( i<t.size() && 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( i<t.size() && 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 std::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 GLUI_String &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()
{
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()
{
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 GLUI_String &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(std::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 GLUI_String &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 GLUI_String &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 = dynamic_cast<GLUI_Scrollbar*>(my_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();
}