diff --git a/Extras/Jamfile b/Extras/Jamfile index 612d393f1..0cd949b5c 100644 --- a/Extras/Jamfile +++ b/Extras/Jamfile @@ -2,6 +2,7 @@ SubDir TOP Extras ; SubInclude TOP Extras ConvexDecomposition ; SubInclude TOP Extras COLLADA_DOM ; +SubInclude TOP Extras glui ; SubInclude TOP Extras LibXML ; SubInclude TOP Extras BulletColladaConverter ; #SubInclude TOP Extras BulletMultiThreaded ; diff --git a/Extras/glui/GL/glui.h b/Extras/glui/GL/glui.h new file mode 100644 index 000000000..6685b0f21 --- /dev/null +++ b/Extras/glui/GL/glui.h @@ -0,0 +1,2586 @@ +/**************************************************************************** + + GLUI User Interface Toolkit (LGPL) + ---------------------------------- + + glui.h - Main (and only) external header for + GLUI User Interface Toolkit + + -------------------------------------------------- + + 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 + +*****************************************************************************/ + +#ifndef GLUI_GLUI_H +#define GLUI_GLUI_H + +#if defined(GLUI_FREEGLUT) + + // FreeGLUT does not yet work perfectly with GLUI + // - use at your own risk. + #include + +#elif defined(GLUI_OPENGLUT) + + // OpenGLUT does not yet work properly with GLUI + // - use at your own risk. + + #include + +#else + + #ifdef __APPLE__ + #include + #else + #include "../../freeglut/gl/glut.h" + //#include + #endif + +#endif + +#include +#include +#include +#include +#include + +#define GLUI_VERSION 2.3f /********** Current version **********/ + +#if defined(_WIN32) +#if !defined(GLUI_NO_LIB_PRAGMA) +//#pragma comment(lib, "glui32.lib") // Link automatically with GLUI library +#endif +#endif + +/********** Do some basic defines *******/ + +#ifndef Byte +#define Byte unsigned char +#endif + +#ifndef _RGBC_ +class RGBc { +public: + Byte r, g, b; + + void set(Byte r,Byte g,Byte b) {this->r=r;this->g=g;this->b=b;} + + RGBc( void ) {} + RGBc( Byte r, Byte g, Byte b ) { set( r, g, b ); } +}; +#define _RGBC_ +#endif + +/********** List of GLUT callbacks ********/ + +enum GLUI_Glut_CB_Types +{ + GLUI_GLUT_RESHAPE, + GLUI_GLUT_KEYBOARD, + GLUI_GLUT_DISPLAY, + GLUI_GLUT_MOUSE, + GLUI_GLUT_MOTION, + GLUI_GLUT_SPECIAL, + GLUI_GLUT_PASSIVE_MOTION, + GLUI_GLUT_ENTRY, + GLUI_GLUT_VISIBILITY +}; + +/********* Constants for window placement **********/ + +#define GLUI_XOFF 6 +#define GLUI_YOFF 6 +#define GLUI_ITEMSPACING 3 +#define GLUI_CHECKBOX_SIZE 13 +#define GLUI_RADIOBUTTON_SIZE 13 +#define GLUI_BUTTON_SIZE 20 +#define GLUI_STATICTEXT_SIZE 13 +#define GLUI_SEPARATOR_HEIGHT 8 +#define GLUI_DEFAULT_CONTROL_WIDTH 100 +#define GLUI_DEFAULT_CONTROL_HEIGHT 13 +#define GLUI_EDITTEXT_BOXINNERMARGINX 3 +#define GLUI_EDITTEXT_HEIGHT 20 +#define GLUI_EDITTEXT_WIDTH 130 +#define GLUI_EDITTEXT_MIN_INT_WIDTH 35 +#define GLUI_EDITTEXT_MIN_TEXT_WIDTH 50 +#define GLUI_PANEL_NAME_DROP 8 +#define GLUI_PANEL_EMBOSS_TOP 4 +/* #define GLUI_ROTATION_WIDTH 60 */ +/* #define GLUI_ROTATION_HEIGHT 78 */ +#define GLUI_ROTATION_WIDTH 50 +#define GLUI_ROTATION_HEIGHT (GLUI_ROTATION_WIDTH+18) +#define GLUI_MOUSE_INTERACTION_WIDTH 50 +#define GLUI_MOUSE_INTERACTION_HEIGHT (GLUI_MOUSE_INTERACTION_WIDTH)+18 + +/** Different panel control types **/ +#define GLUI_PANEL_NONE 0 +#define GLUI_PANEL_EMBOSSED 1 +#define GLUI_PANEL_RAISED 2 + +/** Max # of els in control's float_array **/ +#define GLUI_DEF_MAX_ARRAY 30 + +/********* The control's 'active' behavior *********/ +#define GLUI_CONTROL_ACTIVE_MOUSEDOWN 1 +#define GLUI_CONTROL_ACTIVE_PERMANENT 2 + +/********* Control alignment types **********/ +#define GLUI_ALIGN_CENTER 1 +#define GLUI_ALIGN_RIGHT 2 +#define GLUI_ALIGN_LEFT 3 + +/********** Limit types - how to limit spinner values *********/ +#define GLUI_LIMIT_NONE 0 +#define GLUI_LIMIT_CLAMP 1 +#define GLUI_LIMIT_WRAP 2 + +/********** Translation control types ********************/ +#define GLUI_TRANSLATION_XY 0 +#define GLUI_TRANSLATION_Z 1 +#define GLUI_TRANSLATION_X 2 +#define GLUI_TRANSLATION_Y 3 + +#define GLUI_TRANSLATION_LOCK_NONE 0 +#define GLUI_TRANSLATION_LOCK_X 1 +#define GLUI_TRANSLATION_LOCK_Y 2 + +/********** How was a control activated? *****************/ +#define GLUI_ACTIVATE_MOUSE 1 +#define GLUI_ACTIVATE_TAB 2 + +/********** What type of live variable does a control have? **********/ +#define GLUI_LIVE_NONE 0 +#define GLUI_LIVE_INT 1 +#define GLUI_LIVE_FLOAT 2 +#define GLUI_LIVE_TEXT 3 +#define GLUI_LIVE_STRING 6 +#define GLUI_LIVE_DOUBLE 4 +#define GLUI_LIVE_FLOAT_ARRAY 5 + +/************* Textbox and List Defaults - JVK ******************/ +#define GLUI_TEXTBOX_HEIGHT 130 +#define GLUI_TEXTBOX_WIDTH 130 +#define GLUI_LIST_HEIGHT 130 +#define GLUI_LIST_WIDTH 130 +#define GLUI_DOUBLE_CLICK 1 +#define GLUI_SINGLE_CLICK 0 +#define GLUI_TAB_WIDTH 50 /* In pixels */ +#define GLUI_TEXTBOX_BOXINNERMARGINX 3 +#define GLUI_TEXTBOX_MIN_TEXT_WIDTH 50 +#define GLUI_LIST_BOXINNERMARGINX 3 +#define GLUI_LIST_MIN_TEXT_WIDTH 50 + +/*********************** TreePanel Defaults - JVK *****************************/ +#define GLUI_TREEPANEL_DEFAULTS 0 // bar, standard bar color +#define GLUI_TREEPANEL_ALTERNATE_COLOR 1 // Alternate between 8 different bar colors +#define GLUI_TREEPANEL_ENABLE_BAR 2 // enable the bar +#define GLUI_TREEPANEL_DISABLE_BAR 4 // disable the bar +#define GLUI_TREEPANEL_DISABLE_DEEPEST_BAR 8 // disable only the deepest bar +#define GLUI_TREEPANEL_CONNECT_CHILDREN_ONLY 16 // disable only the bar of the last child of each root +#define GLUI_TREEPANEL_DISPLAY_HIERARCHY 32 // display some sort of hierachy in the tree node title +#define GLUI_TREEPANEL_HIERARCHY_NUMERICDOT 64 // display hierarchy in 1.3.2 (etc... ) format +#define GLUI_TREEPANEL_HIERARCHY_LEVEL_ONLY 128 // display hierarchy as only the level depth + +/******************* GLUI Scrollbar Defaults - JVK ***************************/ +#define GLUI_SCROLL_ARROW_WIDTH 16 +#define GLUI_SCROLL_ARROW_HEIGHT 16 +#define GLUI_SCROLL_BOX_MIN_HEIGHT 5 +#define GLUI_SCROLL_BOX_STD_HEIGHT 16 +#define GLUI_SCROLL_STATE_NONE 0 +#define GLUI_SCROLL_STATE_UP 1 +#define GLUI_SCROLL_STATE_DOWN 2 +#define GLUI_SCROLL_STATE_BOTH 3 +#define GLUI_SCROLL_STATE_SCROLL 4 +#define GLUI_SCROLL_DEFAULT_GROWTH_EXP 1.05f +#define GLUI_SCROLL_VERTICAL 0 +#define GLUI_SCROLL_HORIZONTAL 1 + + +/** Size of the character width hash table for faster lookups. + Make sure to keep this a power of two to avoid the slow divide. + This is also a speed/memory tradeoff; 128 is enough for low ASCII. +*/ +#define CHAR_WIDTH_HASH_SIZE 128 + +/********** Translation codes **********/ + +enum TranslationCodes +{ + GLUI_TRANSLATION_MOUSE_NONE = 0, + GLUI_TRANSLATION_MOUSE_UP, + GLUI_TRANSLATION_MOUSE_DOWN, + GLUI_TRANSLATION_MOUSE_LEFT, + GLUI_TRANSLATION_MOUSE_RIGHT, + GLUI_TRANSLATION_MOUSE_UP_LEFT, + GLUI_TRANSLATION_MOUSE_UP_RIGHT, + GLUI_TRANSLATION_MOUSE_DOWN_LEFT, + GLUI_TRANSLATION_MOUSE_DOWN_RIGHT +}; + +/************ A string type for us to use **********/ + +typedef std::string GLUI_String; +GLUI_String& glui_format_str(GLUI_String &str, const char* fmt, ...); + +/********* Pre-declare classes as needed *********/ + +class GLUI; +class GLUI_Control; +class GLUI_Listbox; +class GLUI_StaticText; +class GLUI_EditText; +class GLUI_Panel; +class GLUI_Spinner; +class GLUI_RadioButton; +class GLUI_RadioGroup; +class GLUI_Glut_Window; +class GLUI_TreePanel; +class GLUI_Scrollbar; +class GLUI_List; + +class Arcball; + +/*** Flags for GLUI class constructor ***/ +#define GLUI_SUBWINDOW ((long)(1<<1)) +#define GLUI_SUBWINDOW_TOP ((long)(1<<2)) +#define GLUI_SUBWINDOW_BOTTOM ((long)(1<<3)) +#define GLUI_SUBWINDOW_LEFT ((long)(1<<4)) +#define GLUI_SUBWINDOW_RIGHT ((long)(1<<5)) + +/*** Codes for different type of edittext boxes and spinners ***/ +#define GLUI_EDITTEXT_TEXT 1 +#define GLUI_EDITTEXT_INT 2 +#define GLUI_EDITTEXT_FLOAT 3 +#define GLUI_SPINNER_INT GLUI_EDITTEXT_INT +#define GLUI_SPINNER_FLOAT GLUI_EDITTEXT_FLOAT +#define GLUI_SCROLL_INT GLUI_EDITTEXT_INT +#define GLUI_SCROLL_FLOAT GLUI_EDITTEXT_FLOAT +// This is only for deprecated interface +#define GLUI_EDITTEXT_STRING 4 + +/*** Definition of callbacks ***/ +typedef void (*GLUI_Update_CB) (int id); +typedef void (*GLUI_Control_CB)(GLUI_Control *); +typedef void (*Int1_CB) (int); +typedef void (*Int2_CB) (int, int); +typedef void (*Int3_CB) (int, int, int); +typedef void (*Int4_CB) (int, int, int, int); + +/************************************************************/ +/** + Callback Adapter Class + Allows us to support different types of callbacks; + like a GLUI_Update_CB function pointer--which takes an int; + and a GLUI_Control_CB function pointer--which takes a GUI_Control object. +*/ +class GLUI_CB +{ +public: + GLUI_CB() : idCB(0),objCB(0) {} + GLUI_CB(GLUI_Update_CB cb) : idCB(cb),objCB(0) {} + GLUI_CB(GLUI_Control_CB cb) : idCB(0),objCB(cb) {} + // (Compiler generated copy constructor) + + /** This control just activated. Fire our callback.*/ + void operator()(GLUI_Control *ctrl) const; + bool operator!() const { return !idCB && !objCB; } + operator bool() const { return !(!(*this)); } +private: + GLUI_Update_CB idCB; + GLUI_Control_CB objCB; +}; + +/************************************************************/ +/* */ +/* Base class, for hierarchical relationships */ +/* */ +/************************************************************/ + +class GLUI_Control; + +/** + GLUI_Node is a node in a sort of tree of GLUI controls. + Each GLUI_Node has a list of siblings (in a circular list) + and a linked list of children. + + Everything onscreen is a GLUI_Node--windows, buttons, etc. + The nodes are traversed for event processing, sizing, redraws, etc. +*/ +class GLUI_Node +{ + friend class GLUI_Tree; /* JVK */ + friend class GLUI_Rollout; + friend class GLUI_Main; + +public: + GLUI_Node(); + virtual ~GLUI_Node() {} + + GLUI_Node *first_sibling(); + GLUI_Node *last_sibling(); + GLUI_Node *prev(); + GLUI_Node *next(); + + GLUI_Node *first_child() { return child_head; } + GLUI_Node *last_child() { return child_tail; } + GLUI_Node *parent() { return parent_node; } + + /** Link in a new child control */ + virtual int add_control( GLUI_Control *control ); + + void link_this_to_parent_last (GLUI_Node *parent ); + void link_this_to_parent_first(GLUI_Node *parent ); + void link_this_to_sibling_next(GLUI_Node *sibling ); + void link_this_to_sibling_prev(GLUI_Node *sibling ); + void unlink(); + + void dump( FILE *out, const char *name ); + +protected: + static void add_child_to_control(GLUI_Node *parent,GLUI_Control *child); + GLUI_Node *parent_node; + GLUI_Node *child_head; + GLUI_Node *child_tail; + GLUI_Node *next_sibling; + GLUI_Node *prev_sibling; +}; + + +/************************************************************/ +/* */ +/* Standard Bitmap stuff */ +/* */ +/************************************************************/ + +enum GLUI_StdBitmaps_Codes +{ + GLUI_STDBITMAP_CHECKBOX_OFF = 0, + GLUI_STDBITMAP_CHECKBOX_ON, + GLUI_STDBITMAP_RADIOBUTTON_OFF, + GLUI_STDBITMAP_RADIOBUTTON_ON, + GLUI_STDBITMAP_UP_ARROW, + GLUI_STDBITMAP_DOWN_ARROW, + GLUI_STDBITMAP_LEFT_ARROW, + GLUI_STDBITMAP_RIGHT_ARROW, + GLUI_STDBITMAP_SPINNER_UP_OFF, + GLUI_STDBITMAP_SPINNER_UP_ON, + GLUI_STDBITMAP_SPINNER_DOWN_OFF, + GLUI_STDBITMAP_SPINNER_DOWN_ON, + GLUI_STDBITMAP_CHECKBOX_OFF_DIS, /*** Disactivated control bitmaps ***/ + GLUI_STDBITMAP_CHECKBOX_ON_DIS, + GLUI_STDBITMAP_RADIOBUTTON_OFF_DIS, + GLUI_STDBITMAP_RADIOBUTTON_ON_DIS, + GLUI_STDBITMAP_SPINNER_UP_DIS, + GLUI_STDBITMAP_SPINNER_DOWN_DIS, + GLUI_STDBITMAP_LISTBOX_UP, + GLUI_STDBITMAP_LISTBOX_DOWN, + GLUI_STDBITMAP_LISTBOX_UP_DIS, + GLUI_STDBITMAP_NUM_ITEMS +}; + +/************************************************************/ +/* */ +/* Class GLUI_Bitmap */ +/* */ +/************************************************************/ + +/** + GLUI_Bitmap is a simple 2D texture map. It's used + to represent small textures like checkboxes, arrows, etc. + via the GLUI_StdBitmaps class. +*/ +class GLUI_Bitmap +{ + friend class GLUI_StdBitmaps; + +public: + GLUI_Bitmap(); + ~GLUI_Bitmap(); + + /** Create bitmap from greyscale byte image */ + void init_grey(unsigned char *array); + + /** Create bitmap from color int image */ + void init(int *array); + +private: + /** RGB pixel data */ + unsigned char *pixels; + int w, h; +}; + + +/************************************************************/ +/* */ +/* Class GLUI_StdBitmap */ +/* */ +/************************************************************/ + +/** + Keeps an array of GLUI_Bitmap objects to represent all the + images used in the UI: checkboxes, arrows, etc. +*/ +class GLUI_StdBitmaps +{ +public: + GLUI_StdBitmaps(); + ~GLUI_StdBitmaps(); + + /** Return the width (in pixels) of the n'th standard bitmap. */ + int width (int n) const; + /** Return the height (in pixels) of the n'th standard bitmap. */ + int height(int n) const; + + /** Draw the n'th standard bitmap (one of the enums + listed in GLUI_StdBitmaps_Codes) at pixel corner (x,y). + */ + void draw(int n, int x, int y) const; + +private: + GLUI_Bitmap bitmaps[GLUI_STDBITMAP_NUM_ITEMS]; +}; + +/************************************************************/ +/* */ +/* Master GLUI Class */ +/* */ +/************************************************************/ + +/** + The master manages our interaction with GLUT. + There's only one GLUI_Master_Object. +*/ +class GLUI_Master_Object +{ + + friend void glui_idle_func(); + +public: + + GLUI_Master_Object(); + ~GLUI_Master_Object(); + + GLUI_Node gluis; + GLUI_Control *active_control, *curr_left_button_glut_menu; + GLUI *active_control_glui; + int glui_id_counter; + + GLUI_Glut_Window *find_glut_window( int window_id ); + + void set_glutIdleFunc(void (*f)(void)); + + /************** + void (*glut_keyboard_CB)(unsigned char, int, int); + void (*glut_reshape_CB)(int, int); + void (*glut_special_CB)(int, int, int); + void (*glut_mouse_CB)(int,int,int,int); + + void (*glut_passive_motion_CB)(int,int); + void (*glut_visibility_CB)(int); + void (*glut_motion_CB)(int,int); + void (*glut_display_CB)(void); + void (*glut_entry_CB)(int); + **********/ + + void set_left_button_glut_menu_control( GLUI_Control *control ); + + /********** GLUT callthroughs **********/ + /* These are the glut callbacks that we do not handle */ + + void set_glutReshapeFunc (void (*f)(int width, int height)); + void set_glutKeyboardFunc(void (*f)(unsigned char key, int x, int y)); + void set_glutSpecialFunc (void (*f)(int key, int x, int y)); + void set_glutMouseFunc (void (*f)(int, int, int, int )); + + void set_glutDisplayFunc(void (*f)(void)) {glutDisplayFunc(f);} + void set_glutTimerFunc(unsigned int millis, void (*f)(int value), int value) + { ::glutTimerFunc(millis,f,value);} + void set_glutOverlayDisplayFunc(void(*f)(void)){glutOverlayDisplayFunc(f);} + void set_glutSpaceballMotionFunc(Int3_CB f) {glutSpaceballMotionFunc(f);} + void set_glutSpaceballRotateFunc(Int3_CB f) {glutSpaceballRotateFunc(f);} + void set_glutSpaceballButtonFunc(Int2_CB f) {glutSpaceballButtonFunc(f);} + void set_glutTabletMotionFunc(Int2_CB f) {glutTabletMotionFunc(f);} + void set_glutTabletButtonFunc(Int4_CB f) {glutTabletButtonFunc(f);} + /* void set_glutWindowStatusFunc(Int1_CB f) {glutWindowStatusFunc(f);} */ + void set_glutMenuStatusFunc(Int3_CB f) {glutMenuStatusFunc(f);} + void set_glutMenuStateFunc(Int1_CB f) {glutMenuStateFunc(f);} + void set_glutButtonBoxFunc(Int2_CB f) {glutButtonBoxFunc(f);} + void set_glutDialsFunc(Int2_CB f) {glutDialsFunc(f);} + + + GLUI *create_glui( const char *name, long flags=0, int x=-1, int y=-1 ); + GLUI *create_glui_subwindow( int parent_window, long flags=0 ); + GLUI *find_glui_by_window_id( int window_id ); + void get_viewport_area( int *x, int *y, int *w, int *h ); + void auto_set_viewport(); + void close_all(); + void sync_live_all(); + + void reshape(); + + float get_version() { return GLUI_VERSION; } + + void glui_setIdleFuncIfNecessary(void); + +private: + GLUI_Node glut_windows; + void (*glut_idle_CB)(void); + + void add_cb_to_glut_window(int window,int cb_type,void *cb); +}; + +/** + This is the only GLUI_Master_Object in existence. +*/ +extern GLUI_Master_Object GLUI_Master; + +/************************************************************/ +/* */ +/* Class for managing a GLUT window */ +/* */ +/************************************************************/ + +/** + A top-level window. The GLUI_Master GLUT callback can route events + to the callbacks in this class, for arbitrary use by external users. + (see GLUI_Master_Object::set_glutKeyboardFunc). + + This entire approach seems to be superceded by the "subwindow" flavor + of GLUI. +*/ +class GLUI_Glut_Window : public GLUI_Node +{ +public: + GLUI_Glut_Window(); + + int glut_window_id; + + /*********** Pointers to GLUT callthrough functions *****/ + void (*glut_keyboard_CB)(unsigned char, int, int); + void (*glut_special_CB)(int, int, int); + void (*glut_reshape_CB)(int, int); + void (*glut_passive_motion_CB)(int,int); + void (*glut_mouse_CB)(int,int,int,int); + void (*glut_visibility_CB)(int); + void (*glut_motion_CB)(int,int); + void (*glut_display_CB)(void); + void (*glut_entry_CB)(int); +}; + +/************************************************************/ +/* */ +/* Main Window GLUI class (not user-level) */ +/* */ +/************************************************************/ + +/** + A GLUI_Main handles GLUT events for one window, routing them to the + appropriate controls. The central user-visible "GLUI" class + inherits from this class; users should not allocate GLUT_Main objects. + + There's a separate GLUI_Main object for: + - Each top-level window with GUI stuff in it. + - Each "subwindow" of another top-level window. + + All the GLUI_Main objects are listed in GLUI_Master.gluis. + A better name for this class might be "GLUI_Environment"; + this class provides the window-level context for every control. +*/ +class GLUI_Main : public GLUI_Node +{ + /********** Friend classes *************/ + + friend class GLUI_Control; + friend class GLUI_Rotation; + friend class GLUI_Translation; + friend class GLUI; + friend class GLUI_Master_Object; + + /*********** Friend functions **********/ + + friend void glui_mouse_func(int button, int state, int x, int y); + friend void glui_keyboard_func(unsigned char key, int x, int y); + friend void glui_special_func(int key, int x, int y); + friend void glui_passive_motion_func(int x, int y); + friend void glui_reshape_func( int w, int h ); + friend void glui_visibility_func(int state); + friend void glui_motion_func(int x, int y); + friend void glui_entry_func(int state); + friend void glui_display_func( void ); + friend void glui_idle_func(void); + + friend void glui_parent_window_reshape_func( int w, int h ); + friend void glui_parent_window_keyboard_func( unsigned char, int, int ); + friend void glui_parent_window_special_func( int, int, int ); + friend void glui_parent_window_mouse_func( int, int, int, int ); + +protected: + /*** Variables ***/ + int main_gfx_window_id; + int mouse_button_down; + int glut_window_id; + int top_level_glut_window_id; + GLUI_Control *active_control; + GLUI_Control *mouse_over_control; + GLUI_Panel *main_panel; + enum buffer_mode_t { + buffer_front=1, ///< Draw updated controls directly to screen. + buffer_back=2 ///< Double buffering: postpone updates until next redraw. + }; + buffer_mode_t buffer_mode; ///< Current drawing mode + int curr_cursor; + int w, h; + long flags; + bool closing; + int parent_window; + int glui_id; + + /********** Misc functions *************/ + + GLUI_Control *find_control( int x, int y ); + GLUI_Control *find_next_control( GLUI_Control *control ); + GLUI_Control *find_next_control_rec( GLUI_Control *control ); + GLUI_Control *find_next_control_( GLUI_Control *control ); + GLUI_Control *find_prev_control( GLUI_Control *control ); + void create_standalone_window( const char *name, int x=-1, int y=-1 ); + void create_subwindow( int parent,int window_alignment ); + void setup_default_glut_callbacks( void ); + + void mouse(int button, int state, int x, int y); + void keyboard(unsigned char key, int x, int y); + void special(int key, int x, int y); + void passive_motion(int x, int y); + void reshape( int w, int h ); + void visibility(int state); + void motion(int x, int y); + void entry(int state); + void display( void ); + void idle(void); + int needs_idle(void); + + void (*glut_mouse_CB)(int, int, int, int); + void (*glut_keyboard_CB)(unsigned char, int, int); + void (*glut_special_CB)(int, int, int); + void (*glut_reshape_CB)(int, int); + + + /*********** Controls ************/ + + virtual int add_control( GLUI_Node *parent, GLUI_Control *control ); + + + /********** Constructors and Destructors ***********/ + + GLUI_Main( void ); + +public: + GLUI_StdBitmaps std_bitmaps; + GLUI_String window_name; + RGBc bkgd_color; + float bkgd_color_f[3]; + + void *font; + int curr_modifiers; + + void adjust_glut_xy( int &x, int &y ) { x; y = h-y; } + void activate_control( GLUI_Control *control, int how ); + void align_controls( GLUI_Control *control ); + void deactivate_current_control( void ); + + /** Draw a 3D-look pushed-out box around this rectangle */ + void draw_raised_box( int x, int y, int w, int h ); + /** Draw a 3D-look pushed-in box around this rectangle */ + void draw_lowered_box( int x, int y, int w, int h ); + + /** Return true if this control should redraw itself immediately (front buffer); + Or queue up a redraw and return false if it shouldn't (back buffer). + */ + bool should_redraw_now(GLUI_Control *ctl); + + /** Switch to the appropriate draw buffer now. Returns the old draw buffer. + This routine should probably only be called from inside the GLUI_DrawingSentinal, + in glui_internal_control.h + */ + int set_current_draw_buffer(); + /** Go back to using this draw buffer. Undoes set_current_draw_buffer. */ + void restore_draw_buffer( int buffer_state ); + + /** Pack, resize the window, and redraw all the controls. */ + void refresh(); + + /** Redraw the main graphics window */ + void post_update_main_gfx(); + + /** Recompute the sizes and positions of all controls */ + void pack_controls(); + + void close_internal(); + void check_subwindow_position(); + void set_ortho_projection(); + void set_viewport(); + int get_glut_window_id( void ) { return glut_window_id; } /* JVK */ +}; + +/************************************************************/ +/* */ +/* GLUI_Control: base class for all controls */ +/* */ +/************************************************************/ + +/** + All the GUI objects inherit from GLUI_Control: buttons, + checkboxes, labels, edit boxes, scrollbars, etc. + Most of the work of this class is in routing events, + like keystrokes, mouseclicks, redraws, and sizing events. + + Yes, this is a huge and hideous class. It needs to be + split up into simpler subobjects. None of the data members + should be directly accessed by users (they should be protected, + not public); only subclasses. +*/ +class GLUI_Control : public GLUI_Node +{ +public: + +/** Onscreen coordinates */ + int w, h; /* dimensions of control */ + int x_abs, y_abs; + int x_off, y_off_top, y_off_bot; /* INNER margins, by which child + controls are indented */ + int contain_x, contain_y; + int contain_w, contain_h; + /* if this is a container control (e.g., + radiogroup or panel) this indicated dimensions + of inner area in which controls reside */ + +/** "activation" for tabbing between controls. */ + int active_type; ///< "GLUI_CONTROL_ACTIVE_..." + bool active; ///< If true, we've got the focus + bool can_activate; ///< If false, remove from tab order. + bool spacebar_mouse_click; ///< Spacebar simulates click. + +/** Callbacks */ + long user_id; ///< Integer to pass to callback function. + GLUI_CB callback; ///< User callback function, or NULL. + +/** Variable value storage */ + float float_val; /**< Our float value */ + int int_val; /**< Our integer value */ + float float_array_val[GLUI_DEF_MAX_ARRAY]; + int float_array_size; + GLUI_String text; /**< The text inside this control */ + +/** "Live variable" updating */ + void *ptr_val; /**< A pointer to the user's live variable value */ + int live_type; + bool live_inited; + /* These variables store the last value that live variable was known to have. */ + int last_live_int; + float last_live_float; + GLUI_String last_live_text; + float last_live_float_array[GLUI_DEF_MAX_ARRAY]; + +/** Properties of our control */ + GLUI *glui; /**< Our containing event handler (NEVER NULL during event processing!) */ + bool is_container; /**< Is this a container class (e.g., panel) */ + int alignment; + bool enabled; /**< Is this control grayed out? */ + GLUI_String name; /**< The name of this control */ + void *font; /**< Our glutbitmap font */ + bool collapsible, is_open; + GLUI_Node collapsed_node; + bool hidden; /* Collapsed controls (and children) are hidden */ + int char_widths[CHAR_WIDTH_HASH_SIZE][2]; /* Character width hash table */ + +public: + /*** Get/Set values ***/ + virtual void set_name( const char *string ); + virtual void set_int_val( int new_int ) { int_val = new_int; output_live(true); } + virtual void set_float_val( float new_float ) { float_val = new_float; output_live(true); } + virtual void set_ptr_val( void *new_ptr ) { ptr_val = new_ptr; output_live(true); } + virtual void set_float_array_val( float *array_ptr ); + + virtual float get_float_val( void ) { return float_val; } + virtual int get_int_val( void ) { return int_val; } + virtual void get_float_array_val( float *array_ptr ); + virtual int get_id( void ) const { return user_id; } + virtual void set_id( int id ) { user_id=id; } + + virtual int mouse_down_handler( int local_x, int local_y ) { local_x; local_y; return false; } + virtual int mouse_up_handler( int local_x, int local_y, bool inside ) { local_x; local_y; inside; return false; } + virtual int mouse_held_down_handler( int local_x, int local_y, bool inside) { local_x; local_y; inside; return false; } + virtual int key_handler( unsigned char key, int modifiers ) { key; modifiers; return false; } + virtual int special_handler( int key,int modifiers ) { key; modifiers; return false; } + + virtual void update_size( void ) { } + virtual void idle( void ) { } + virtual int mouse_over( int state, int x, int y ) { state; x; y; return false; } + + virtual void enable( void ); + virtual void disable( void ); + virtual void activate( int how ) { how; active = true; } + virtual void deactivate( void ) { active = false; } + + /** Hide (shrink into a rollout) and unhide (expose from a rollout) */ + void hide_internal( int recurse ); + void unhide_internal( int recurse ); + + /** Return true if it currently makes sense to draw this class. */ + int can_draw( void ) { return (glui != NULL && hidden == false); } + + /** Redraw this control. + In single-buffering mode (drawing to GL_FRONT), this is just + a call to translate_and_draw_front (after a can_draw() check). + In double-buffering mode (drawing to GL_BACK), this queues up + a redraw and returns false, since you shouldn't draw yet. + */ + void redraw(void); + + /** Redraw everybody in our window. */ + void redraw_window(void); + + virtual void align( void ); + void pack( int x, int y ); /* Recalculate positions and offsets */ + void pack_old( int x, int y ); + void draw_recursive( int x, int y ); + int set_to_glut_window( void ); + void restore_window( int orig ); + void translate_and_draw_front( void ); + void translate_to_origin( void ) + {glTranslatef((float)x_abs+.5f,(float)y_abs+.5f,0.0f);} + virtual void draw( int x, int y )=0; + void set_font( void *new_font ); + void *get_font( void ); + int string_width( const char *text ); + int string_width( const GLUI_String &str ) + { return string_width(str.c_str()); } + int char_width( char c ); + + void draw_name( int x, int y ); + void draw_box_inwards_outline( int x_min, int x_max, + int y_min, int y_max ); + void draw_box( int x_min, int x_max, int y_min, int y_max, + float r, float g, float b ); + void draw_bkgd_box( int x_min, int x_max, int y_min, int y_max ); + void draw_emboss_box( int x_min, int x_max,int y_min,int y_max); + void draw_string( const char *text ); + void draw_string( const GLUI_String &s ) + { draw_string(s.c_str()); } + void draw_char( char c ); + void draw_active_box( int x_min, int x_max, int y_min, int y_max ); + void set_to_bkgd_color( void ); + + void set_w( int new_w ); + void set_h( int new_w ); + void set_alignment( int new_align ); + void sync_live( int recurse, int draw ); /* Reads live variable */ + void init_live( void ); + void output_live( int update_main_gfx ); /** Writes live variable **/ + virtual void set_text( const char *t ) { t; } + void execute_callback( void ); + void get_this_column_dims( int *col_x, int *col_y, + int *col_w, int *col_h, + int *col_x_off, int *col_y_off ); + virtual bool needs_idle( void ) const; + virtual bool wants_tabs() const { return false; } + + GLUI_Control(void) + { + x_off = GLUI_XOFF; + y_off_top = GLUI_YOFF; + y_off_bot = GLUI_YOFF; + x_abs = GLUI_XOFF; + y_abs = GLUI_YOFF; + active = false; + enabled = true; + int_val = 0; + last_live_int = 0; + float_array_size = 0; + glui_format_str(name, "Control: %p", this); + float_val = 0.0; + last_live_float = 0.0; + ptr_val = NULL; + glui = NULL; + w = GLUI_DEFAULT_CONTROL_WIDTH; + h = GLUI_DEFAULT_CONTROL_HEIGHT; + font = NULL; + active_type = GLUI_CONTROL_ACTIVE_MOUSEDOWN; + alignment = GLUI_ALIGN_LEFT; + is_container = false; + can_activate = true; /* By default, you can activate a control */ + spacebar_mouse_click = true; /* Does spacebar simulate a mouse click? */ + live_type = GLUI_LIVE_NONE; + text = ""; + last_live_text == ""; + live_inited = false; + collapsible = false; + is_open = true; + hidden = false; + memset(char_widths, -1, sizeof(char_widths)); /* JVK */ + int i; + for( i=0; iint_val = 1; set_color(red, green, blue); } } + void disable_bar() { if (column) { column->int_val = 0; } } + void set_child_number(int c) { child_number = c; } + void set_level_color(float r, float g, float b) { + lred = r; + lgreen = g; + lblue = b; + } + void set_color(float r, float g, float b) { + red = r; + green = g; + blue = b; + } +protected: + void common_init() + { + currently_inside = false; + initially_inside = false; + can_activate = true; + is_container = true; + h = GLUI_DEFAULT_CONTROL_HEIGHT + 7; + w = GLUI_DEFAULT_CONTROL_WIDTH; + y_off_top = 21; + collapsible = true; + red = .5; + green = .5; + blue = .5; + lred = 0; + lgreen = 0; + lblue = 0; + column = NULL; + is_current = 0; + child_number = 0; + format = 0; + panel = NULL; + name = ""; + level_name = ""; + level = 0; + + }; +}; + + +/************************************************************/ +/* */ +/* TreePanel class (container) JVK */ +/* */ +/************************************************************/ + +/** + Manages, maintains, and formats a tree of GLUI_Tree objects. + These are shown in a heirarchical, collapsible display. + + FIXME: There's an infinite loop in the traversal code (OSL 2006/06) +*/ +class GLUI_TreePanel : public GLUI_Panel +{ +public: + GLUI_TreePanel(GLUI_Node *parent, const char *name, + bool open=false, int inset=0); + + int max_levels; + int next_id; + int format; + float red; + float green; + float blue; + float lred; + float lgreen; + float lblue; + int root_children; + /* These variables allow the tree panel to traverse the tree + using only two function calls. (Well, four, if you count + going in reverse */ + + GLUI_Tree *curr_branch; /* Current Branch */ + GLUI_Panel *curr_root; /* Current Root */ + +public: + void set_color(float r, float g, float b); + void set_level_color(float r, float g, float b); + void set_format(int f) { format = f; } + + /* Adds branch to curr_root */ + GLUI_Tree * ab(const char *name, GLUI_Tree *root = NULL); + /* Goes up one level, resets curr_root and curr_branch to parents*/ + void fb(GLUI_Tree *branch= NULL); + /* Deletes the curr_branch, goes up one level using fb */ + void db(GLUI_Tree *branch = NULL); + /* Finds the very last branch of curr_root, resets vars */ + void descendBranch(GLUI_Panel *root = NULL); + /* Resets curr_root and curr branch to TreePanel and lastChild */ + void resetToRoot(GLUI_Panel *new_root = NULL); + void next( void ); + void refresh( void ); + void expand_all( void ); + void collapse_all( void ); + void update_all( void ); + void initNode(GLUI_Tree *temp); + void formatNode(GLUI_Tree *temp); + +protected: + int uniqueID( void ) { next_id++; return next_id - 1; } + void common_init() + { + GLUI_Panel(); + next_id = 0; + curr_root = this; + curr_branch = NULL; + red = .5; + green = .5; + blue = .5; + root_children = 0; + } +}; + +/************************************************************/ +/* */ +/* User-Level GLUI class */ +/* */ +/************************************************************/ + +class GLUI_Rotation; +class GLUI_Translation; + +/** + The main user-visible interface object to GLUI. + +*/ +class GLUI : public GLUI_Main +{ +public: +/** DEPRECATED interface for creating new GLUI objects */ + int add_control( GLUI_Control *control ) { return main_panel->add_control(control); } + + void add_column( int draw_bar = true ); + void add_column_to_panel( GLUI_Panel *panel, int draw_bar = true ); + + void add_separator( void ); + void add_separator_to_panel( GLUI_Panel *panel ); + + GLUI_RadioGroup + *add_radiogroup( int *live_var=NULL, + int user_id=-1,GLUI_CB callback=GLUI_CB()); + + GLUI_RadioGroup + *add_radiogroup_to_panel( GLUI_Panel *panel, + int *live_var=NULL, + int user_id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_RadioButton + *add_radiobutton_to_group( GLUI_RadioGroup *group, + const char *name ); + + GLUI_Listbox *add_listbox( const char *name, int *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Listbox *add_listbox_to_panel( GLUI_Panel *panel, + const char *name, int *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB()); + + GLUI_Rotation *add_rotation( const char *name, float *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Rotation *add_rotation_to_panel( GLUI_Panel *panel, + const char *name, float *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB()); + + GLUI_Translation *add_translation( const char *name, + int trans_type, float *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Translation *add_translation_to_panel( + GLUI_Panel *panel, const char *name, + int trans_type, float *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB()); + + GLUI_Checkbox *add_checkbox( const char *name, + int *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB()); + GLUI_Checkbox *add_checkbox_to_panel( GLUI_Panel *panel, const char *name, + int *live_var=NULL, int id=-1, + GLUI_CB callback=GLUI_CB()); + + GLUI_Button *add_button( const char *name, int id=-1, + GLUI_CB callback=GLUI_CB()); + GLUI_Button *add_button_to_panel( GLUI_Panel *panel, const char *name, + int id=-1, GLUI_CB callback=GLUI_CB() ); + + GLUI_StaticText *add_statictext( const char *name ); + GLUI_StaticText *add_statictext_to_panel( GLUI_Panel *panel, const char *name ); + + GLUI_EditText *add_edittext( const char *name, + int data_type=GLUI_EDITTEXT_TEXT, + void*live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_EditText *add_edittext_to_panel( GLUI_Panel *panel, + const char *name, + int data_type=GLUI_EDITTEXT_TEXT, + void *live_var=NULL, int id=-1, + GLUI_CB callback=GLUI_CB() ); + GLUI_EditText *add_edittext( const char *name, GLUI_String& live_var, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_EditText *add_edittext_to_panel( GLUI_Panel *panel, const char *name, + GLUI_String& live_var, int id=-1, + GLUI_CB callback=GLUI_CB() ); + + GLUI_Spinner *add_spinner( const char *name, + int data_type=GLUI_SPINNER_INT, + void *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Spinner *add_spinner_to_panel( GLUI_Panel *panel, + const char *name, + int data_type=GLUI_SPINNER_INT, + void *live_var=NULL, + int id=-1, + GLUI_CB callback=GLUI_CB() ); + + GLUI_Panel *add_panel( const char *name, int type=GLUI_PANEL_EMBOSSED ); + GLUI_Panel *add_panel_to_panel( GLUI_Panel *panel, const char *name, + int type=GLUI_PANEL_EMBOSSED ); + + + GLUI_Rollout *add_rollout( const char *name, int open=true, + int type=GLUI_PANEL_EMBOSSED); + GLUI_Rollout *add_rollout_to_panel( GLUI_Panel *panel, const char *name, + int open=true, + int type=GLUI_PANEL_EMBOSSED); + + +/** Set the window where our widgets should be displayed. */ + void set_main_gfx_window( int window_id ); + int get_glut_window_id( void ) { return glut_window_id; } + + void enable( void ) { main_panel->enable(); } + void disable( void ); + + void sync_live( void ); + + void close( void ); + + void show( void ); + void hide( void ); + + /***** GLUT callback setup functions *****/ + /* + void set_glutDisplayFunc(void (*f)(void)); + void set_glutReshapeFunc(void (*f)(int width, int height)); + void set_glutKeyboardFunc(void (*f)(unsigned char key, int x, int y)); + void set_glutSpecialFunc(void (*f)(int key, int x, int y)); + void set_glutMouseFunc(void (*f)(int button, int state, int x, int y)); + void set_glutMotionFunc(void (*f)(int x, int y)); + void set_glutPassiveMotionFunc(void (*f)(int x, int y)); + void set_glutEntryFunc(void (*f)(int state)); + void set_glutVisibilityFunc(void (*f)(int state)); + void set_glutInit( int *argcp, const char **argv ); + void set_glutInitWindowSize(int width, int height); + void set_glutInitWindowPosition(int x, int y); + void set_glutInitDisplayMode(unsigned int mode); + int set_glutCreateWindow(const char *name); + */ + + /***** Constructors and desctructors *****/ + + int init( const char *name, long flags, int x, int y, int parent_window ); +protected: + virtual int add_control( GLUI_Node *parent, GLUI_Control *control ) { + return GLUI_Main::add_control( parent, control ); + } +}; + +/************************************************************/ +/* */ +/* EditText class */ +/* */ +/************************************************************/ + +class GLUI_EditText : public GLUI_Control +{ +public: + int has_limits; + int data_type; + GLUI_String orig_text; + int insertion_pt; + int title_x_offset; + int text_x_offset; + int substring_start; /*substring that gets displayed in box*/ + int substring_end; + int sel_start, sel_end; /* current selection */ + int num_periods; + int last_insertion_pt; + float float_low, float_high; + int int_low, int_high; + GLUI_Spinner *spinner; + int debug; + int draw_text_only; + + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key, int modifiers ); + + void activate( int how ); + void deactivate( void ); + + void draw( int x, int y ); + + int mouse_over( int state, int x, int y ); + + int find_word_break( int start, int direction ); + int substring_width( int start, int end ); + void clear_substring( int start, int end ); + int find_insertion_pt( int x, int y ); + int update_substring_bounds( void ); + void update_and_draw_text( void ); + void draw_text( int x, int y ); + void draw_insertion_pt( void ); + void set_numeric_text( void ); + void update_x_offsets( void ); + void update_size( void ); + + void set_float_limits( float low,float high,int limit_type=GLUI_LIMIT_CLAMP); + void set_int_limits( int low, int high, int limit_type=GLUI_LIMIT_CLAMP ); + void set_float_val( float new_val ); + void set_int_val( int new_val ); + void set_text( const char *text ); + void set_text( const GLUI_String &s) { set_text(s.c_str()); } + const char *get_text() { return text.c_str(); } + + void dump( FILE *out, const char *text ); + + // Constructor, no live variable + GLUI_EditText( GLUI_Node *parent, const char *name, + int text_type=GLUI_EDITTEXT_TEXT, + int id=-1, GLUI_CB callback=GLUI_CB() ); + // Constructor, int live variable + GLUI_EditText( GLUI_Node *parent, const char *name, + int *live_var, + int id=-1, GLUI_CB callback=GLUI_CB() ); + // Constructor, float live variable + GLUI_EditText( GLUI_Node *parent, const char *name, + float *live_var, + int id=-1, GLUI_CB callback=GLUI_CB() ); + // Constructor, char* live variable + GLUI_EditText( GLUI_Node *parent, const char *name, + char *live_var, + int id=-1, GLUI_CB callback=GLUI_CB() ); + // Constructor, std::string live variable + GLUI_EditText( GLUI_Node *parent, const char *name, + std::string &live_var, + int id=-1, GLUI_CB callback=GLUI_CB() ); + + // Deprecated constructor, only called internally + GLUI_EditText( GLUI_Node *parent, const char *name, + int text_type, void *live_var, + int id, GLUI_CB callback ); + // Deprecated constructor, only called internally + GLUI_EditText( void ) { common_init(); } + +protected: + void common_init( void ) { + h = GLUI_EDITTEXT_HEIGHT; + w = GLUI_EDITTEXT_WIDTH; + title_x_offset = 0; + text_x_offset = 55; + insertion_pt = -1; + last_insertion_pt = -1; + name = ""; + substring_start = 0; + data_type = GLUI_EDITTEXT_TEXT; + substring_end = 2; + num_periods = 0; + has_limits = GLUI_LIMIT_NONE; + sel_start = 0; + sel_end = 0; + active_type = GLUI_CONTROL_ACTIVE_PERMANENT; + can_activate = true; + spacebar_mouse_click = false; + spinner = NULL; + debug = false; + draw_text_only = false; + } + void common_construct( GLUI_Node *parent, const char *name, + int data_type, int live_type, void *live_var, + int id, GLUI_CB callback ); +}; + +/************************************************************/ +/* */ +/* CommandLine class */ +/* */ +/************************************************************/ + +class GLUI_CommandLine : public GLUI_EditText +{ +public: + typedef GLUI_EditText Super; + + enum { HIST_SIZE = 100 }; + std::vector hist_list; + int curr_hist; + int oldest_hist; + int newest_hist; + bool commit_flag; + +public: + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key,int modifiers ); + void deactivate( void ); + + virtual const char *get_history( int command_number ) const + { return hist_list[command_number - oldest_hist].c_str(); } + virtual GLUI_String& get_history_str( int command_number ) + { return hist_list[command_number - oldest_hist]; } + virtual const GLUI_String& get_history_str( int command_number ) const + { return hist_list[command_number - oldest_hist]; } + virtual void recall_history( int history_number ); + virtual void scroll_history( int direction ); + virtual void add_to_history( const char *text ); + virtual void reset_history( void ); + + void dump( FILE *out, const char *text ); + + + GLUI_CommandLine( GLUI_Node *parent, const char *name, void *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_CommandLine( void ) { common_init(); } +protected: + void common_init() { + hist_list.resize(HIST_SIZE); + curr_hist = 0; + oldest_hist = 0; + newest_hist = 0; + commit_flag = false; + } +}; + +/************************************************************/ +/* */ +/* RadioGroup class (container) */ +/* */ +/************************************************************/ + +class GLUI_RadioGroup : public GLUI_Control +{ +public: + int num_buttons; + + void draw( int x, int y ); + void set_name( const char *text ); + void set_int_val( int int_val ); + void set_selected( int int_val ); + + void draw_group( int translate ); + + GLUI_RadioGroup( GLUI_Node *parent, int *live_var=NULL, + int user_id=-1,GLUI_CB callback=GLUI_CB() ); + GLUI_RadioGroup( void ) { common_init(); } + +protected: + void common_init( void ) { + x_off = 0; + y_off_top = 0; + y_off_bot = 0; + is_container = true; + w = 300; + h = 300; + num_buttons = 0; + name = ""; + can_activate = false; + live_type = GLUI_LIVE_INT; + } +}; + +/************************************************************/ +/* */ +/* RadioButton class (container) */ +/* */ +/************************************************************/ + +class GLUI_RadioButton : public GLUI_Control +{ +public: + int orig_value; + bool currently_inside; + int text_x_offset; + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + + void draw( int x, int y ); + void update_size( void ); + + void draw_active_area( void ); + void draw_checked( void ); + void draw_unchecked( void ); + void draw_O( void ); + + GLUI_RadioButton( GLUI_RadioGroup *group, const char *name ); + GLUI_RadioGroup *group; + +protected: + void common_init() + { + glui_format_str( name, "RadioButton: %p", (void *) this ); + h = GLUI_RADIOBUTTON_SIZE; + group = NULL; + orig_value = -1; + text_x_offset = 18; + can_activate = true; + } +}; + + +/************************************************************/ +/* */ +/* Separator class (container) */ +/* */ +/************************************************************/ + +class GLUI_Separator : public GLUI_Control +{ +public: + void draw( int x, int y ); + + GLUI_Separator( GLUI_Node *parent ); + GLUI_Separator( void ) { common_init(); } + +protected: + void common_init() { + w = 100; + h = GLUI_SEPARATOR_HEIGHT; + can_activate = false; + } +}; + +#define GLUI_SPINNER_ARROW_WIDTH 12 +#define GLUI_SPINNER_ARROW_HEIGHT 8 +#define GLUI_SPINNER_ARROW_Y 2 + +#define GLUI_SPINNER_STATE_NONE 0 +#define GLUI_SPINNER_STATE_UP 1 +#define GLUI_SPINNER_STATE_DOWN 2 +#define GLUI_SPINNER_STATE_BOTH 3 + +#define GLUI_SPINNER_DEFAULT_GROWTH_EXP 1.05f + +/************************************************************/ +/* */ +/* Spinner class (container) */ +/* */ +/************************************************************/ + +class GLUI_Spinner : public GLUI_Control +{ +public: + // Constructor, no live var + GLUI_Spinner( GLUI_Node* parent, const char *name, + int data_type=GLUI_SPINNER_INT, int id=-1, GLUI_CB callback=GLUI_CB() ); + // Constructor, int live var + GLUI_Spinner( GLUI_Node* parent, const char *name, + int *live_var, int id=-1, GLUI_CB callback=GLUI_CB() ); + // Constructor, float live var + GLUI_Spinner( GLUI_Node* parent, const char *name, + float *live_var, int id=-1, GLUI_CB callback=GLUI_CB() ); + // Deprecated constructor + GLUI_Spinner( GLUI_Node* parent, const char *name, + int data_type, + void *live_var, + int id=-1, GLUI_CB callback=GLUI_CB() ); + // Deprecated constructor + GLUI_Spinner( void ) { common_init(); } + + bool currently_inside; + int state; + float growth, growth_exp; + int last_x, last_y; + int data_type; + int callback_count; + int last_int_val; + float last_float_val; + int first_callback; + float user_speed; + + GLUI_EditText *edittext; + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key,int modifiers ); + + void draw( int x, int y ); + void draw_pressed( void ); + void draw_unpressed( void ); + void draw_text( int sunken ); + + void update_size( void ); + + void set_float_limits( float low,float high,int limit_type=GLUI_LIMIT_CLAMP); + void set_int_limits( int low, int high,int limit_type=GLUI_LIMIT_CLAMP); + int find_arrow( int local_x, int local_y ); + void do_drag( int x, int y ); + void do_callbacks( void ); + void do_click( void ); + void idle( void ); + bool needs_idle( void ) const; + + const char *get_text( void ); + + void set_float_val( float new_val ); + void set_int_val( int new_val ); + float get_float_val( void ); + int get_int_val( void ); + void increase_growth( void ); + void reset_growth( void ); + + void set_speed( float speed ) { user_speed = speed; } + +protected: + void common_init() { + glui_format_str( name, "Spinner: %p", this ); + h = GLUI_EDITTEXT_HEIGHT; + w = GLUI_EDITTEXT_WIDTH; + x_off = 0; + y_off_top = 0; + y_off_bot = 0; + can_activate = true; + state = GLUI_SPINNER_STATE_NONE; + edittext = NULL; + growth_exp = GLUI_SPINNER_DEFAULT_GROWTH_EXP; + callback_count = 0; + first_callback = true; + user_speed = 1.0; + } + void common_construct( GLUI_Node* parent, const char *name, + int data_type, void *live_var, + int id, GLUI_CB callback ); +}; + +/************************************************************/ +/* */ +/* StaticText class */ +/* */ +/************************************************************/ + +class GLUI_StaticText : public GLUI_Control +{ +public: + void set_text( const char *text ); + void draw( int x, int y ); + void draw_text( void ); + void update_size( void ); + void erase_text( void ); + + GLUI_StaticText(GLUI_Node *parent, const char *name); + GLUI_StaticText( void ) { common_init(); } + +protected: + void common_init() { + h = GLUI_STATICTEXT_SIZE; + name = ""; + can_activate = false; + } +}; + +/************************************************************/ +/* */ +/* TextBox class - JVK */ +/* */ +/************************************************************/ + +class GLUI_TextBox : public GLUI_Control +{ +public: + /* GLUI Textbox - JVK */ + GLUI_TextBox(GLUI_Node *parent, GLUI_String &live_var, + bool scroll = false, int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_TextBox( GLUI_Node *parent, + bool scroll = false, int id=-1, + GLUI_CB callback=GLUI_CB() ); + + GLUI_String orig_text; + int insertion_pt; + int substring_start; /*substring that gets displayed in box*/ + int substring_end; + int sel_start, sel_end; /* current selection */ + int last_insertion_pt; + int debug; + int draw_text_only; + int tab_width; + int start_line; + int num_lines; + int curr_line; + int visible_lines; + int insert_x; /* Similar to "insertion_pt", these variables keep */ + int insert_y; /* track of where the ptr is, but in pixels */ + int keygoal_x; /* where up down keys would like to put insertion pt*/ + GLUI_Scrollbar *scrollbar; + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key,int modifiers ); + + void activate( int how ); + void deactivate( void ); + + void enable( void ); + void disable( void ); + + void draw( int x, int y ); + + int mouse_over( int state, int x, int y ); + + int get_box_width(); + int find_word_break( int start, int direction ); + int substring_width( int start, int end, int initial_width=0 ); + void clear_substring( int start, int end ); + int find_insertion_pt( int x, int y ); + int update_substring_bounds( void ); + void update_and_draw_text( void ); + void draw_text( int x, int y ); + void draw_insertion_pt( void ); + void update_x_offsets( void ); + void update_size( void ); + + void set_text( const char *text ); + const char *get_text( void ) { return text.c_str(); } + + void dump( FILE *out, char *text ); + void set_tab_w(int w) { tab_width = w; } + void set_start_line(int l) { start_line = l; } + static void scrollbar_callback(GLUI_Control*); + + bool wants_tabs( void ) const { return true; } + +protected: + void common_init() + { + h = GLUI_TEXTBOX_HEIGHT; + w = GLUI_TEXTBOX_WIDTH; + tab_width = GLUI_TAB_WIDTH; + num_lines = 0; + visible_lines = 0; + start_line = 0; + curr_line = 0; + insert_y = -1; + insert_x = -1; + insertion_pt = -1; + last_insertion_pt = -1; + name[0] = '\0'; + substring_start = 0; + substring_end = 2; + sel_start = 0; + sel_end = 0; + active_type = GLUI_CONTROL_ACTIVE_PERMANENT; + can_activate = true; + spacebar_mouse_click = false; + scrollbar = NULL; + debug = false; + draw_text_only = false; + } + void common_construct( + GLUI_Node *parent, GLUI_String *live_var, + bool scroll, int id, GLUI_CB callback); +}; + +/************************************************************/ +/* */ +/* List class - JVK */ +/* */ +/************************************************************/ + +class GLUI_List_Item : public GLUI_Node +{ +public: + GLUI_String text; + int id; +}; + +/************************************************************/ +/* */ +/* List class - JVK */ +/* */ +/************************************************************/ + +class GLUI_List : public GLUI_Control +{ +public: + /* GLUI List - JVK */ + GLUI_List( GLUI_Node *parent, bool scroll = false, + int id=-1, GLUI_CB callback=GLUI_CB() ); + /*, GLUI_Control *object = NULL + ,GLUI_InterObject_CB obj_cb = NULL);*/ + + GLUI_List( GLUI_Node *parent, + GLUI_String& live_var, bool scroll = false, + int id=-1, + GLUI_CB callback=GLUI_CB() + /*,GLUI_Control *object = NULL */ + /*,GLUI_InterObject_CB obj_cb = NULL*/); + + + GLUI_String orig_text; + int debug; + int draw_text_only; + int start_line; + int num_lines; + int curr_line; + int visible_lines; + GLUI_Scrollbar *scrollbar; + GLUI_List_Item items_list; + GLUI_Control *associated_object; + GLUI_CB obj_cb; + int cb_click_type; + int last_line; + int last_click_time; + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key,int modifiers ); + + void activate( int how ); + void deactivate( void ); + + void draw( int x, int y ); + + int mouse_over( int state, int x, int y ); + + int get_box_width(); + int find_word_break( int start, int direction ); + int substring_width( const char *t, int start, int end ); + int find_line( int x, int y ); + void update_and_draw_text( void ); + void draw_text( const char *t, int selected, int x, int y ); + void update_size( void ); + + + int add_item( int id, const char *text ); + int delete_item( const char *text ); + int delete_item( int id ); + int delete_all(); + + GLUI_List_Item *get_item_ptr( const char *text ); + GLUI_List_Item *get_item_ptr( int id ); + + void dump( FILE *out, const char *text ); + void set_start_line(int l) { start_line = l; } + static void scrollbar_callback(GLUI_Control*); + int get_current_item() { return curr_line; } + void set_click_type(int d) { + cb_click_type = d; } + void set_object_callback(GLUI_CB cb=GLUI_CB(), GLUI_Control*obj=NULL) + { obj_cb=cb; associated_object=obj; } + +protected: + void common_init() + { + h = GLUI_LIST_HEIGHT; + w = GLUI_LIST_WIDTH; + num_lines = 0; + visible_lines = 0; + start_line = 0; + curr_line = 0; + name[0] = '\0'; + active_type = GLUI_CONTROL_ACTIVE_PERMANENT; + can_activate = true; + spacebar_mouse_click = false; + scrollbar = NULL; + debug = false; + draw_text_only = false; + cb_click_type = GLUI_SINGLE_CLICK; + last_line = -1; + last_click_time = 0; + associated_object = NULL; + }; + void common_construct( + GLUI_Node *parent, + GLUI_String* live_var, bool scroll, + int id, + GLUI_CB callback + /*,GLUI_Control *object*/ + /*,GLUI_InterObject_CB obj_cb*/); +}; + +/************************************************************/ +/* */ +/* Scrollbar class - JVK */ +/* */ +/************************************************************/ + +class GLUI_Scrollbar : public GLUI_Control +{ +public: + // Constructor, no live var + GLUI_Scrollbar( GLUI_Node *parent, + const char *name, + int horz_vert=GLUI_SCROLL_HORIZONTAL, + int data_type=GLUI_SCROLL_INT, + int id=-1, GLUI_CB callback=GLUI_CB() + /*,GLUI_Control *object = NULL*/ + /*,GLUI_InterObject_CB obj_cb = NULL*/ + ); + + // Constructor, int live var + GLUI_Scrollbar( GLUI_Node *parent, const char *name, int horz_vert, + int *live_var, + int id=-1, GLUI_CB callback=GLUI_CB() + /*,GLUI_Control *object = NULL*/ + /*,GLUI_InterObject_CB obj_cb = NULL*/ + ); + + // Constructor, float live var + GLUI_Scrollbar( GLUI_Node *parent, const char *name, int horz_vert, + float *live_var, + int id=-1, GLUI_CB callback=GLUI_CB() + /*,GLUI_Control *object = NULL*/ + /*,GLUI_InterObject_CB obj_cb = NULL*/ + ); + + bool currently_inside; + int state; + float growth, growth_exp; + int last_x, last_y; + int data_type; + int callback_count; + int last_int_val; ///< Used to prevent repeated callbacks. + float last_float_val; + int first_callback; + float user_speed; + float float_min, float_max; + int int_min, int_max; + int horizontal; + double last_update_time; ///< GLUI_Time() we last advanced scrollbar. + double velocity_limit; ///< Maximum distance to advance per second. + int box_length; + int box_start_position; + int box_end_position; + int track_length; + + + /* Rather than directly access an Editbox or Textbox for + changing variables, a pointer to some object is defined + along with a static callback in the form func(void *, int) - + the int is the new value, the void * must be cast to that + particular object type before use. + */ + void * associated_object; /* Lets the Spinner manage it's own callbacks */ + GLUI_CB object_cb; /* function pointer to object call_back */ + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key,int modifiers ); + + void draw( int x, int y ); + void draw_pressed( void ); + void draw_unpressed( void ); + void draw_text( int sunken ); + + void update_size( void ); + + void set_int_limits( int low, int high,int limit_type=GLUI_LIMIT_CLAMP); + void set_float_limits( float low,float high,int limit_type=GLUI_LIMIT_CLAMP); + int find_arrow( int local_x, int local_y ); + void do_drag( int x, int y ); + void do_callbacks( void ); + void draw_scroll( void ); + void do_click( void ); + void idle( void ); + bool needs_idle( void ) const; + void set_int_val( int new_val ); + void set_float_val( float new_val ); + void increase_growth( void ); + void reset_growth( void ); + + void set_speed( float speed ) { user_speed = speed; }; + void update_scroll_parameters(); + void set_object_callback(GLUI_CB cb=GLUI_CB(), GLUI_Control*obj=NULL) + { object_cb=cb; associated_object=obj; } + +protected: + void common_init ( void ); + void common_construct( + GLUI_Node *parent, + const char *name, + int horz_vert, + int data_type, void* live_var, + int id, GLUI_CB callback + /*,GLUI_Control *object + ,GLUI_InterObject_CB obj_cb*/ + ); + + virtual void draw_scroll_arrow(int arrowtype, int x, int y); + virtual void draw_scroll_box(int x, int y, int w, int h); +}; + +/************************************************************/ +/* */ +/* Listbox class */ +/* */ +/************************************************************/ + +class GLUI_Listbox_Item : public GLUI_Node +{ +public: + GLUI_String text; + int id; +}; + +class GLUI_Listbox : public GLUI_Control +{ +public: + GLUI_String curr_text; + GLUI_Listbox_Item items_list; + int depressed; + + int orig_value; + bool currently_inside; + int text_x_offset, title_x_offset; + int glut_menu_id; + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int key_handler( unsigned char key,int modifiers ); + int special_handler( int key,int modifiers ); + + void update_size( void ); + void draw( int x, int y ); + int mouse_over( int state, int x, int y ); + + void set_int_val( int new_val ); + void dump( FILE *output ); + + int add_item( int id, const char *text ); + int delete_item( const char *text ); + int delete_item( int id ); + int sort_items( void ); + + int do_selection( int item ); + + GLUI_Listbox_Item *get_item_ptr( const char *text ); + GLUI_Listbox_Item *get_item_ptr( int id ); + + + GLUI_Listbox( GLUI_Node *parent, + const char *name, int *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Listbox( void ) { common_init(); } + +protected: + /** Change w and return true if we need to be widened to fit the current item. */ + bool recalculate_item_width( void ); + void common_init() { + glui_format_str( name, "Listbox: %p", this ); + w = GLUI_EDITTEXT_WIDTH; + h = GLUI_EDITTEXT_HEIGHT; + orig_value = -1; + title_x_offset = 0; + text_x_offset = 55; + can_activate = true; + curr_text = ""; + live_type = GLUI_LIVE_INT; /* This has an integer live var */ + depressed = false; + glut_menu_id = -1; + } + + ~GLUI_Listbox(); +}; + +/************************************************************/ +/* */ +/* Mouse_Interaction class */ +/* */ +/************************************************************/ + +/** + This is the superclass of translation and rotation widgets. +*/ +class GLUI_Mouse_Interaction : public GLUI_Control +{ +public: + /*int get_main_area_size( void ) { return MIN( h-18, */ + int draw_active_area_only; + + int mouse_down_handler( int local_x, int local_y ); + int mouse_up_handler( int local_x, int local_y, bool inside ); + int mouse_held_down_handler( int local_x, int local_y, bool inside ); + int special_handler( int key, int modifiers ); + void update_size( void ); + void draw( int x, int y ); + void draw_active_area( void ); + + /*** The following methods (starting with "iaction_") need to + be overloaded ***/ + virtual int iaction_mouse_down_handler( int local_x, int local_y ) = 0; + virtual int iaction_mouse_up_handler( int local_x, int local_y, bool inside )=0; + virtual int iaction_mouse_held_down_handler( int local_x, int local_y, bool inside )=0; + virtual int iaction_special_handler( int key, int modifiers )=0; + virtual void iaction_draw_active_area_persp( void )=0; + virtual void iaction_draw_active_area_ortho( void )=0; + virtual void iaction_dump( FILE *output )=0; + virtual void iaction_init( void ) = 0; + + GLUI_Mouse_Interaction( void ) { + glui_format_str( name, "Mouse_Interaction: %p", this ); + w = GLUI_MOUSE_INTERACTION_WIDTH; + h = GLUI_MOUSE_INTERACTION_HEIGHT; + can_activate = true; + live_type = GLUI_LIVE_NONE; + alignment = GLUI_ALIGN_CENTER; + draw_active_area_only = false; + } +}; + +/************************************************************/ +/* */ +/* Rotation class */ +/* */ +/************************************************************/ + +/** + An onscreen rotation controller--allows the user to interact with + a 3D rotation via a spaceball-like interface. +*/ +class GLUI_Rotation : public GLUI_Mouse_Interaction +{ +public: + Arcball *ball; + GLUquadricObj *quadObj; + bool can_spin, spinning; + float damping; + + int iaction_mouse_down_handler( int local_x, int local_y ); + int iaction_mouse_up_handler( int local_x, int local_y, bool inside ); + int iaction_mouse_held_down_handler( int local_x, int local_y, bool inside ); + int iaction_special_handler( int key, int modifiers ); + void iaction_init( void ) { init_ball(); } + void iaction_draw_active_area_persp( void ); + void iaction_draw_active_area_ortho( void ); + void iaction_dump( FILE *output ); + + /* void update_size( void ); */ + /* void draw( int x, int y ); */ + /* int mouse_over( int state, int x, int y ); */ + + void setup_texture( void ); + void setup_lights( void ); + void draw_ball( float radius ); + + void init_ball( void ); + + void reset( void ); + + bool needs_idle( void ) const; + void idle( void ); + + void copy_float_array_to_ball( void ); + void copy_ball_to_float_array( void ); + + void set_spin( float damp_factor ); + + GLUI_Rotation( GLUI_Node *parent, const char *name, float *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Rotation(void) { common_init(); } + +protected: + void common_init(); +}; + +/************************************************************/ +/* */ +/* Translation class */ +/* */ +/************************************************************/ + +/** + An onscreen translation controller--allows the user to interact with + a 3D translation. +*/ +class GLUI_Translation : public GLUI_Mouse_Interaction +{ +public: + int trans_type; /* Is this an XY or a Z controller? */ + int down_x, down_y; + float scale_factor; + GLUquadricObj *quadObj; + int trans_mouse_code; + float orig_x, orig_y, orig_z; + int locked; + + int iaction_mouse_down_handler( int local_x, int local_y ); + int iaction_mouse_up_handler( int local_x, int local_y, bool inside ); + int iaction_mouse_held_down_handler( int local_x, int local_y, bool inside ); + int iaction_special_handler( int key, int modifiers ); + void iaction_init( void ) { } + void iaction_draw_active_area_persp( void ); + void iaction_draw_active_area_ortho( void ); + void iaction_dump( FILE *output ); + + void set_speed( float s ) { scale_factor = s; } + + void setup_texture( void ); + void setup_lights( void ); + void draw_2d_arrow( int radius, int filled, int orientation ); + void draw_2d_x_arrows( int radius ); + void draw_2d_y_arrows( int radius ); + void draw_2d_z_arrows( int radius ); + void draw_2d_xy_arrows( int radius ); + + int get_mouse_code( int x, int y ); + + /* Float array is either a single float (for single-axis controls), + or two floats for X and Y (if an XY controller) */ + + float get_z( void ) { return float_array_val[0]; } + float get_x( void ) { return float_array_val[0]; } + float get_y( void ) { + if ( trans_type == GLUI_TRANSLATION_XY ) return float_array_val[1]; + else return float_array_val[0]; + } + + void set_z( float val ); + void set_x( float val ); + void set_y( float val ); + void set_one_val( float val, int index ); + + GLUI_Translation( GLUI_Node *parent, const char *name, + int trans_type, float *live_var=NULL, + int id=-1, GLUI_CB callback=GLUI_CB() ); + GLUI_Translation( void ) { common_init(); } + +protected: + void common_init() { + locked = GLUI_TRANSLATION_LOCK_NONE; + glui_format_str( name, "Translation: %p", this ); + w = GLUI_MOUSE_INTERACTION_WIDTH; + h = GLUI_MOUSE_INTERACTION_HEIGHT; + can_activate = true; + live_type = GLUI_LIVE_FLOAT_ARRAY; + float_array_size = 0; + alignment = GLUI_ALIGN_CENTER; + trans_type = GLUI_TRANSLATION_XY; + scale_factor = 1.0; + quadObj = NULL; + trans_mouse_code = GLUI_TRANSLATION_MOUSE_NONE; + } +}; + +/********** Misc functions *********************/ +int _glutBitmapWidthString( void *font, const char *s ); +void _glutBitmapString( void *font, const char *s ); + +/********** Our own callbacks for glut *********/ +/* These are the callbacks that we pass to glut. They take + some action if necessary, then (possibly) call the user-level + glut callbacks. +*/ + +void glui_display_func( void ); +void glui_reshape_func( int w, int h ); +void glui_keyboard_func(unsigned char key, int x, int y); +void glui_special_func(int key, int x, int y); +void glui_mouse_func(int button, int state, int x, int y); +void glui_motion_func(int x, int y); +void glui_passive_motion_func(int x, int y); +void glui_entry_func(int state); +void glui_visibility_func(int state); +void glui_idle_func(void); + +void glui_parent_window_reshape_func( int w, int h ); +void glui_parent_window_keyboard_func(unsigned char key, int x, int y); +void glui_parent_window_mouse_func(int, int, int, int ); +void glui_parent_window_special_func(int key, int x, int y); + +#endif diff --git a/Extras/glui/Jamfile b/Extras/glui/Jamfile new file mode 100644 index 000000000..75a8564ec --- /dev/null +++ b/Extras/glui/Jamfile @@ -0,0 +1,18 @@ +SubDir TOP Extras glui ; + +if $(GLUT.AVAILABLE) = "yes" +{ + + + Description glui : "glui" ; + Library glui : + [ Wildcard *.h *.cpp ] : noinstall +; + +CFlags glui : +; + +LibDepends glui : ; + + ExternalLibs bulletopenglsupport : GLUT ; +} diff --git a/Extras/glui/algebra3.cpp b/Extras/glui/algebra3.cpp new file mode 100644 index 000000000..ddc18f4f8 --- /dev/null +++ b/Extras/glui/algebra3.cpp @@ -0,0 +1,1609 @@ +/* + + algebra3.cpp, algebra3.h - C++ Vector and Matrix Algebra routines + + GLUI User Interface Toolkit (LGPL) + 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 + +*/ + +/************************************************************************** + + There are three vector classes and two matrix classes: vec2, vec3, + vec4, mat3, and mat4. + + All the standard arithmetic operations are defined, with '*' + for dot product of two vectors and multiplication of two matrices, + and '^' for cross product of two vectors. + + Additional functions include length(), normalize(), homogenize for + vectors, and print(), set(), apply() for all classes. + + There is a function transpose() for matrices, but note that it + does not actually change the matrix, + + When multiplied with a matrix, a vector is treated as a row vector + if it precedes the matrix (v*M), and as a column vector if it + follows the matrix (M*v). + + Matrices are stored in row-major form. + + A vector of one dimension (2d, 3d, or 4d) can be cast to a vector + of a higher or lower dimension. If casting to a higher dimension, + the new component is set by default to 1.0, unless a value is + specified: + vec3 a(1.0, 2.0, 3.0 ); + vec4 b( a, 4.0 ); // now b == {1.0, 2.0, 3.0, 4.0}; + When casting to a lower dimension, the vector is homogenized in + the lower dimension. E.g., if a 4d {X,Y,Z,W} is cast to 3d, the + resulting vector is {X/W, Y/W, Z/W}. It is up to the user to + insure the fourth component is not zero before casting. + + There are also the following function for building matrices: + identity2D(), translation2D(), rotation2D(), + scaling2D(), identity3D(), translation3D(), + rotation3D(), rotation3Drad(), scaling3D(), + perspective3D() + + + --------------------------------------------------------------------- + + Author: Jean-Francois DOUEg + Revised: Paul Rademacher + Version 3.2 - Feb 1998 + Revised: Nigel Stewart (GLUI Code Cleaning) + +**************************************************************************/ + +#include "algebra3.h" +#include "glui_internal.h" +#include + +#ifdef VEC_ERROR_FATAL +#ifndef VEC_ERROR +#define VEC_ERROR(E) { printf( "VERROR %s\n", E ); exit(1); } +#endif +#else +#ifndef VEC_ERROR +#define VEC_ERROR(E) { printf( "VERROR %s\n", E ); } +#endif +#endif + +/**************************************************************** + * * + * vec2 Member functions * + * * + ****************************************************************/ + +/******************** vec2 CONSTRUCTORS ********************/ + +vec2::vec2() +{ + n[VX] = n[VY] = 0.0; +} + +vec2::vec2(float x, float y) +{ + n[VX] = x; + n[VY] = y; +} + +vec2::vec2(const vec2 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; +} + +vec2::vec2(const vec3 &v) // it is up to caller to avoid divide-by-zero +{ + n[VX] = v.n[VX]/v.n[VZ]; + n[VY] = v.n[VY]/v.n[VZ]; +} + +vec2::vec2(const vec3 &v, int dropAxis) +{ + switch (dropAxis) + { + case VX: n[VX] = v.n[VY]; n[VY] = v.n[VZ]; break; + case VY: n[VX] = v.n[VX]; n[VY] = v.n[VZ]; break; + default: n[VX] = v.n[VX]; n[VY] = v.n[VY]; break; + } +} + +/******************** vec2 ASSIGNMENT OPERATORS ******************/ + +vec2 & vec2::operator=(const vec2 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + return *this; +} + +vec2 & vec2::operator+=(const vec2 &v) +{ + n[VX] += v.n[VX]; + n[VY] += v.n[VY]; + return *this; +} + +vec2 & vec2::operator-=(const vec2 &v) +{ + n[VX] -= v.n[VX]; + n[VY] -= v.n[VY]; + return *this; +} + +vec2 &vec2::operator*=(float d) +{ + n[VX] *= d; + n[VY] *= d; + return *this; +} + +vec2 &vec2::operator/=(float d) +{ + float d_inv = 1.0f/d; + n[VX] *= d_inv; + n[VY] *= d_inv; + return *this; +} + +float &vec2::operator[](int i) +{ + if (i < VX || i > VY) + //VEC_ERROR("vec2 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("vec2 [] operator: illegal access" ); + return n[i]; +} + +const float &vec2::operator[](int i) const +{ + if (i < VX || i > VY) + //VEC_ERROR("vec2 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("vec2 [] operator: illegal access" ); + + return n[i]; +} + +/******************** vec2 SPECIAL FUNCTIONS ********************/ + +float vec2::length() const +{ + return (float) sqrt(length2()); +} + +float vec2::length2() const +{ + return n[VX]*n[VX] + n[VY]*n[VY]; +} + +vec2 &vec2::normalize() // it is up to caller to avoid divide-by-zero +{ + *this /= length(); + return *this; +} + +vec2 &vec2::apply(V_FCT_PTR fct) +{ + n[VX] = (*fct)(n[VX]); + n[VY] = (*fct)(n[VY]); + return *this; +} + +void vec2::set( float x, float y ) +{ + n[VX] = x; n[VY] = y; +} + +/******************** vec2 FRIENDS *****************************/ + +vec2 operator-(const vec2 &a) +{ + return vec2(-a.n[VX],-a.n[VY]); +} + +vec2 operator+(const vec2 &a, const vec2& b) +{ + return vec2(a.n[VX]+b.n[VX], a.n[VY]+b.n[VY]); +} + +vec2 operator-(const vec2 &a, const vec2& b) +{ + return vec2(a.n[VX]-b.n[VX], a.n[VY]-b.n[VY]); +} + +vec2 operator*(const vec2 &a, float d) +{ + return vec2(d*a.n[VX], d*a.n[VY]); +} + +vec2 operator*(float d, const vec2 &a) +{ + return a*d; +} + +vec2 operator*(const mat3 &a, const vec2 &v) +{ + vec3 av; + + av.n[VX] = a.v[0].n[VX]*v.n[VX] + a.v[0].n[VY]*v.n[VY] + a.v[0].n[VZ]; + av.n[VY] = a.v[1].n[VX]*v.n[VX] + a.v[1].n[VY]*v.n[VY] + a.v[1].n[VZ]; + av.n[VZ] = a.v[2].n[VX]*v.n[VX] + a.v[2].n[VY]*v.n[VY] + a.v[2].n[VZ]; + + return av; +} + +vec2 operator*(const vec2 &v, const mat3 &a) +{ + return a.transpose() * v; +} + +vec3 operator*(const mat3 &a, const vec3 &v) +{ + vec3 av; + + av.n[VX] = a.v[0].n[VX]*v.n[VX] + a.v[0].n[VY]*v.n[VY] + a.v[0].n[VZ]*v.n[VZ]; + av.n[VY] = a.v[1].n[VX]*v.n[VX] + a.v[1].n[VY]*v.n[VY] + a.v[1].n[VZ]*v.n[VZ]; + av.n[VZ] = a.v[2].n[VX]*v.n[VX] + a.v[2].n[VY]*v.n[VY] + a.v[2].n[VZ]*v.n[VZ]; + + return av; +} + +vec3 operator*(const vec3 &v, const mat3 &a) +{ + return a.transpose() * v; +} + +float operator*(const vec2 &a, const vec2 &b) +{ + return a.n[VX]*b.n[VX] + a.n[VY]*b.n[VY]; +} + +vec2 operator/(const vec2 &a, float d) +{ + float d_inv = 1.0f/d; + return vec2(a.n[VX]*d_inv, a.n[VY]*d_inv); +} + +vec3 operator^(const vec2 &a, const vec2 &b) +{ + return vec3(0.0, 0.0, a.n[VX] * b.n[VY] - b.n[VX] * a.n[VY]); +} + +int operator==(const vec2 &a, const vec2 &b) +{ + return (a.n[VX] == b.n[VX]) && (a.n[VY] == b.n[VY]); +} + +int operator!=(const vec2 &a, const vec2 &b) +{ + return !(a == b); +} + +/*ostream& operator << (ostream& s, vec2& v) +{ return s << "| " << v.n[VX] << ' ' << v.n[VY] << " |"; } +*/ + +/*istream& operator >> (istream& s, vec2& v) { + vec2 v_tmp; + char c = ' '; + + while (isspace(c)) + s >> c; + // The vectors can be formatted either as x y or | x y | + if (c == '|') { + s >> v_tmp[VX] >> v_tmp[VY]; + while (s >> c && isspace(c)) ; + if (c != '|') + ;//s.set(_bad); + } + else { + s.putback(c); + s >> v_tmp[VX] >> v_tmp[VY]; + } + if (s) + v = v_tmp; + return s; +} +*/ + +void swap(vec2 &a, vec2 &b) +{ + vec2 tmp(a); + a = b; + b = tmp; +} + +vec2 min_vec(const vec2 &a, const vec2 &b) +{ + return vec2(MIN(a.n[VX], b.n[VX]), MIN(a.n[VY], b.n[VY])); +} + +vec2 max_vec(const vec2 &a, const vec2 &b) +{ + return vec2(MAX(a.n[VX], b.n[VX]), MAX(a.n[VY], b.n[VY])); +} + +vec2 prod(const vec2 &a, const vec2 &b) +{ + return vec2(a.n[VX] * b.n[VX], a.n[VY] * b.n[VY]); +} + +/**************************************************************** + * * + * vec3 Member functions * + * * + ****************************************************************/ + +// CONSTRUCTORS + +vec3::vec3() +{ + n[VX] = n[VY] = n[VZ] = 0.0; +} + +vec3::vec3(float x, float y, float z) +{ + n[VX] = x; + n[VY] = y; + n[VZ] = z; +} + +vec3::vec3(const vec3 &v) +{ + n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; +} + +vec3::vec3(const vec2 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = 1.0; +} + +vec3::vec3(const vec2 &v, float d) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = d; +} + +vec3::vec3(const vec4 &v) // it is up to caller to avoid divide-by-zero +{ + n[VX] = v.n[VX] / v.n[VW]; + n[VY] = v.n[VY] / v.n[VW]; + n[VZ] = v.n[VZ] / v.n[VW]; +} + +vec3::vec3(const vec4 &v, int dropAxis) +{ + switch (dropAxis) + { + case VX: n[VX] = v.n[VY]; n[VY] = v.n[VZ]; n[VZ] = v.n[VW]; break; + case VY: n[VX] = v.n[VX]; n[VY] = v.n[VZ]; n[VZ] = v.n[VW]; break; + case VZ: n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VW]; break; + default: n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; break; + } +} + + +// ASSIGNMENT OPERATORS + +vec3 &vec3::operator=(const vec3 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = v.n[VZ]; + return *this; +} + +vec3 &vec3::operator+=(const vec3 &v) +{ + n[VX] += v.n[VX]; + n[VY] += v.n[VY]; + n[VZ] += v.n[VZ]; + return *this; +} + +vec3 &vec3::operator-=(const vec3& v) +{ + n[VX] -= v.n[VX]; + n[VY] -= v.n[VY]; + n[VZ] -= v.n[VZ]; + return *this; +} + +vec3 &vec3::operator*=(float d) +{ + n[VX] *= d; + n[VY] *= d; + n[VZ] *= d; + return *this; +} + +vec3 &vec3::operator/=(float d) +{ + float d_inv = 1.0f/d; + n[VX] *= d_inv; + n[VY] *= d_inv; + n[VZ] *= d_inv; + return *this; +} + +float &vec3::operator[](int i) +{ + if (i < VX || i > VZ) + //VEC_ERROR("vec3 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("vec3 [] operator: illegal access" ); + + return n[i]; +} + +const float &vec3::operator[](int i) const +{ + if (i < VX || i > VZ) + //VEC_ERROR("vec3 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("vec3 [] operator: illegal access" ); + + return n[i]; +} + +// SPECIAL FUNCTIONS + +float vec3::length() const +{ + return (float) sqrt(length2()); +} + +float vec3::length2() const +{ + return n[VX]*n[VX] + n[VY]*n[VY] + n[VZ]*n[VZ]; +} + +vec3 &vec3::normalize() // it is up to caller to avoid divide-by-zero +{ + *this /= length(); + return *this; +} + +vec3 &vec3::homogenize(void) // it is up to caller to avoid divide-by-zero +{ + n[VX] /= n[VZ]; + n[VY] /= n[VZ]; + n[VZ] = 1.0; + return *this; +} + +vec3 &vec3::apply(V_FCT_PTR fct) +{ + n[VX] = (*fct)(n[VX]); + n[VY] = (*fct)(n[VY]); + n[VZ] = (*fct)(n[VZ]); + return *this; +} + +void vec3::set(float x, float y, float z) // set vector +{ + n[VX] = x; + n[VY] = y; + n[VZ] = z; +} + +void vec3::print(FILE *file, const char *name) const // print vector to a file +{ + fprintf( file, "%s: <%f, %f, %f>\n", name, n[VX], n[VY], n[VZ] ); +} + +// FRIENDS + +vec3 operator-(const vec3 &a) +{ + return vec3(-a.n[VX],-a.n[VY],-a.n[VZ]); +} + +vec3 operator+(const vec3 &a, const vec3 &b) +{ + return vec3(a.n[VX]+ b.n[VX], a.n[VY] + b.n[VY], a.n[VZ] + b.n[VZ]); +} + +vec3 operator-(const vec3 &a, const vec3 &b) +{ + return vec3(a.n[VX]-b.n[VX], a.n[VY]-b.n[VY], a.n[VZ]-b.n[VZ]); +} + +vec3 operator*(const vec3 &a, float d) +{ + return vec3(d*a.n[VX], d*a.n[VY], d*a.n[VZ]); +} + +vec3 operator*(float d, const vec3 &a) +{ + return a*d; +} + +vec3 operator*(const mat4 &a, const vec3 &v) +{ + return a*vec4(v); +} + +vec3 operator*(const vec3 &v, mat4 &a) +{ + return a.transpose()*v; +} + +float operator*(const vec3 &a, const vec3 &b) +{ + return a.n[VX]*b.n[VX] + a.n[VY]*b.n[VY] + a.n[VZ]*b.n[VZ]; +} + +vec3 operator/(const vec3 &a, float d) +{ + float d_inv = 1.0f/d; + return vec3(a.n[VX]*d_inv, a.n[VY]*d_inv, a.n[VZ]*d_inv); +} + +vec3 operator^(const vec3 &a, const vec3 &b) +{ + return + vec3(a.n[VY]*b.n[VZ] - a.n[VZ]*b.n[VY], + a.n[VZ]*b.n[VX] - a.n[VX]*b.n[VZ], + a.n[VX]*b.n[VY] - a.n[VY]*b.n[VX]); +} + +int operator==(const vec3 &a, const vec3 &b) +{ + return (a.n[VX] == b.n[VX]) && (a.n[VY] == b.n[VY]) && (a.n[VZ] == b.n[VZ]); +} + +int operator!=(const vec3 &a, const vec3 &b) +{ + return !(a == b); +} + +/*ostream& operator << (ostream& s, vec3& v) +{ return s << "| " << v.n[VX] << ' ' << v.n[VY] << ' ' << v.n[VZ] << " |"; } + +istream& operator >> (istream& s, vec3& v) { + vec3 v_tmp; + char c = ' '; + + while (isspace(c)) + s >> c; + // The vectors can be formatted either as x y z or | x y z | + if (c == '|') { + s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ]; + while (s >> c && isspace(c)) ; + if (c != '|') + ;//s.set(_bad); + } + else { + s.putback(c); + s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ]; + } + if (s) + v = v_tmp; + return s; +} +*/ + +void swap(vec3 &a, vec3 &b) +{ + vec3 tmp(a); + a = b; + b = tmp; +} + +vec3 min_vec(const vec3 &a, const vec3 &b) +{ + return vec3( + MIN(a.n[VX], b.n[VX]), + MIN(a.n[VY], b.n[VY]), + MIN(a.n[VZ], b.n[VZ])); +} + +vec3 max_vec(const vec3 &a, const vec3 &b) +{ + return vec3( + MAX(a.n[VX], b.n[VX]), + MAX(a.n[VY], b.n[VY]), + MAX(a.n[VZ], b.n[VZ])); +} + +vec3 prod(const vec3 &a, const vec3 &b) +{ + return vec3(a.n[VX]*b.n[VX], a.n[VY]*b.n[VY], a.n[VZ]*b.n[VZ]); +} + +/**************************************************************** + * * + * vec4 Member functions * + * * + ****************************************************************/ + +// CONSTRUCTORS + +vec4::vec4() +{ + n[VX] = n[VY] = n[VZ] = 0.0; + n[VW] = 1.0; +} + +vec4::vec4(float x, float y, float z, float w) +{ + n[VX] = x; + n[VY] = y; + n[VZ] = z; + n[VW] = w; +} + +vec4::vec4(const vec4 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = v.n[VZ]; + n[VW] = v.n[VW]; +} + +vec4::vec4(const vec3 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = v.n[VZ]; + n[VW] = 1.0; +} + +vec4::vec4(const vec3 &v, float d) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = v.n[VZ]; + n[VW] = d; +} + +// ASSIGNMENT OPERATORS + +vec4 &vec4::operator=(const vec4 &v) +{ + n[VX] = v.n[VX]; + n[VY] = v.n[VY]; + n[VZ] = v.n[VZ]; + n[VW] = v.n[VW]; + return *this; +} + +vec4 &vec4::operator+=(const vec4 &v) +{ + n[VX] += v.n[VX]; + n[VY] += v.n[VY]; + n[VZ] += v.n[VZ]; + n[VW] += v.n[VW]; + return *this; +} + +vec4 &vec4::operator-=(const vec4 &v) +{ + n[VX] -= v.n[VX]; + n[VY] -= v.n[VY]; + n[VZ] -= v.n[VZ]; + n[VW] -= v.n[VW]; + return *this; +} + +vec4 &vec4::operator*=(float d) +{ + n[VX] *= d; + n[VY] *= d; + n[VZ] *= d; + n[VW] *= d; + return *this; +} + +vec4 &vec4::operator/=(float d) +{ + float d_inv = 1.0f/d; + n[VX] *= d_inv; + n[VY] *= d_inv; + n[VZ] *= d_inv; + n[VW] *= d_inv; + return *this; +} + +float &vec4::operator[](int i) +{ + if (i < VX || i > VW) + //VEC_ERROR("vec4 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("vec4 [] operator: illegal access" ); + + return n[i]; +} + +const float &vec4::operator[](int i) const +{ + if (i < VX || i > VW) + //VEC_ERROR("vec4 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("vec4 [] operator: illegal access" ); + + return n[i]; +} + +// SPECIAL FUNCTIONS + +float vec4::length() const +{ + return (float) sqrt(length2()); +} + +float vec4::length2() const +{ + return n[VX]*n[VX] + n[VY]*n[VY] + n[VZ]*n[VZ] + n[VW]*n[VW]; +} + +vec4 &vec4::normalize() // it is up to caller to avoid divide-by-zero +{ + *this /= length(); + return *this; +} + +vec4 &vec4::homogenize() // it is up to caller to avoid divide-by-zero +{ + n[VX] /= n[VW]; + n[VY] /= n[VW]; + n[VZ] /= n[VW]; + n[VW] = 1.0; + return *this; +} + +vec4 &vec4::apply(V_FCT_PTR fct) +{ + n[VX] = (*fct)(n[VX]); + n[VY] = (*fct)(n[VY]); + n[VZ] = (*fct)(n[VZ]); + n[VW] = (*fct)(n[VW]); + return *this; +} + +void vec4::print(FILE *file, const char *name) const // print vector to a file +{ + fprintf( file, "%s: <%f, %f, %f, %f>\n", name, n[VX], n[VY], n[VZ], n[VW]); +} + +void vec4::set(float x, float y, float z, float a) +{ + n[0] = x; + n[1] = y; + n[2] = z; + n[3] = a; +} + + +// FRIENDS + +vec4 operator-(const vec4 &a) +{ + return vec4(-a.n[VX],-a.n[VY],-a.n[VZ],-a.n[VW]); +} + +vec4 operator+(const vec4 &a, const vec4 &b) +{ + return vec4( + a.n[VX] + b.n[VX], + a.n[VY] + b.n[VY], + a.n[VZ] + b.n[VZ], + a.n[VW] + b.n[VW]); +} + +vec4 operator-(const vec4 &a, const vec4 &b) +{ + return vec4( + a.n[VX] - b.n[VX], + a.n[VY] - b.n[VY], + a.n[VZ] - b.n[VZ], + a.n[VW] - b.n[VW]); +} + +vec4 operator*(const vec4 &a, float d) +{ + return vec4(d*a.n[VX], d*a.n[VY], d*a.n[VZ], d*a.n[VW]); +} + +vec4 operator*(float d, const vec4 &a) +{ + return a*d; +} + +vec4 operator*(const mat4 &a, const vec4 &v) +{ + #define ROWCOL(i) \ + a.v[i].n[0]*v.n[VX] + \ + a.v[i].n[1]*v.n[VY] + \ + a.v[i].n[2]*v.n[VZ] + \ + a.v[i].n[3]*v.n[VW] + + return vec4(ROWCOL(0), ROWCOL(1), ROWCOL(2), ROWCOL(3)); + + #undef ROWCOL +} + +vec4 operator*(const vec4 &v, const mat4 &a) +{ + return a.transpose()*v; +} + +float operator*(const vec4 &a, const vec4 &b) +{ + return + a.n[VX]*b.n[VX] + + a.n[VY]*b.n[VY] + + a.n[VZ]*b.n[VZ] + + a.n[VW]*b.n[VW]; +} + +vec4 operator/(const vec4 &a, float d) +{ + float d_inv = 1.0f/d; + return vec4( + a.n[VX]*d_inv, + a.n[VY]*d_inv, + a.n[VZ]*d_inv, + a.n[VW]*d_inv); +} + +int operator==(const vec4 &a, const vec4 &b) +{ + return + (a.n[VX] == b.n[VX]) && + (a.n[VY] == b.n[VY]) && + (a.n[VZ] == b.n[VZ]) && + (a.n[VW] == b.n[VW]); +} + +int operator!=(const vec4 &a, const vec4 &b) +{ + return !(a == b); +} + +/*ostream& operator << (ostream& s, vec4& v) +{ return s << "| " << v.n[VX] << ' ' << v.n[VY] << ' ' << v.n[VZ] << ' ' + << v.n[VW] << " |"; } + +istream& operator >> (istream& s, vec4& v) { + vec4 v_tmp; + char c = ' '; + + while (isspace(c)) + s >> c; + // The vectors can be formatted either as x y z w or | x y z w | + if (c == '|') { + s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ] >> v_tmp[VW]; + while (s >> c && isspace(c)) ; + if (c != '|') + ;//s.set(_bad); + } + else { + s.putback(c); + s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ] >> v_tmp[VW]; + } + if (s) + v = v_tmp; + return s; +} +*/ + +void swap(vec4 &a, vec4 &b) +{ + vec4 tmp(a); + a = b; + b = tmp; +} + +vec4 min_vec(const vec4 &a, const vec4 &b) +{ + return vec4( + MIN(a.n[VX], b.n[VX]), + MIN(a.n[VY], b.n[VY]), + MIN(a.n[VZ], b.n[VZ]), + MIN(a.n[VW], b.n[VW])); +} + +vec4 max_vec(const vec4 &a, const vec4 &b) +{ + return vec4( + MAX(a.n[VX], b.n[VX]), + MAX(a.n[VY], b.n[VY]), + MAX(a.n[VZ], b.n[VZ]), + MAX(a.n[VW], b.n[VW])); +} + +vec4 prod(const vec4 &a, const vec4 &b) +{ + return vec4( + a.n[VX] * b.n[VX], + a.n[VY] * b.n[VY], + a.n[VZ] * b.n[VZ], + a.n[VW] * b.n[VW]); +} + +/**************************************************************** + * * + * mat3 member functions * + * * + ****************************************************************/ + +// CONSTRUCTORS + +mat3::mat3() +{ + *this = identity2D(); +} + +mat3::mat3(const vec3 &v0, const vec3 &v1, const vec3 &v2) +{ + set(v0, v1, v2); +} + +mat3::mat3(const mat3 &m) +{ + v[0] = m.v[0]; + v[1] = m.v[1]; + v[2] = m.v[2]; +} + +// ASSIGNMENT OPERATORS + +mat3 &mat3::operator=(const mat3 &m) +{ + v[0] = m.v[0]; + v[1] = m.v[1]; + v[2] = m.v[2]; + return *this; +} + +mat3 &mat3::operator+=(const mat3& m) +{ + v[0] += m.v[0]; + v[1] += m.v[1]; + v[2] += m.v[2]; + return *this; +} + +mat3 &mat3::operator-=(const mat3& m) +{ + v[0] -= m.v[0]; + v[1] -= m.v[1]; + v[2] -= m.v[2]; + return *this; +} + +mat3 &mat3::operator*=(float d) +{ + v[0] *= d; + v[1] *= d; + v[2] *= d; + return *this; +} + +mat3 &mat3::operator/=(float d) +{ + v[0] /= d; + v[1] /= d; + v[2] /= d; + return *this; +} + +vec3 &mat3::operator[](int i) +{ + if (i < VX || i > VZ) + //VEC_ERROR("mat3 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("mat3 [] operator: illegal access" ); + + return v[i]; +} + +const vec3 &mat3::operator[](int i) const +{ + if (i < VX || i > VZ) + //VEC_ERROR("mat3 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("mat3 [] operator: illegal access" ); + + return v[i]; +} + +void mat3::set(const vec3 &v0, const vec3 &v1, const vec3 &v2) +{ + v[0] = v0; + v[1] = v1; + v[2] = v2; +} + +// SPECIAL FUNCTIONS + +mat3 mat3::transpose() const +{ + return mat3( + vec3(v[0][0], v[1][0], v[2][0]), + vec3(v[0][1], v[1][1], v[2][1]), + vec3(v[0][2], v[1][2], v[2][2])); +} + +mat3 mat3::inverse() const // Gauss-Jordan elimination with partial pivoting +{ + mat3 a(*this); // As a evolves from original mat into identity + mat3 b(identity2D()); // b evolves from identity into inverse(a) + int i, j, i1; + + // Loop over cols of a from left to right, eliminating above and below diag + for (j=0; j<3; j++) // Find largest pivot in column j among rows j..2 + { + i1 = j; // Row with largest pivot candidate + for (i=j+1; i<3; i++) + if (fabs(a.v[i].n[j]) > fabs(a.v[i1].n[j])) + i1 = i; + + // Swap rows i1 and j in a and b to put pivot on diagonal + swap(a.v[i1], a.v[j]); + swap(b.v[i1], b.v[j]); + + // Scale row j to have a unit diagonal + if (a.v[j].n[j]==0.) + VEC_ERROR("mat3::inverse: singular matrix; can't invert\n"); + + b.v[j] /= a.v[j].n[j]; + a.v[j] /= a.v[j].n[j]; + + // Eliminate off-diagonal elems in col j of a, doing identical ops to b + for (i=0; i<3; i++) + if (i!=j) + { + b.v[i] -= a.v[i].n[j]*b.v[j]; + a.v[i] -= a.v[i].n[j]*a.v[j]; + } + } + + return b; +} + +mat3 &mat3::apply(V_FCT_PTR fct) +{ + v[VX].apply(fct); + v[VY].apply(fct); + v[VZ].apply(fct); + return *this; +} + + +// FRIENDS + +mat3 operator-(const mat3 &a) +{ + return mat3(-a.v[0], -a.v[1], -a.v[2]); +} + +mat3 operator+(const mat3 &a, const mat3 &b) +{ + return mat3(a.v[0]+b.v[0], a.v[1]+b.v[1], a.v[2]+b.v[2]); +} + +mat3 operator-(const mat3 &a, const mat3 &b) +{ + return mat3(a.v[0]-b.v[0], a.v[1]-b.v[1], a.v[2]-b.v[2]); +} + +mat3 operator*(const mat3 &a, const mat3 &b) +{ + #define ROWCOL(i, j) \ + a.v[i].n[0]*b.v[0][j] + a.v[i].n[1]*b.v[1][j] + a.v[i].n[2]*b.v[2][j] + + return mat3( + vec3(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2)), + vec3(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2)), + vec3(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2))); + + #undef ROWCOL +} + +mat3 operator*(const mat3 &a, float d) +{ + return mat3(a.v[0]*d, a.v[1]*d, a.v[2]*d); +} + +mat3 operator*(float d, const mat3 &a) +{ + return a*d; +} + +mat3 operator/(const mat3 &a, float d) +{ + return mat3(a.v[0]/d, a.v[1]/d, a.v[2]/d); +} + +int operator==(const mat3 &a, const mat3 &b) +{ + return + (a.v[0] == b.v[0]) && + (a.v[1] == b.v[1]) && + (a.v[2] == b.v[2]); +} + +int operator!=(const mat3 &a, const mat3 &b) +{ + return !(a == b); +} + +/*ostream& operator << (ostream& s, mat3& m) +{ return s << m.v[VX] << '\n' << m.v[VY] << '\n' << m.v[VZ]; } + +istream& operator >> (istream& s, mat3& m) { + mat3 m_tmp; + + s >> m_tmp[VX] >> m_tmp[VY] >> m_tmp[VZ]; + if (s) + m = m_tmp; + return s; +} +*/ + +void swap(mat3 &a, mat3 &b) +{ + mat3 tmp(a); + a = b; + b = tmp; +} + +void mat3::print(FILE *file, const char *name) const +{ + int i, j; + + fprintf( stderr, "%s:\n", name ); + + for( i = 0; i < 3; i++ ) + { + fprintf( stderr, " " ); + for( j = 0; j < 3; j++ ) + { + fprintf( stderr, "%f ", v[i][j] ); + } + fprintf( stderr, "\n" ); + } +} + + + +/**************************************************************** + * * + * mat4 member functions * + * * + ****************************************************************/ + +// CONSTRUCTORS + +mat4::mat4() +{ + *this = identity3D(); +} + +mat4::mat4(const vec4& v0, const vec4& v1, const vec4& v2, const vec4& v3) +{ + v[0] = v0; + v[1] = v1; + v[2] = v2; + v[3] = v3; +} + +mat4::mat4(const mat4 &m) +{ + v[0] = m.v[0]; + v[1] = m.v[1]; + v[2] = m.v[2]; + v[3] = m.v[3]; +} + +mat4::mat4( + float a00, float a01, float a02, float a03, + float a10, float a11, float a12, float a13, + float a20, float a21, float a22, float a23, + float a30, float a31, float a32, float a33 ) +{ + v[0][0] = a00; v[0][1] = a01; v[0][2] = a02; v[0][3] = a03; + v[1][0] = a10; v[1][1] = a11; v[1][2] = a12; v[1][3] = a13; + v[2][0] = a20; v[2][1] = a21; v[2][2] = a22; v[2][3] = a23; + v[3][0] = a30; v[3][1] = a31; v[3][2] = a32; v[3][3] = a33; +} + +// ASSIGNMENT OPERATORS + +mat4 &mat4::operator=(const mat4 &m) +{ + v[0] = m.v[0]; + v[1] = m.v[1]; + v[2] = m.v[2]; + v[3] = m.v[3]; + return *this; +} + +mat4 &mat4::operator+=(const mat4 &m) +{ + v[0] += m.v[0]; + v[1] += m.v[1]; + v[2] += m.v[2]; + v[3] += m.v[3]; + return *this; +} + +mat4 &mat4::operator-=(const mat4 &m) +{ + v[0] -= m.v[0]; + v[1] -= m.v[1]; + v[2] -= m.v[2]; + v[3] -= m.v[3]; + return *this; +} + +mat4 &mat4::operator*=(float d) +{ + v[0] *= d; + v[1] *= d; + v[2] *= d; + v[3] *= d; + return *this; +} + +mat4 &mat4::operator/=(float d) +{ + v[0] /= d; + v[1] /= d; + v[2] /= d; + v[3] /= d; + return *this; +} + +vec4 &mat4::operator[](int i) +{ + if (i < VX || i > VW) + //VEC_ERROR("mat4 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("mat4 [] operator: illegal access" ); + return v[i]; +} + +const vec4 &mat4::operator[](int i) const +{ + if (i < VX || i > VW) + //VEC_ERROR("mat4 [] operator: illegal access; index = " << i << '\n') + VEC_ERROR("mat4 [] operator: illegal access" ); + return v[i]; +} + +// SPECIAL FUNCTIONS; + +mat4 mat4::transpose() const +{ + return mat4( + vec4(v[0][0], v[1][0], v[2][0], v[3][0]), + vec4(v[0][1], v[1][1], v[2][1], v[3][1]), + vec4(v[0][2], v[1][2], v[2][2], v[3][2]), + vec4(v[0][3], v[1][3], v[2][3], v[3][3])); +} + +mat4 mat4::inverse() const // Gauss-Jordan elimination with partial pivoting +{ + mat4 a(*this); // As a evolves from original mat into identity + mat4 b(identity3D()); // b evolves from identity into inverse(a) + int i, j, i1; + + // Loop over cols of a from left to right, eliminating above and below diag + for (j=0; j<4; j++) // Find largest pivot in column j among rows j..3 + { + i1 = j; // Row with largest pivot candidate + for (i=j+1; i<4; i++) + if (fabs(a.v[i].n[j]) > fabs(a.v[i1].n[j])) + i1 = i; + + // Swap rows i1 and j in a and b to put pivot on diagonal + swap(a.v[i1], a.v[j]); + swap(b.v[i1], b.v[j]); + + // Scale row j to have a unit diagonal + if (a.v[j].n[j]==0.) + VEC_ERROR("mat4::inverse: singular matrix; can't invert\n"); + + b.v[j] /= a.v[j].n[j]; + a.v[j] /= a.v[j].n[j]; + + // Eliminate off-diagonal elems in col j of a, doing identical ops to b + for (i=0; i<4; i++) + if (i!=j) + { + b.v[i] -= a.v[i].n[j]*b.v[j]; + a.v[i] -= a.v[i].n[j]*a.v[j]; + } + } + + return b; +} + +mat4 &mat4::apply(V_FCT_PTR fct) +{ + v[VX].apply(fct); + v[VY].apply(fct); + v[VZ].apply(fct); + v[VW].apply(fct); + return *this; +} + +void mat4::print(FILE *file, const char *name) const +{ + int i, j; + + fprintf( stderr, "%s:\n", name ); + + for( i = 0; i < 4; i++ ) + { + fprintf( stderr, " " ); + for( j = 0; j < 4; j++ ) + { + fprintf( stderr, "%f ", v[i][j] ); + } + fprintf( stderr, "\n" ); + } +} + +void mat4::swap_rows(int i, int j) +{ + vec4 t; + + t = v[i]; + v[i] = v[j]; + v[j] = t; +} + +void mat4::swap_cols(int i, int j) +{ + float t; + int k; + + for (k=0; k<4; k++) + { + t = v[k][i]; + v[k][i] = v[k][j]; + v[k][j] = t; + } +} + + +// FRIENDS + +mat4 operator-(const mat4 &a) +{ + return mat4(-a.v[0],-a.v[1],-a.v[2],-a.v[3]); +} + +mat4 operator+(const mat4 &a, const mat4 &b) +{ + return mat4( + a.v[0] + b.v[0], + a.v[1] + b.v[1], + a.v[2] + b.v[2], + a.v[3] + b.v[3]); +} + +mat4 operator-(const mat4 &a, const mat4 &b) +{ + return mat4( + a.v[0] - b.v[0], + a.v[1] - b.v[1], + a.v[2] - b.v[2], + a.v[3] - b.v[3]); +} + +mat4 operator*(const mat4 &a, const mat4 &b) +{ + #define ROWCOL(i, j) \ + a.v[i].n[0]*b.v[0][j] + \ + a.v[i].n[1]*b.v[1][j] + \ + a.v[i].n[2]*b.v[2][j] + \ + a.v[i].n[3]*b.v[3][j] + + return mat4( + vec4(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2), ROWCOL(0,3)), + vec4(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2), ROWCOL(1,3)), + vec4(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2), ROWCOL(2,3)), + vec4(ROWCOL(3,0), ROWCOL(3,1), ROWCOL(3,2), ROWCOL(3,3)) + ); + + #undef ROWCOL +} + +mat4 operator*(const mat4 &a, float d) +{ + return mat4(a.v[0]*d, a.v[1]*d, a.v[2]*d, a.v[3]*d); +} + +mat4 operator*(float d, const mat4 &a) +{ + return a*d; +} + +mat4 operator/(const mat4 &a, float d) +{ + return mat4(a.v[0]/d, a.v[1]/d, a.v[2]/d, a.v[3]/d); +} + +int operator==(const mat4 &a, const mat4 &b) +{ + return + (a.v[0] == b.v[0]) && + (a.v[1] == b.v[1]) && + (a.v[2] == b.v[2]) && + (a.v[3] == b.v[3]); +} + +int operator!=(const mat4 &a, const mat4 &b) +{ + return !(a == b); +} + +/*ostream& operator << (ostream& s, mat4& m) +{ return s << m.v[VX] << '\n' << m.v[VY] << '\n' << m.v[VZ] << '\n' << m.v[VW]; } + +istream& operator >> (istream& s, mat4& m) +{ + mat4 m_tmp; + + s >> m_tmp[VX] >> m_tmp[VY] >> m_tmp[VZ] >> m_tmp[VW]; + if (s) + m = m_tmp; + return s; +} +*/ + +void swap(mat4 &a, mat4 &b) +{ + mat4 tmp(a); + a = b; + b = tmp; +} + +/**************************************************************** + * * + * 2D functions and 3D functions * + * * + ****************************************************************/ + +mat3 identity2D() +{ + return mat3( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0)); +} + +mat3 translation2D(const vec2 &v) +{ + return mat3( + vec3(1.0, 0.0, v[VX]), + vec3(0.0, 1.0, v[VY]), + vec3(0.0, 0.0, 1.0)); +} + +mat3 rotation2D(const vec2 &Center, float angleDeg) +{ + float angleRad = (float) (angleDeg * M_PI / 180.0); + float c = (float) cos(angleRad); + float s = (float) sin(angleRad); + + return mat3( + vec3(c, -s, Center[VX] * (1.0f-c) + Center[VY] * s), + vec3(s, c, Center[VY] * (1.0f-c) - Center[VX] * s), + vec3(0.0, 0.0, 1.0)); +} + +mat3 scaling2D(const vec2 &scaleVector) +{ + return mat3( + vec3(scaleVector[VX], 0.0, 0.0), + vec3(0.0, scaleVector[VY], 0.0), + vec3(0.0, 0.0, 1.0)); +} + +mat4 identity3D() +{ + return mat4( + vec4(1.0, 0.0, 0.0, 0.0), + vec4(0.0, 1.0, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(0.0, 0.0, 0.0, 1.0)); +} + +mat4 translation3D(const vec3 &v) +{ + return mat4( + vec4(1.0, 0.0, 0.0, v[VX]), + vec4(0.0, 1.0, 0.0, v[VY]), + vec4(0.0, 0.0, 1.0, v[VZ]), + vec4(0.0, 0.0, 0.0, 1.0)); +} + +mat4 rotation3D(const vec3 &Axis, float angleDeg) +{ + float angleRad = (float) (angleDeg * M_PI / 180.0); + float c = (float) cos(angleRad); + float s = (float) sin(angleRad); + float t = 1.0f - c; + + vec3 axis(Axis); + axis.normalize(); + + return mat4( + vec4(t * axis[VX] * axis[VX] + c, + t * axis[VX] * axis[VY] - s * axis[VZ], + t * axis[VX] * axis[VZ] + s * axis[VY], + 0.0), + vec4(t * axis[VX] * axis[VY] + s * axis[VZ], + t * axis[VY] * axis[VY] + c, + t * axis[VY] * axis[VZ] - s * axis[VX], + 0.0), + vec4(t * axis[VX] * axis[VZ] - s * axis[VY], + t * axis[VY] * axis[VZ] + s * axis[VX], + t * axis[VZ] * axis[VZ] + c, + 0.0), + vec4(0.0, 0.0, 0.0, 1.0)); +} + +mat4 rotation3Drad(const vec3 &Axis, float angleRad) +{ + float c = (float) cos(angleRad); + float s = (float) sin(angleRad); + float t = 1.0f - c; + + vec3 axis(Axis); + axis.normalize(); + + return mat4( + vec4(t * axis[VX] * axis[VX] + c, + t * axis[VX] * axis[VY] - s * axis[VZ], + t * axis[VX] * axis[VZ] + s * axis[VY], + 0.0), + vec4(t * axis[VX] * axis[VY] + s * axis[VZ], + t * axis[VY] * axis[VY] + c, + t * axis[VY] * axis[VZ] - s * axis[VX], + 0.0), + vec4(t * axis[VX] * axis[VZ] - s * axis[VY], + t * axis[VY] * axis[VZ] + s * axis[VX], + t * axis[VZ] * axis[VZ] + c, + 0.0), + vec4(0.0, 0.0, 0.0, 1.0)); +} + +mat4 scaling3D(const vec3 &scaleVector) +{ + return mat4( + vec4(scaleVector[VX], 0.0, 0.0, 0.0), + vec4(0.0, scaleVector[VY], 0.0, 0.0), + vec4(0.0, 0.0, scaleVector[VZ], 0.0), + vec4(0.0, 0.0, 0.0, 1.0)); +} + +mat4 perspective3D(float d) +{ + return mat4( + vec4(1.0f, 0.0f, 0.0f, 0.0f), + vec4(0.0f, 1.0f, 0.0f, 0.0f), + vec4(0.0f, 0.0f, 1.0f, 0.0f), + vec4(0.0f, 0.0f, 1.0f/d, 0.0f)); +} diff --git a/Extras/glui/algebra3.h b/Extras/glui/algebra3.h new file mode 100644 index 000000000..7849673df --- /dev/null +++ b/Extras/glui/algebra3.h @@ -0,0 +1,475 @@ +/* + + algebra3.cpp, algebra3.h - C++ Vector and Matrix Algebra routines + + GLUI User Interface Toolkit (LGPL) + 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 + +*/ + +/************************************************************************** + + There are three vector classes and two matrix classes: vec2, vec3, + vec4, mat3, and mat4. + + All the standard arithmetic operations are defined, with '*' + for dot product of two vectors and multiplication of two matrices, + and '^' for cross product of two vectors. + + Additional functions include length(), normalize(), homogenize for + vectors, and print(), set(), apply() for all classes. + + There is a function transpose() for matrices, but note that it + does not actually change the matrix, + + When multiplied with a matrix, a vector is treated as a row vector + if it precedes the matrix (v*M), and as a column vector if it + follows the matrix (M*v). + + Matrices are stored in row-major form. + + A vector of one dimension (2d, 3d, or 4d) can be cast to a vector + of a higher or lower dimension. If casting to a higher dimension, + the new component is set by default to 1.0, unless a value is + specified: + vec3 a(1.0, 2.0, 3.0 ); + vec4 b( a, 4.0 ); // now b == {1.0, 2.0, 3.0, 4.0}; + When casting to a lower dimension, the vector is homogenized in + the lower dimension. E.g., if a 4d {X,Y,Z,W} is cast to 3d, the + resulting vector is {X/W, Y/W, Z/W}. It is up to the user to + insure the fourth component is not zero before casting. + + There are also the following function for building matrices: + identity2D(), translation2D(), rotation2D(), + scaling2D(), identity3D(), translation3D(), + rotation3D(), rotation3Drad(), scaling3D(), + perspective3D() + + NOTE: When compiling for Windows, include this file first, to avoid + certain name conflicts + + --------------------------------------------------------------------- + + Author: Jean-Francois DOUEg + Revised: Paul Rademacher + Version 3.2 - Feb 1998 + Revised: Nigel Stewart (GLUI Code Cleaning) + +**************************************************************************/ + +#ifndef GLUI_ALGEBRA3_H +#define GLUI_ALGEBRA3_H + +#include +#include +#include + +// this line defines a new type: pointer to a function which returns a +// float and takes as argument a float +typedef float (*V_FCT_PTR)(float); + +class vec2; +class vec3; +class vec4; +class mat3; +class mat4; + +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +enum {VX, VY, VZ, VW}; // axes +enum {PA, PB, PC, PD}; // planes +enum {RED, GREEN, BLUE, ALPHA}; // colors +enum {KA, KD, KS, ES}; // phong coefficients + +/**************************************************************** + * * + * 2D Vector * + * * + ****************************************************************/ + +class vec2 +{ + friend class vec3; + +protected: + + float n[2]; + +public: + + // Constructors + + vec2(); + vec2(float x, float y); + vec2(const vec2 &v); // copy constructor + vec2(const vec3 &v); // cast v3 to v2 + vec2(const vec3 &v, int dropAxis); // cast v3 to v2 + + // Assignment operators + + vec2 &operator = (const vec2 &v); // assignment of a vec2 + vec2 &operator += (const vec2 &v); // incrementation by a vec2 + vec2 &operator -= (const vec2 &v); // decrementation by a vec2 + vec2 &operator *= (float d); // multiplication by a constant + vec2 &operator /= (float d); // division by a constant + + // special functions + + float length() const; // length of a vec2 + float length2() const; // squared length of a vec2 + vec2 &normalize(); // normalize a vec2 + vec2 &apply(V_FCT_PTR fct); // apply a func. to each component + void set(float x, float y); // set vector + + float &operator [] (int i); // indexing + const float &operator [] (int i) const; // indexing + + // friends + + friend vec2 operator - (const vec2 &v); // -v1 + friend vec2 operator + (const vec2 &a, const vec2 &b); // v1 + v2 + friend vec2 operator - (const vec2 &a, const vec2 &b); // v1 - v2 + friend vec2 operator * (const vec2 &a, float d); // v1 * 3.0 + friend vec2 operator * (float d, const vec2 &a); // 3.0 * v1 + friend vec2 operator * (const mat3 &a, const vec2 &v); // M . v + friend vec2 operator * (const vec2 &v, const mat3 &a); // v . M + friend float operator * (const vec2 &a, const vec2 &b); // dot product + friend vec2 operator / (const vec2 &a, float d); // v1 / 3.0 + friend vec3 operator ^ (const vec2 &a, const vec2 &b); // cross product + friend int operator == (const vec2 &a, const vec2 &b); // v1 == v2 ? + friend int operator != (const vec2 &a, const vec2 &b); // v1 != v2 ? + //friend ostream& operator << (ostream& s, vec2& v); // output to stream + //friend istream& operator >> (istream& s, vec2& v); // input from strm. + friend void swap(vec2 &a, vec2 &b); // swap v1 & v2 + friend vec2 min_vec(const vec2 &a, const vec2 &b); // min(v1, v2) + friend vec2 max_vec(const vec2 &a, const vec2 &b); // max(v1, v2) + friend vec2 prod (const vec2 &a, const vec2 &b); // term by term * +}; + +/**************************************************************** + * * + * 3D Vector * + * * + ****************************************************************/ + +class vec3 +{ + friend class vec2; + friend class vec4; + friend class mat3; + +protected: + + float n[3]; + +public: + + // Constructors + + vec3(); + vec3(float x, float y, float z); + vec3(const vec3 &v); // copy constructor + vec3(const vec2 &v); // cast v2 to v3 + vec3(const vec2 &v, float d); // cast v2 to v3 + vec3(const vec4 &v); // cast v4 to v3 + vec3(const vec4 &v, int dropAxis); // cast v4 to v3 + + // Assignment operators + + vec3 &operator = (const vec3 &v); // assignment of a vec3 + vec3 &operator += (const vec3 &v); // incrementation by a vec3 + vec3 &operator -= (const vec3 &v); // decrementation by a vec3 + vec3 &operator *= (float d); // multiplication by a constant + vec3 &operator /= (float d); // division by a constant + + // special functions + + float length() const; // length of a vec3 + float length2() const; // squared length of a vec3 + vec3& normalize(); // normalize a vec3 + vec3& homogenize(); // homogenize (div by Z) + vec3& apply(V_FCT_PTR fct); // apply a func. to each component + void set(float x, float y, float z); // set vector + + void print(FILE *file, const char *name) const; // print vector to a file + + + float &operator [] (int i); // indexing + const float &operator [] (int i) const; // indexing + + // friends + + friend vec3 operator - (const vec3 &v); // -v1 + friend vec3 operator + (const vec3 &a, const vec3 &b); // v1 + v2 + friend vec3 operator - (const vec3 &a, const vec3 &b); // v1 - v2 + friend vec3 operator * (const vec3 &a, float d); // v1 * 3.0 + friend vec3 operator * (float d, const vec3 &a); // 3.0 * v1 + friend vec3 operator * (const mat4 &a, const vec3 &v); // M . v + friend vec3 operator * (const vec3 &v, const mat4 &a); // v . M + friend float operator * (const vec3 &a, const vec3 &b); // dot product + friend vec3 operator / (const vec3 &a, float d); // v1 / 3.0 + friend vec3 operator ^ (const vec3 &a, const vec3 &b); // cross product + friend int operator == (const vec3 &a, const vec3 &b); // v1 == v2 ? + friend int operator != (const vec3 &a, const vec3 &b); // v1 != v2 ? + //friend ostream& operator << (ostream& s, vec3& v); // output to stream + //friend istream& operator >> (istream& s, vec3& v); // input from strm. + friend void swap(vec3 &a, vec3 &b); // swap v1 & v2 + friend vec3 min_vec(const vec3 &a, const vec3 &b); // min(v1, v2) + friend vec3 max_vec(const vec3 &a, const vec3 &b); // max(v1, v2) + friend vec3 prod(const vec3 &a, const vec3 &b); // term by term * + + // necessary friend declarations + + friend vec2 operator * (const mat3 &a, const vec2 &v); // linear transform + friend vec3 operator * (const mat3 &a, const vec3 &v); // linear transform + friend mat3 operator * (const mat3 &a, const mat3 &b); // matrix 3 product +}; + +/**************************************************************** + * * + * 4D Vector * + * * + ****************************************************************/ + +class vec4 +{ + friend class vec3; + friend class mat4; + +protected: + + float n[4]; + +public: + + // Constructors + + vec4(); + vec4(float x, float y, float z, float w); + vec4(const vec4 &v); // copy constructor + vec4(const vec3 &v); // cast vec3 to vec4 + vec4(const vec3 &v, float d); // cast vec3 to vec4 + + // Assignment operators + + vec4 &operator = (const vec4 &v); // assignment of a vec4 + vec4 &operator += (const vec4 &v); // incrementation by a vec4 + vec4 &operator -= (const vec4 &v); // decrementation by a vec4 + vec4 &operator *= (float d); // multiplication by a constant + vec4 &operator /= (float d); // division by a constant + + // special functions + + float length() const; // length of a vec4 + float length2() const; // squared length of a vec4 + vec4 &normalize(); // normalize a vec4 + vec4 &apply(V_FCT_PTR fct); // apply a func. to each component + vec4 &homogenize(); + + void print(FILE *file, const char *name) const; // print vector to a file + + void set(float x, float y, float z, float a); + + float &operator [] (int i); // indexing + const float &operator [] (int i) const; // indexing + + // friends + + friend vec4 operator - (const vec4 &v); // -v1 + friend vec4 operator + (const vec4 &a, const vec4 &b); // v1 + v2 + friend vec4 operator - (const vec4 &a, const vec4 &b); // v1 - v2 + friend vec4 operator * (const vec4 &a, float d); // v1 * 3.0 + friend vec4 operator * (float d, const vec4 &a); // 3.0 * v1 + friend vec4 operator * (const mat4 &a, const vec4 &v); // M . v + friend vec4 operator * (const vec4 &v, const mat4 &a); // v . M + friend float operator * (const vec4 &a, const vec4 &b); // dot product + friend vec4 operator / (const vec4 &a, float d); // v1 / 3.0 + friend int operator == (const vec4 &a, const vec4 &b); // v1 == v2 ? + friend int operator != (const vec4 &a, const vec4 &b); // v1 != v2 ? + //friend ostream& operator << (ostream& s, vec4& v); // output to stream + //friend istream& operator >> (istream& s, vec4& v); // input from strm. + friend void swap(vec4 &a, vec4 &b); // swap v1 & v2 + friend vec4 min_vec(const vec4 &a, const vec4 &b); // min(v1, v2) + friend vec4 max_vec(const vec4 &a, const vec4 &b); // max(v1, v2) + friend vec4 prod (const vec4 &a, const vec4 &b); // term by term * + + // necessary friend declarations + + friend vec3 operator * (const mat4 &a, const vec3 &v); // linear transform + friend mat4 operator * (const mat4 &a, const mat4 &b); // matrix 4 product +}; + +/**************************************************************** + * * + * 3x3 Matrix * + * * + ****************************************************************/ + +class mat3 +{ +protected: + + vec3 v[3]; + +public: + + // Constructors + + mat3(); + mat3(const vec3 &v0, const vec3 &v1, const vec3 &v2); + mat3(const mat3 &m); + + // Assignment operators + + mat3 &operator = (const mat3 &m); // assignment of a mat3 + mat3 &operator += (const mat3 &m); // incrementation by a mat3 + mat3 &operator -= (const mat3 &m); // decrementation by a mat3 + mat3 &operator *= (float d); // multiplication by a constant + mat3 &operator /= (float d); // division by a constant + + // special functions + + mat3 transpose() const; // transpose + mat3 inverse() const; // inverse + mat3 &apply(V_FCT_PTR fct); // apply a func. to each element + + void print(FILE *file, const char *name ) const; // print matrix to a file + + void set(const vec3 &v0, const vec3 &v1, const vec3 &v2); + + vec3 &operator [] (int i); // indexing + const vec3 &operator [] (int i) const; // indexing + + // friends + + friend mat3 operator - (const mat3 &a); // -m1 + friend mat3 operator + (const mat3 &a, const mat3 &b); // m1 + m2 + friend mat3 operator - (const mat3 &a, const mat3 &b); // m1 - m2 + friend mat3 operator * (const mat3 &a, const mat3 &b); // m1 * m2 + friend mat3 operator * (const mat3 &a, float d); // m1 * 3.0 + friend mat3 operator * (float d, const mat3 &a); // 3.0 * m1 + friend mat3 operator / (const mat3 &a, float d); // m1 / 3.0 + friend int operator == (const mat3 &a, const mat3 &b); // m1 == m2 ? + friend int operator != (const mat3 &a, const mat3 &b); // m1 != m2 ? + //friend ostream& operator << (ostream& s, mat3& m); // output to stream + //friend istream& operator >> (istream& s, mat3& m); // input from strm. + friend void swap(mat3 &a, mat3 &b); // swap m1 & m2 + + // necessary friend declarations + + friend vec3 operator * (const mat3 &a, const vec3 &v); // linear transform + friend vec2 operator * (const mat3 &a, const vec2 &v); // linear transform +}; + +/**************************************************************** + * * + * 4x4 Matrix * + * * + ****************************************************************/ + +class mat4 +{ +protected: + + vec4 v[4]; + +public: + + // Constructors + + mat4(); + mat4(const vec4 &v0, const vec4 &v1, const vec4 &v2, const vec4 &v3); + mat4(const mat4 &m); + mat4(float a00, float a01, float a02, float a03, + float a10, float a11, float a12, float a13, + float a20, float a21, float a22, float a23, + float a30, float a31, float a32, float a33 ); + + + // Assignment operators + + mat4 &operator = (const mat4 &m); // assignment of a mat4 + mat4 &operator += (const mat4 &m); // incrementation by a mat4 + mat4 &operator -= (const mat4 &m); // decrementation by a mat4 + mat4 &operator *= (float d); // multiplication by a constant + mat4 &operator /= (float d); // division by a constant + + // special functions + + mat4 transpose() const; // transpose + mat4 inverse() const; // inverse + mat4 &apply(V_FCT_PTR fct); // apply a func. to each element + + void print(FILE *file, const char *name) const; // print matrix to a file + + vec4 &operator [] (int i); // indexing + const vec4 &operator [] (int i) const; // indexing + + void swap_rows(int i, int j); // swap rows i and j + void swap_cols(int i, int j); // swap cols i and j + + // friends + + friend mat4 operator - (const mat4 &a); // -m1 + friend mat4 operator + (const mat4 &a, const mat4 &b); // m1 + m2 + friend mat4 operator - (const mat4 &a, const mat4 &b); // m1 - m2 + friend mat4 operator * (const mat4 &a, const mat4 &b); // m1 * m2 + friend mat4 operator * (const mat4 &a, float d); // m1 * 4.0 + friend mat4 operator * (float d, const mat4 &a); // 4.0 * m1 + friend mat4 operator / (const mat4 &a, float d); // m1 / 3.0 + friend int operator == (const mat4 &a, const mat4 &b); // m1 == m2 ? + friend int operator != (const mat4 &a, const mat4 &b); // m1 != m2 ? + //friend ostream& operator << (ostream& s, mat4& m); // output to stream + //friend istream& operator >> (istream& s, mat4& m); // input from strm. + friend void swap(mat4 &a, mat4 &b); // swap m1 & m2 + + // necessary friend declarations + + friend vec4 operator * (const mat4 &a, const vec4 &v); // linear transform + //friend vec4 operator * (const vec4& v, const mat4& a); // linear transform + friend vec3 operator * (const mat4 &a, const vec3 &v); // linear transform + friend vec3 operator * (const vec3 &v, const mat4 &a); // linear transform +}; + +/**************************************************************** + * * + * 2D functions and 3D functions * + * * + ****************************************************************/ + +mat3 identity2D (); // identity 2D +mat3 translation2D(const vec2 &v); // translation 2D +mat3 rotation2D (const vec2 &Center, float angleDeg); // rotation 2D +mat3 scaling2D (const vec2 &scaleVector); // scaling 2D +mat4 identity3D (); // identity 3D +mat4 translation3D(const vec3 &v); // translation 3D +mat4 rotation3D (const vec3 &Axis, float angleDeg); // rotation 3D +mat4 rotation3Drad(const vec3 &Axis, float angleRad); // rotation 3D +mat4 scaling3D (const vec3 &scaleVector); // scaling 3D +mat4 perspective3D(float d); // perspective 3D + +vec3 operator * (const vec3 &v, const mat3 &a); +vec2 operator * (const vec2 &v, const mat3 &a); +vec3 operator * (const vec3 &v, const mat4 &a); +vec4 operator * (const vec4 &v, const mat4 &a); + +#endif diff --git a/Extras/glui/arcball.cpp b/Extras/glui/arcball.cpp new file mode 100644 index 000000000..d233c7fc0 --- /dev/null +++ b/Extras/glui/arcball.cpp @@ -0,0 +1,237 @@ +/********************************************************************** + + arcball.cpp + + + -------------------------------------------------- + + GLUI User Interface Toolkit (LGPL) + Copyright (c) 1998 Paul Rademacher + Feb 1998, Paul Rademacher (rademach@cs.unc.edu) + Oct 2003, Nigel Stewart - GLUI Code Cleaning + + 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 "arcball.h" + +#include + + +/**************************************** Arcball::Arcball() ****/ +/* Default (void) constructor for Arcball */ + +Arcball::Arcball() +{ + rot_ptr = &rot; + init(); +} + +/**************************************** Arcball::Arcball() ****/ +/* Takes as argument a mat4 to use instead of the internal rot */ + +Arcball::Arcball(mat4 *mtx) +{ + rot_ptr = mtx; +} + + +/**************************************** Arcball::Arcball() ****/ +/* A constructor that accepts the screen center and arcball radius*/ + +Arcball::Arcball(const vec2 &_center, float _radius) +{ + rot_ptr = &rot; + init(); + set_params(_center, _radius); +} + + +/************************************** Arcball::set_params() ****/ + +void Arcball::set_params(const vec2 &_center, float _radius) +{ + center = _center; + radius = _radius; +} + +/*************************************** Arcball::init() **********/ + +void Arcball::init() +{ + center.set( 0.0, 0.0 ); + radius = 1.0; + q_now = quat_identity(); + *rot_ptr = identity3D(); + q_increment = quat_identity(); + rot_increment = identity3D(); + is_mouse_down = false; + is_spinning = false; + damp_factor = 0.0; + zero_increment = true; +} + +/*********************************** Arcball::mouse_to_sphere() ****/ + +vec3 Arcball::mouse_to_sphere(const vec2 &p) +{ + float mag; + vec2 v2 = (p - center) / radius; + vec3 v3( v2[0], v2[1], 0.0 ); + + mag = v2*v2; + + if ( mag > 1.0 ) + v3.normalize(); + else + v3[VZ] = (float) sqrt( 1.0 - mag ); + + /* Now we add constraints - X takes precedence over Y */ + if ( constraint_x ) + { + v3 = constrain_vector( v3, vec3( 1.0, 0.0, 0.0 )); + } + else if ( constraint_y ) + { + v3 = constrain_vector( v3, vec3( 0.0, 1.0, 0.0 )); + } + + return v3; +} + + +/************************************ Arcball::constrain_vector() ****/ + +vec3 Arcball::constrain_vector(const vec3 &vector, const vec3 &axis) +{ + return (vector-(vector*axis)*axis).normalize(); +} + +/************************************ Arcball::mouse_down() **********/ + +void Arcball::mouse_down(int x, int y) +{ + down_pt.set( (float)x, (float) y ); + is_mouse_down = true; + + q_increment = quat_identity(); + rot_increment = identity3D(); + zero_increment = true; +} + + +/************************************ Arcball::mouse_up() **********/ + +void Arcball::mouse_up() +{ + q_now = q_drag * q_now; + is_mouse_down = false; +} + + +/********************************** Arcball::mouse_motion() **********/ + +void Arcball::mouse_motion(int x, int y, int shift, int ctrl, int alt) +{ + /* Set the X constraint if CONTROL key is pressed, Y if ALT key */ + set_constraints( ctrl != 0, alt != 0 ); + + vec2 new_pt( (float)x, (float) y ); + vec3 v0 = mouse_to_sphere( down_pt ); + vec3 v1 = mouse_to_sphere( new_pt ); + + vec3 cross = v0^v1; + + q_drag.set( cross, v0 * v1 ); + + // *rot_ptr = (q_drag * q_now).to_mat4(); + mat4 temp = q_drag.to_mat4(); + *rot_ptr = *rot_ptr * temp; + + down_pt = new_pt; + + /* We keep a copy of the current incremental rotation (= q_drag) */ + q_increment = q_drag; + rot_increment = q_increment.to_mat4(); + + set_constraints(false, false); + + if ( q_increment.s < .999999 ) + { + is_spinning = true; + zero_increment = false; + } + else + { + is_spinning = false; + zero_increment = true; + } +} + + +/********************************** Arcball::mouse_motion() **********/ + +void Arcball::mouse_motion(int x, int y) +{ + mouse_motion(x, y, 0, 0, 0); +} + + +/***************************** Arcball::set_constraints() **********/ + +void Arcball::set_constraints(bool _constraint_x, bool _constraint_y) +{ + constraint_x = _constraint_x; + constraint_y = _constraint_y; +} + +/***************************** Arcball::idle() *********************/ + +void Arcball::idle() +{ + if (is_mouse_down) + { + is_spinning = false; + zero_increment = true; + } + + if (damp_factor < 1.0f) + q_increment.scale_angle(1.0f - damp_factor); + + rot_increment = q_increment.to_mat4(); + + if (q_increment.s >= .999999f) + { + is_spinning = false; + zero_increment = true; + } +} + + +/************************ Arcball::set_damping() *********************/ + +void Arcball::set_damping(float d) +{ + damp_factor = d; +} + + + + + diff --git a/Extras/glui/arcball.h b/Extras/glui/arcball.h new file mode 100644 index 000000000..ef69afc95 --- /dev/null +++ b/Extras/glui/arcball.h @@ -0,0 +1,97 @@ +/********************************************************************** + + arcball.h + + GLUI User Interface Toolkit (LGPL) + Copyright (c) 1998 Paul Rademacher + Feb 1998, Paul Rademacher (rademach@cs.unc.edu) + Oct 2003, Nigel Stewart - GLUI Code Cleaning + + + 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 + + --------------------------------------------------------------------- + + A C++ class that implements the Arcball, as described by Ken + Shoemake in Graphics Gems IV. + This class takes as input mouse events (mouse down, mouse drag, + mouse up), and creates the appropriate quaternions and 4x4 matrices + to represent the rotation given by the mouse. + + This class is used as follows: + - initialize [either in the constructor or with set_params()], the + center position (x,y) of the arcball on the screen, and the radius + - on mouse down, call mouse_down(x,y) with the mouse position + - as the mouse is dragged, repeatedly call mouse_motion() with the + current x and y positions. One can optionally pass in the current + state of the SHIFT, ALT, and CONTROL keys (passing zero if keys + are not pressed, non-zero otherwise), which constrains + the rotation to certain axes (X for CONTROL, Y for ALT). + - when the mouse button is released, call mouse_up() + + Axis constraints can also be explicitly set with the + set_constraints() function. + + The current rotation is stored in the 4x4 float matrix 'rot'. + It is also stored in the quaternion 'q_now'. + +**********************************************************************/ + +#ifndef GLUI_ARCBALL_H +#define GLUI_ARCBALL_H + +#include "glui_internal.h" +#include "algebra3.h" +#include "quaternion.h" + +class Arcball +{ +public: + Arcball(); + Arcball(mat4 *mtx); + Arcball(const vec2 ¢er, float radius); + + void set_damping(float d); + void idle(); + void mouse_down(int x, int y); + void mouse_up(); + void mouse_motion(int x, int y, int shift, int ctrl, int alt); + void mouse_motion(int x, int y); + void set_constraints(bool constrain_x, bool constrain_y); + void set_params(const vec2 ¢er, float radius); + void reset_mouse(); + void init(); + + vec3 constrain_vector(const vec3 &vector, const vec3 &axis); + vec3 mouse_to_sphere(const vec2 &p); + + //public: + int is_mouse_down; /* true for down, false for up */ + int is_spinning; + quat q_now, q_down, q_drag, q_increment; + vec2 down_pt; + mat4 rot, rot_increment; + mat4 *rot_ptr; + + bool constraint_x, constraint_y; + vec2 center; + float radius, damp_factor; + int zero_increment; +}; + +#endif diff --git a/Extras/glui/glui.cpp b/Extras/glui/glui.cpp new file mode 100644 index 000000000..221e68d2c --- /dev/null +++ b/Extras/glui/glui.cpp @@ -0,0 +1,2105 @@ +/**************************************************************************** + + GLUI User Interface Toolkit (LGPL) + --------------------------- + + glui.cpp + + -------------------------------------------------- + + 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" + + +/** + Note: moving this routine here from glui_add_controls.cpp prevents the linker + from touching glui_add_controls.o in non-deprecated programs, which + descreases the linked size of small GLUI programs substantially (100K+). (OSL 2006/06) +*/ +void GLUI_Node::add_child_to_control(GLUI_Node *parent,GLUI_Control *child) +{ + GLUI_Control *parent_control; + + /*** Collapsible nodes have to be handled differently, b/c the first and + last children are swapped in and out ***/ + parent_control = ((GLUI_Control*)parent); + if ( parent_control->collapsible == true ) { + if ( NOT parent_control->is_open ) { + /** Swap in the original first and last children **/ + parent_control->child_head = parent_control->collapsed_node.child_head; + parent_control->child_tail = parent_control->collapsed_node.child_tail; + + /*** Link this control ***/ + child->link_this_to_parent_last( parent_control ); + + /** Swap the children back out ***/ + parent_control->collapsed_node.child_head = parent_control->child_head; + parent_control->collapsed_node.child_tail = parent_control->child_tail; + parent_control->child_head = NULL; + parent_control->child_tail = NULL; + } + else { + child->link_this_to_parent_last( parent_control ); + } + } + else { + child->link_this_to_parent_last( parent_control ); + } + child->glui = (GLUI*) parent_control->glui; + child->update_size(); + child->enabled = parent_control->enabled; + child->glui->refresh(); + + /** Now set the 'hidden' var based on the parent **/ + if ( parent_control->hidden OR + (parent_control->collapsible AND NOT parent_control->is_open ) ) + { + child->hidden = true; + } +} + + +/************************************ GLUI_Node::add_control() **************/ + +int GLUI_Node::add_control( GLUI_Control *child ) +{ + add_child_to_control(this,child); + return true; +} + +/************************************ GLUI_Main::add_control() **************/ + +int GLUI_Main::add_control( GLUI_Node *parent, GLUI_Control *control ) +{ + add_child_to_control(parent,control); + return true; +} + + + +/*** This object must be used to create a GLUI ***/ + +GLUI_Master_Object GLUI_Master; + +/************************************ finish_drawing() *********** + Probably a silly routine. Called after all event handling callbacks. +*/ + +static void finish_drawing(void) +{ + glFinish(); +} + +/************************************ GLUI_CB::operator()() ************/ +void GLUI_CB::operator()(GLUI_Control*ctrl) const +{ + if (idCB) idCB(ctrl->user_id); + if (objCB) objCB(ctrl); +} + + +/************************************************ GLUI::GLUI() **********/ + +int GLUI::init( const char *text, long flags, int x, int y, int parent_window ) +{ + int old_glut_window; + + this->flags = flags; + + window_name = text; + + buffer_mode = buffer_back; ///< New smooth way + //buffer_mode = buffer_front; ///< Old flickery way (a bit faster). + + /*** We copy over the current window callthroughs ***/ + /*** (I think this might actually only be needed for subwindows) ***/ + /* glut_keyboard_CB = GLUI_Master.glut_keyboard_CB; + glut_reshape_CB = GLUI_Master.glut_reshape_CB; + glut_special_CB = GLUI_Master.glut_special_CB; + glut_mouse_CB = GLUI_Master.glut_mouse_CB;*/ + + + if ( (flags & GLUI_SUBWINDOW) != GLUI_SUBWINDOW ) { /* not a subwindow, creating a new top-level window */ + old_glut_window = glutGetWindow(); + + create_standalone_window( window_name.c_str(), x, y ); + setup_default_glut_callbacks(); + + if ( old_glut_window > 0 ) + glutSetWindow( old_glut_window ); + + top_level_glut_window_id = glut_window_id; + } + else /* *is* a subwindow */ + { + old_glut_window = glutGetWindow(); + + create_subwindow( parent_window, flags ); + setup_default_glut_callbacks(); + + if ( old_glut_window > 0 ) + glutSetWindow( old_glut_window ); + + top_level_glut_window_id = parent_window; + + /* + glutReshapeFunc( glui_parent_window_reshape_func ); + glutSpecialFunc( glui_parent_window_special_func ); + glutKeyboardFunc( glui_parent_window_keyboard_func ); + glutMouseFunc( glui_parent_window_mouse_func ); + */ + + } + + return true; +} + + +/**************************** GLUI_Main::create_standalone_window() ********/ + +void GLUI_Main::create_standalone_window( const char *name, int x, int y ) +{ + glutInitWindowSize( 100, 100 ); + if ( x >= 0 OR y >= 0 ) + glutInitWindowPosition( x, y ); + glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE ); + glut_window_id = glutCreateWindow( name ); +} + + +/******************************** GLUI_Main::create_subwindow() **********/ + +void GLUI_Main::create_subwindow( int parent_window, int window_alignment ) +{ + glut_window_id = glutCreateSubWindow(parent_window, 0,0, 100, 100); + this->parent_window = parent_window; +} + + +/**************************** GLUI_Main::setup_default_glut_callbacks() *****/ + +void GLUI_Main::setup_default_glut_callbacks( void ) +{ + glutDisplayFunc( glui_display_func ); + glutReshapeFunc( glui_reshape_func ); + glutKeyboardFunc( glui_keyboard_func ); + glutSpecialFunc( glui_special_func ); + glutMouseFunc( glui_mouse_func ); + glutMotionFunc( glui_motion_func ); + glutPassiveMotionFunc( glui_passive_motion_func ); + glutEntryFunc( glui_entry_func ); + glutVisibilityFunc( glui_visibility_func ); + /* glutIdleFunc( glui_idle_func ); // FIXME! 100% CPU usage! */ +} + + +/********************************************** glui_display_func() ********/ + +void glui_display_func(void) +{ + GLUI *glui; + + /* printf( "display func\n" ); */ + + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + + if ( glui ) { + glui->display(); + /* + Do not do anything after the above line, b/c the GLUI + window might have just closed itself + */ + } +} + + +/********************************************** glui_reshape_func() ********/ + +void glui_reshape_func(int w,int h ) +{ + GLUI *glui; + GLUI_Glut_Window *glut_window; + int current_window; + + /*printf( "glui_reshape_func(): %d w/h: %d/%d\n", glutGetWindow(), w, h ); */ + + current_window = glutGetWindow(); + + /*** First check if this is main glut window ***/ + glut_window = GLUI_Master.find_glut_window( current_window ); + if ( glut_window ) { + if (glut_window->glut_reshape_CB) glut_window->glut_reshape_CB(w,h); + + /*** Now send reshape events to all subwindows ***/ + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while(glui) { + if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND + glui->parent_window == current_window ) { + glutSetWindow( glui->get_glut_window_id()); + glui->reshape(w,h); + /* glui->check_subwindow_position(); */ + } + glui = (GLUI*) glui->next(); + } + } + else { + /*** A standalone GLUI window ***/ + + glui = GLUI_Master.find_glui_by_window_id( current_window ); + + if ( glui ) { + glui->reshape(w,h); + } + } +} + +/********************************************** glui_keyboard_func() ********/ + +void glui_keyboard_func(unsigned char key, int x, int y) +{ + GLUI *glui; + int current_window; + GLUI_Glut_Window *glut_window; + + current_window = glutGetWindow(); + glut_window = GLUI_Master.find_glut_window( current_window ); + + /*printf( "key: %d\n", current_window ); */ + + if ( glut_window ) { /** Was event in a GLUT window? **/ + if ( GLUI_Master.active_control_glui AND GLUI_Master.active_control ) { + glutSetWindow( GLUI_Master.active_control_glui->get_glut_window_id() ); + + GLUI_Master.active_control_glui->keyboard(key,x,y); + finish_drawing(); + + glutSetWindow( current_window ); + } + else { + if (glut_window->glut_keyboard_CB) + glut_window->glut_keyboard_CB( key, x, y ); + } + } + else { /*** Nope, event was in a standalone GLUI window **/ + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + + if ( glui ) { + glui->keyboard(key,x,y); + finish_drawing(); + } + } +} + + +/************************************************ glui_special_func() ********/ + +void glui_special_func(int key, int x, int y) +{ + GLUI *glui; + int current_window; + GLUI_Glut_Window *glut_window; + + current_window = glutGetWindow(); + glut_window = GLUI_Master.find_glut_window( current_window ); + + if (glut_window) /** Was event in a GLUT window? **/ + { + if ( GLUI_Master.active_control_glui AND GLUI_Master.active_control ) + { + glutSetWindow( GLUI_Master.active_control_glui->get_glut_window_id() ); + + GLUI_Master.active_control_glui->special(key,x,y); + finish_drawing(); + + glutSetWindow( current_window ); + } + else + { + if (glut_window->glut_special_CB) + glut_window->glut_special_CB( key, x, y ); + } + } + else /*** Nope, event was in a standalone GLUI window **/ + { + glui = GLUI_Master.find_glui_by_window_id(glutGetWindow()); + + if ( glui ) + { + glui->special(key,x,y); + finish_drawing(); + } + } +} + +/********************************************** glui_mouse_func() ********/ + +void glui_mouse_func(int button, int state, int x, int y) +{ + GLUI *glui; + int current_window; + GLUI_Glut_Window *glut_window; + + current_window = glutGetWindow(); + glut_window = GLUI_Master.find_glut_window( current_window ); + + if ( glut_window ) { /** Was event in a GLUT window? **/ + if ( GLUI_Master.active_control_glui != NULL ) + GLUI_Master.active_control_glui->deactivate_current_control(); + + if (glut_window->glut_mouse_CB) + glut_window->glut_mouse_CB( button, state, x, y ); + finish_drawing(); + } + else { /** Nope - event was in a GLUI standalone window **/ + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + if ( glui ) { + glui->passive_motion( 0,0 ); + glui->mouse( button, state, x, y ); + finish_drawing(); + } + } +} + + +/********************************************** glui_motion_func() ********/ + +void glui_motion_func(int x, int y) +{ + GLUI *glui; + + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + + if ( glui ) { + glui->motion(x,y); + finish_drawing(); + } + +} + + +/**************************************** glui_passive_motion_func() ********/ + +void glui_passive_motion_func(int x, int y) +{ + GLUI *glui; + + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + + if ( glui ) { + glui->passive_motion(x,y); + finish_drawing(); + } +} + + +/********************************************** glui_entry_func() ********/ + +void glui_entry_func(int state) +{ + GLUI *glui; + + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + + if ( glui ) { + glui->entry(state); + } +} + + +/******************************************** glui_visibility_func() ********/ + +void glui_visibility_func(int state) +{ + GLUI *glui; + + /* printf( "IN GLUI VISIBILITY()\n" ); */ + /* fflush( stdout ); */ + + glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() ); + + if ( glui ) { + glui->visibility(state); + } +} + + +/********************************************** glui_idle_func() ********/ +/* Send idle event to each glui, then to the main window */ + +void glui_idle_func(void) +{ + GLUI *glui; + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + glui->idle(); + finish_drawing(); + + glui = (GLUI*) glui->next(); + } + + if ( GLUI_Master.glut_idle_CB ) { + /*** We set the current glut window before calling the user's + idle function, even though glut explicitly says the window id is + undefined in an idle callback. ***/ + + /** Check what the current window is first ***/ + + /*** Arbitrarily set the window id to the main gfx window of the + first glui window ***/ + /* int current_window, new_window; */ + /* current_window = glutGetWindow(); */ + /* if (GLUI_Master.gluis.first_child() != NULL ) { */ + /* new_window = ((GLUI_Main*)GLUI_Master.gluis.first_child())-> */ + /* main_gfx_window_id; */ + /* if ( new_window > 0 AND new_window != old_window ) { */ + /* --- Window is changed only if its not already the current window ---*/ + /* glutSetWindow( new_window ); */ + /* } */ + /*} */ + + GLUI_Master.glut_idle_CB(); + } +} + +/*********************************** GLUI_Master_Object::GLUI_Master_Object() ******/ + +GLUI_Master_Object::GLUI_Master_Object() +: glui_id_counter(1), + glut_idle_CB(NULL) +{ +} + +GLUI_Master_Object::~GLUI_Master_Object() +{ +} + +/*********************************** GLUI_Master_Object::create_glui() ******/ + +GLUI *GLUI_Master_Object::create_glui( const char *name, long flags,int x,int y ) +{ + GLUI *new_glui = new GLUI; + new_glui->init( name, flags, x, y, -1 ); + new_glui->link_this_to_parent_last( &this->gluis ); + return new_glui; +} + + +/************************** GLUI_Master_Object::create_glui_subwindow() ******/ + +GLUI *GLUI_Master_Object::create_glui_subwindow( int parent_window, + long flags ) +{ + GLUI *new_glui = new GLUI; + GLUI_String new_name; + glui_format_str( new_name, "subwin_%p", this ); + + new_glui->init( new_name.c_str(), flags | GLUI_SUBWINDOW, 0,0, + parent_window ); + new_glui->main_panel->set_int_val( GLUI_PANEL_EMBOSSED ); + new_glui->link_this_to_parent_last( &this->gluis ); + return new_glui; +} + + +/********************** GLUI_Master_Object::find_glui_by_window_id() ********/ + +GLUI *GLUI_Master_Object::find_glui_by_window_id( int window_id ) +{ + GLUI_Node *node; + + node = gluis.first_child(); + while( node ) { + if ( ((GLUI*)node)->get_glut_window_id() == window_id ) + return (GLUI*) node; + + node = node->next(); + } + return NULL; +} + + +/******************************************** GLUI_Main::display() **********/ + +void GLUI_Main::display( void ) +{ + int win_w, win_h; + + /* SUBTLE: on freeGLUT, the correct window is always already set. + But older versions of GLUT need this call, or else subwindows + don't update properly when resizing or damage-painting. + */ + glutSetWindow( glut_window_id ); + + /* Set up OpenGL state for widget drawing */ + glDisable( GL_DEPTH_TEST ); + glCullFace( GL_BACK ); + glDisable( GL_CULL_FACE ); + glDisable( GL_LIGHTING ); + set_current_draw_buffer(); + + /**** This function is used as a special place to do 'safe' processing, + e.g., handling window close requests. + That is, we can't close the window directly in the callback, so + we set a flag, post a redisplay message (which eventually calls + this function), then close the window safely in here. ****/ + if ( closing ) { + close_internal(); + return; + } + + /* if ( TEST_AND( this->flags, GLUI_SUBWINDOW )) + check_subwindow_position(); + */ + + win_w = glutGet( GLUT_WINDOW_WIDTH ); + win_h = glutGet( GLUT_WINDOW_HEIGHT ); + + /*** Check here if the window needs resizing ***/ + if ( win_w != main_panel->w OR win_h != main_panel->h ) { + glutReshapeWindow( main_panel->w, main_panel->h ); + return; + } + + /******* Draw GLUI window ******/ + glClearColor( (float) bkgd_color.r / 255.0, + (float) bkgd_color.g / 255.0, + (float) bkgd_color.b / 255.0, + 1.0 ); + glClear( GL_COLOR_BUFFER_BIT ); /* | GL_DEPTH_BUFFER_BIT ); */ + + set_ortho_projection(); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + /*** Rotate image so y increases downward. + In normal OpenGL, y increases upward. ***/ + glTranslatef( (float) win_w/2.0, (float) win_h/2.0, 0.0 ); + glRotatef( 180.0, 0.0, 1.0, 0.0 ); + glRotatef( 180.0, 0.0, 0.0, 1.0 ); + glTranslatef( (float) -win_w/2.0, (float) -win_h/2.0, 0.0 ); + + // Recursively draw the main panel + // main_panel->draw_bkgd_box( 0, 0, win_w, win_h ); + main_panel->draw_recursive( 0, 0 ); + + switch (buffer_mode) { + case buffer_front: /* Make sure drawing gets to screen */ + glFlush(); + break; + case buffer_back: /* Bring back buffer to front */ + glutSwapBuffers(); + break; + } +} + + + + +/*************************************** _glutBitmapWidthString() **********/ + +int _glutBitmapWidthString( void *font, const char *s ) +{ + const char *p = s; + int width = 0; + + while( *p != '\0' ) { + width += glutBitmapWidth( font, *p ); + p++; + } + + return width; +} + +/************************************ _glutBitmapString *********************/ +/* Displays the contents of a string using GLUT's bitmap character function */ +/* Does not handle newlines */ + +void _glutBitmapString( void *font, const char *s ) +{ + const char *p = s; + + while( *p != '\0' ) { + glutBitmapCharacter( font, *p ); + p++; + } +} + + + +/****************************** GLUI_Main::reshape() **************/ + +void GLUI_Main::reshape( int reshape_w, int reshape_h ) +{ + int new_w, new_h; + + pack_controls(); + + new_w = main_panel->w;/* + 1; */ + new_h = main_panel->h;/* + 1; */ + + if ( reshape_w != new_w OR reshape_h != new_h ) { + this->w = new_w; + this->h = new_h; + + glutReshapeWindow( new_w, new_h ); + } + else { + } + + if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) { + check_subwindow_position(); + + /***** if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) { + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) { + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) { + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_RIGHT )) { + } + ****/ + } + + glViewport( 0, 0, new_w, new_h ); + + /* printf( "%d: %d\n", glutGetWindow(), this->flags ); */ + + glutPostRedisplay(); +} + + +/****************************** GLUI_Main::keyboard() **************/ + +void GLUI_Main::keyboard(unsigned char key, int x, int y) +{ + GLUI_Control *new_control; + + curr_modifiers = glutGetModifiers(); + + /*** If it's a tab or shift tab, we don't pass it on to the controls. + Instead, we use it to cycle through active controls ***/ + if ( key == '\t' AND !mouse_button_down AND + (!active_control || !active_control->wants_tabs())) { + if ( curr_modifiers & GLUT_ACTIVE_SHIFT ) { + new_control = find_prev_control( active_control ); + } + else { + new_control = find_next_control( active_control ); + } + + /* if ( new_control ) + printf( "new_control: %s\n", new_control->name ); + */ + + deactivate_current_control(); + activate_control( new_control, GLUI_ACTIVATE_TAB ); + } + else if ( key == ' ' AND active_control + AND active_control->spacebar_mouse_click ) { + /*** If the user presses the spacebar, and a non-edittext control + is active, we send it a mouse down event followed by a mouse up + event (simulated mouse-click) ***/ + + active_control->mouse_down_handler( 0, 0 ); + active_control->mouse_up_handler( 0, 0, true ); + } else { + /*** Pass the keystroke onto the active control, if any ***/ + if ( active_control != NULL ) + active_control->key_handler( key, curr_modifiers ); + } +} + + +/****************************** GLUI_Main::special() **************/ + +void GLUI_Main::special(int key, int x, int y) +{ + curr_modifiers = glutGetModifiers(); + + /*** Pass the keystroke onto the active control, if any ***/ + if ( active_control != NULL ) + active_control->special_handler( key, glutGetModifiers() ); +} + + + +/****************************** GLUI_Main::mouse() **************/ + +void GLUI_Main::mouse(int button, int state, int x, int y) +{ + int callthrough; + GLUI_Control *control; + + /* printf( "MOUSE: %d %d\n", button, state ); */ + + callthrough = true; + + curr_modifiers = glutGetModifiers(); + + if ( button == GLUT_LEFT ) { + control = find_control( x, y ); + + /*if ( control ) printf( "control: %s\n", control->name.c_str() ); */ + + if ( mouse_button_down AND active_control != NULL AND + state == GLUT_UP ) + { + /** We just released the mouse, which was depressed at some control **/ + + callthrough = active_control-> + mouse_up_handler( x, y, control==active_control); + glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); + + if ( active_control AND + active_control->active_type == GLUI_CONTROL_ACTIVE_MOUSEDOWN AND 0) + { + /*** This is a control that needs to be deactivated when the + mouse button is released ****/ + deactivate_current_control(); + } + } + else { + if ( control ) { + if ( NOT mouse_button_down AND state == GLUT_DOWN ) { + /*** We just pressed the mouse down at some control ***/ + + if ( active_control != control ) { + if ( active_control != NULL ) { + /** There is an active control still - deactivate it ***/ + deactivate_current_control(); + } + } + + if ( control->enabled ) { + activate_control( control, GLUI_ACTIVATE_MOUSE ); + callthrough = control->mouse_down_handler( x, y ); + } + } + } + } + + if ( state == GLUT_DOWN ) + mouse_button_down = true; + else if ( state == GLUT_UP ) + mouse_button_down = false; + } + + /** + NO CALLTHROUGH NEEDED FOR MOUSE EVENTS + if ( callthrough AND glut_mouse_CB ) + glut_mouse_CB( button, state, x, y ); + **/ + + callthrough=callthrough; /* To get rid of compiler warnings */ +} + + +/****************************** GLUI_Main::motion() **************/ + +void GLUI_Main::motion(int x, int y) +{ + int callthrough; + GLUI_Control *control; + + /* printf( "MOTION: %d %d\n", x, y ); */ + + callthrough = true; + + control = find_control(x,y); + + if ( mouse_button_down AND active_control != NULL ) { + callthrough = + active_control->mouse_held_down_handler(x,y,control==active_control); + } + + /** + NO CALLTHROUGH NEEDED FOR MOUSE EVENTS + + if ( callthrough AND glut_motion_CB ) + glut_motion_CB(x,y); + **/ + + callthrough=callthrough; /* To get rid of compiler warnings */ +} + + +/*********************** GLUI_Main::passive_motion() **************/ + +void GLUI_Main::passive_motion(int x, int y) +{ + GLUI_Control *control; + + control = find_control( x, y ); + + /* printf( "%p %p\n", control, mouse_over_control ); */ + + if ( control != mouse_over_control ) { + if ( mouse_over_control ) { + mouse_over_control->mouse_over( false, x, y ); + } + + if ( control ) { + control->mouse_over( true, x, y ); + mouse_over_control = control; + } + } + + /* + if ( curr_cursor != GLUT_CURSOR_INHERIT ) { + curr_cursor = GLUT_CURSOR_INHERIT; + glutSetCursor( GLUT_CURSOR_INHERIT ); + }*/ + +} + + +/****************************** GLUI_Main::entry() **************/ + +void GLUI_Main::entry(int state) +{ + /*if ( NOT active_control OR ( active_control AND ( active_control->type == GLUI_CONTROL_EDITTEXT + OR active_control->type == GLUI_CONTROL_SPINNER) ) )*/ + glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); +} + + +/****************************** GLUI_Main::visibility() **************/ + +void GLUI_Main::visibility(int state) +{ +} + + +/****************************** GLUI_Main::idle() **************/ + +void GLUI_Main::idle(void) +{ + /*** Pass the idle event onto the active control, if any ***/ + + /* printf( "IDLE \t" ); */ + + if ( active_control != NULL ) { + /* First we check if the control actually needs the idle right now. + Otherwise, let's avoid wasting cycles and OpenGL context switching */ + + if ( active_control->needs_idle() ) { + /*** Set the current glut window to the glui window */ + /*** But don't change the window if we're already at that window ***/ + + if ( glut_window_id > 0 AND glutGetWindow() != glut_window_id ) { + glutSetWindow( glut_window_id ); + } + + active_control->idle(); + } + } +} + +int GLUI_Main::needs_idle( void ) +{ + return active_control != NULL && active_control->needs_idle(); +} + + +/******************************************* GLUI_Main::find_control() ******/ + +GLUI_Control *GLUI_Main::find_control( int x, int y ) +{ + GLUI_Control *node, *last_container; + + last_container = NULL; + + node = main_panel; + while( node != NULL ) { + if ( !dynamic_cast(node) AND + PT_IN_BOX( x, y, + node->x_abs, node->x_abs + node->w, + node->y_abs, node->y_abs + node->h ) + ) + { + /*** Point is inside current node ***/ + + if ( node->first_child() == NULL ) { + /*** SPECIAL CASE: for edittext boxes, we make sure click is + in box, and not on name string. This should be generalized + for all controls later... ***/ + if ( dynamic_cast(node) ) { + if ( x < node->x_abs + ((GLUI_EditText*)node)->text_x_offset ) + return (GLUI_Control*) node->parent(); + } + + return node; /* point is inside this node, and node has no children, + so return this node as the selected node */ + } + else { + /*** This is a container class ***/ + last_container = node; + node = (GLUI_Control*) node->first_child(); /* Descend into child */ + } + + } + else { + node = (GLUI_Control*) node->next(); + } + } + + /** No leaf-level nodes found to accept the mouse click, so + return the last container control found which DOES accept the click **/ + + if ( last_container ) { + /* printf( "ctrl: '%s'\n", last_container->name ); */ + + return last_container; + } + else { + return NULL; + } +} + + +/************************************* GLUI_Main::pack_controls() ***********/ + +void GLUI_Main::pack_controls( void ) +{ + main_panel->pack(0,0); + + /**** Now align controls within their bounds ****/ + align_controls( main_panel ); + + /*** If this is a subwindow, expand panel to fit parent window ***/ + if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) { + int parent_h, parent_w; + int orig_window; + + orig_window = glutGetWindow(); + glutSetWindow( this->top_level_glut_window_id ); + parent_h = glutGet( GLUT_WINDOW_HEIGHT ); + parent_w = glutGet( GLUT_WINDOW_WIDTH ); + + glutSetWindow( orig_window ); + + /* printf( "%d %d\n", parent_h, parent_w ); */ + + if ( 1 ) { + if ( TEST_AND(this->flags,GLUI_SUBWINDOW_TOP )) { + main_panel->w = MAX( main_panel->w, parent_w ); + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) { + main_panel->h = MAX( main_panel->h, parent_h ); + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_BOTTOM )) { + main_panel->w = MAX( main_panel->w, parent_w ); + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_RIGHT )) { + main_panel->h = MAX( main_panel->h, parent_h ); + } + } + } + + this->w = main_panel->w; + this->h = main_panel->h; +} + + +/************************************ GLUI_Main::align_controls() **********/ + +void GLUI_Main::align_controls( GLUI_Control *control ) +{ + GLUI_Control *child; + + control->align(); + + child = (GLUI_Control*) control->first_child(); + + while( child != NULL ) { + align_controls( child ); + + child = (GLUI_Control*)child->next(); + } +} + + + +/*********************************** GLUI::set_main_gfx_window() ************/ + +void GLUI::set_main_gfx_window( int window_id ) +{ + main_gfx_window_id = window_id; +} + + +/********************************* GLUI_Main::post_update_main_gfx() ********/ + +void GLUI_Main::post_update_main_gfx( void ) +{ + int old_window; + + if ( main_gfx_window_id > 0 ) { + old_window = glutGetWindow(); + glutSetWindow( main_gfx_window_id ); + glutPostRedisplay(); + if( old_window > 0 ) + glutSetWindow( old_window ); + } +} + +/********************************* GLUI_Main::should_redraw_now() ********/ +/** Return true if this control should redraw itself immediately (front buffer); + Or queue up a redraw and return false if it shouldn't (back buffer). + + Called from GLUI_Control::redraw. +*/ +bool GLUI_Main::should_redraw_now(GLUI_Control *ctl) +{ + switch (buffer_mode) { + case buffer_front: return true; /* always draw in front-buffer mode */ + case buffer_back: { + int orig = ctl->set_to_glut_window(); + glutPostRedisplay(); /* redraw soon */ + ctl->restore_window(orig); + return false; /* don't draw now. */ + } + } + return false; /* never executed */ +} + +/********************************* GLUI_Main::set_current_draw_buffer() ********/ + +int GLUI_Main::set_current_draw_buffer( void ) +{ + /* Save old buffer */ + GLint state; + glGetIntegerv( GL_DRAW_BUFFER, &state ); + /* Switch to new buffer */ + switch (buffer_mode) { + case buffer_front: glDrawBuffer(GL_FRONT); break; + case buffer_back: glDrawBuffer(GL_BACK); break; /* might not be needed... */ + } + return (int)state; +} + + +/********************************* GLUI_Main::restore_draw_buffer() **********/ + +void GLUI_Main::restore_draw_buffer( int buffer_state ) +{ + glDrawBuffer( buffer_state ); +} + + +/******************************************** GLUI_Main::GLUI_Main() ********/ + +GLUI_Main::GLUI_Main( void ) +{ + mouse_button_down = false; + w = 0; + h = 0; + active_control = NULL; + mouse_over_control = NULL; + main_gfx_window_id = -1; + glut_window_id = -1; + curr_modifiers = 0; + closing = false; + parent_window = -1; + glui_id = GLUI_Master.glui_id_counter; + GLUI_Master.glui_id_counter++; + + font = GLUT_BITMAP_HELVETICA_12; + curr_cursor = GLUT_CURSOR_LEFT_ARROW; + + int r=200, g=200, b=200; + bkgd_color.set( r,g,b ); + bkgd_color_f[0] = r / 255.0; + bkgd_color_f[1] = g / 255.0; + bkgd_color_f[2] = b / 255.0; + + /*** Create the main panel ***/ + main_panel = new GLUI_Panel; + main_panel->set_int_val( GLUI_PANEL_NONE ); + main_panel->glui = (GLUI*) this; + main_panel->name = "\0"; +} + +/************************************ GLUI_Main::draw_raised_box() **********/ + +void GLUI_Main::draw_raised_box( int x, int y, int w, int h ) +{ + w = w+x; + h = h+y; + + glColor3ub( bkgd_color.r, bkgd_color.g, bkgd_color.b ); + glBegin( GL_LINE_LOOP ); + glVertex2i( x+1, y+1 ); glVertex2i( w-1, y+1 ); + glVertex2i( w-1, h-1 ); glVertex2i( x+1, h-1 ); + glEnd(); + + glColor3d( 1.0, 1.0, 1.0 ); + glBegin( GL_LINE_STRIP ); + glVertex2i( x, h ); glVertex2i( x, y ); glVertex2i( w, y ); + glEnd(); + + glColor3d( 0.0, 0.0, 0.0 ); + glBegin( GL_LINE_STRIP ); + glVertex2i( w, y ); glVertex2i( w, h ); glVertex2i( x, h ); + glEnd(); + + glColor3d( .5, .5, .5 ); + glBegin( GL_LINE_STRIP ); + glVertex2i( w-1, y+1 ); glVertex2i( w-1, h-1 ); glVertex2i( x+1, h-1 ); + glEnd(); +} + + +/************************************ GLUI_Main::draw_lowered_box() **********/ +/* Not quite perfect... **/ + +void GLUI_Main::draw_lowered_box( int x, int y, int w, int h ) +{ + w = w+x; + h = h+y; + + glColor3ub( bkgd_color.r, bkgd_color.g, bkgd_color.b ); + glBegin( GL_LINE_LOOP ); + glVertex2i( x+1, y+1 ); glVertex2i( w-1, y+1 ); + glVertex2i( w-1, h-1 ); glVertex2i( x+1, h-1 ); + glEnd(); + + glColor3d( 0.0, 0.0, 0.0 ); + glBegin( GL_LINE_STRIP ); + glVertex2i( x, h ); glVertex2i( x, y ); glVertex2i( w, y ); + glEnd(); + + glColor3d( 1.0, 1.0, 1.0 ); + glBegin( GL_LINE_STRIP ); + glVertex2i( w, y ); glVertex2i( w, h ); glVertex2i( x, h ); + glEnd(); + + glColor3d( .5, .5, .5 ); + glBegin( GL_LINE_STRIP ); + glVertex2i( w-1, y+1 ); glVertex2i( w-1, h-1 ); glVertex2i( x+1, h-1 ); + glEnd(); +} + + +/************************************* GLUI_Main::activate_control() *********/ + +void GLUI_Main::activate_control( GLUI_Control *control, int how ) +{ + /** Are we not activating a control in the same window as the + previous active control? */ + if ( GLUI_Master.active_control_glui AND + this != (GLUI_Main*) GLUI_Master.active_control_glui ) { + GLUI_Master.active_control_glui->deactivate_current_control(); + } + + /******* Now activate it *****/ + if ( control != NULL AND control->can_activate AND control->enabled ) { + active_control = control; + + control->activate(how); + + /*if ( NOT active_control->is_container OR */ + /* active_control->type == GLUI_CONTROL_ROLLOUT) { */ + active_control->redraw(); + /*} */ + } + else { + active_control = NULL; + } + + /* printf( "activate: %d\n", glutGetWindow() ); */ + GLUI_Master.active_control = active_control; + GLUI_Master.active_control_glui = (GLUI*) this; +} + + +/************************* GLUI_Main::deactivate_current_control() **********/ + +void GLUI_Main::deactivate_current_control( void ) +{ + int orig; + + if ( active_control != NULL ) { + orig = active_control->set_to_glut_window(); + + active_control->deactivate(); + + /** If this isn't a container control, then redraw it in its + deactivated state. Container controls, such as panels, look + the same activated or not **/ + + /*if ( NOT active_control->is_container OR */ + /* active_control->type == GLUI_CONTROL_ROLLOUT ) { */ + active_control->redraw(); + /*} */ + + active_control->restore_window( orig ); + + active_control = NULL; + } + + /* printf( "deactivate: %d\n", glutGetWindow() ); */ + GLUI_Master.active_control = NULL; + GLUI_Master.active_control_glui = NULL; +} + + +/****************************** GLUI_Main::find_next_control() **************/ + +GLUI_Control *GLUI_Main::find_next_control_( GLUI_Control *control ) +{ + /*** THIS IS NOT find_next_control()! This is an unused older + version (look at the underscore at the end) ***/ + + if ( control == NULL ) + return find_next_control_rec( main_panel ); + else + return find_next_control_rec( control ); +} + +/****************************** GLUI_Main::find_next_control() **************/ + +GLUI_Control *GLUI_Main::find_next_control_rec( GLUI_Control *control ) +{ + GLUI_Control *child = NULL, *rec_control, *sibling; + + /*** Recursively investigate children ***/ + child = (GLUI_Control*) control->first_child(); + if ( child ) { + /*** If we can activate the first child, then do so ***/ + if ( child->can_activate AND child->enabled ) + return child; + else /*** Recurse into first child ***/ + rec_control = find_next_control_rec( child ); + + if ( rec_control ) + return rec_control; + } + + /*** At this point, either we don't have children, or the child cannot + be activated. So let's try the next sibling ***/ + + sibling = (GLUI_Control*) control->next(); + if ( sibling ) { + if ( sibling->can_activate AND sibling->enabled ) + return sibling; + else /*** Recurse into sibling ***/ + rec_control = find_next_control_rec( sibling ); + + if ( rec_control ) + return rec_control; + } + + return NULL; +} + + +/****************************** GLUI_Main::find_next_control() **************/ + +GLUI_Control *GLUI_Main::find_next_control( GLUI_Control *control ) +{ + GLUI_Control *tmp_control = NULL; + int back_up; + + if ( control == NULL ) + control = main_panel; + + while( control != NULL ) { + /** see if this control has a child **/ + tmp_control = (GLUI_Control*) control->first_child(); + + if ( tmp_control != NULL ) { + if ( tmp_control->can_activate AND tmp_control->enabled ) + return tmp_control; + + control = tmp_control; /* Descend into child */ + continue; + } + + /*** At this point, control has no children ***/ + + /** see if this control has a next sibling **/ + tmp_control = (GLUI_Control*) control->next(); + + if ( tmp_control != NULL ) { + if ( tmp_control->can_activate AND tmp_control->enabled ) + return tmp_control; + + control = tmp_control; + continue; + } + + /** back up until we find a sibling of an ancestor **/ + back_up = true; + while ( control->parent() AND back_up ) { + control = (GLUI_Control*) control->parent(); + + if ( control->next() ) { + control = (GLUI_Control*) control->next(); + if ( control->can_activate AND control->enabled ) + return control; + else + back_up = false; + + /*** if ( control->is_container ) { + tmp_control = control; + control = NULL; + break; + } + else { + back_up = false; + } + ***/ + } + } + + /** Check if we've cycled back to the top... if so, return NULL **/ + if ( control == main_panel ) { + return NULL; + } + } + /* + if ( tmp_control != NULL AND tmp_control->can_activate AND + tmp_control->enabled ) { + return tmp_control; + }*/ + + return NULL; +} + + +/****************************** GLUI_Main::find_prev_control() **************/ + +GLUI_Control *GLUI_Main::find_prev_control( GLUI_Control *control ) +{ + GLUI_Control *tmp_control, *next_control; + + if ( control == NULL ) { /* here we find the last valid control */ + next_control = main_panel; + + do { + tmp_control = next_control; + next_control = find_next_control( tmp_control ); + } while( next_control != NULL ); + + return tmp_control; + } + else { /* here we find the actual previous control */ + next_control = main_panel; + + do { + tmp_control = next_control; + next_control = find_next_control( tmp_control ); + } while( next_control != NULL AND next_control != control ); + + if ( next_control == NULL OR tmp_control == main_panel ) + return NULL; + else + return tmp_control; + } +} + +/************************* GLUI_Master_Object::set_glutIdleFunc() ***********/ + +void GLUI_Master_Object::set_glutIdleFunc(void (*f)(void)) +{ + glut_idle_CB = f; + GLUI_Master.glui_setIdleFuncIfNecessary(); +} + + +/**************************************** GLUI::disable() ********************/ + +void GLUI::disable( void ) +{ + deactivate_current_control(); + main_panel->disable(); +} + + +/******************************************** GLUI::sync_live() **************/ + +void GLUI::sync_live( void ) +{ + main_panel->sync_live(true, true); +} + + +/********************************* GLUI_Master_Object::sync_live_all() *****/ + +void GLUI_Master_Object::sync_live_all( void ) +{ + GLUI *glui; + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + + glui->sync_live(); /** sync it **/ + + glui = (GLUI*) glui->next(); + } +} + + +/************************************* GLUI_Master_Object::close() **********/ + +void GLUI_Master_Object::close_all( void ) +{ + GLUI *glui; + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + + glui->close(); /** Set flag to close **/ + + glui = (GLUI*) glui->next(); + } +} + + +/************************************* GLUI_Main::close_internal() **********/ + +void GLUI_Main::close_internal( void ) +{ + glutDestroyWindow(glutGetWindow()); /** Close this window **/ + + this->unlink(); + + if ( GLUI_Master.active_control_glui == this ) { + GLUI_Master.active_control = NULL; + GLUI_Master.active_control_glui = NULL; + } + + if ( parent_window != -1 ) { + glutSetWindow( parent_window ); + int win_w = glutGet( GLUT_WINDOW_WIDTH ); + int win_h = glutGet( GLUT_WINDOW_HEIGHT ); + glutReshapeWindow(win_w+1, win_h); + glutReshapeWindow(win_w-1, win_h); + } + + delete this->main_panel; + + delete this; +} + + +/************************************************** GLUI::close() **********/ + +void GLUI::close( void ) +{ + int old_glut_window; + + closing = true; + + old_glut_window = glutGetWindow(); + glutSetWindow( get_glut_window_id() ); + glutPostRedisplay(); + + glutSetWindow( old_glut_window ); +} + + +/************************** GLUI_Main::check_subwindow_position() **********/ + +void GLUI_Main::check_subwindow_position( void ) +{ + /*** Reposition this window if subwindow ***/ + if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) { + + int parent_w, parent_h, new_x, new_y; + int old_window = glutGetWindow(); + + glutSetWindow( glut_window_id ); + + glutSetWindow( glutGet( GLUT_WINDOW_PARENT )); + parent_w = glutGet( GLUT_WINDOW_WIDTH ); + parent_h = glutGet( GLUT_WINDOW_HEIGHT ); + + glutSetWindow( glut_window_id ); + + if ( TEST_AND(this->flags,GLUI_SUBWINDOW_RIGHT )) { + new_x = parent_w - this->w; + new_y = 0; + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) { + new_x = 0; + new_y = 0; + } + else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_BOTTOM )) { + new_x = 0; + new_y = parent_h - this->h; + } + else { /*** GLUI_SUBWINDOW_TOP ***/ + new_x = 0; + new_y = 0; + } + + /** Now make adjustments based on presence of other subwindows **/ + GLUI *curr_glui; + curr_glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( curr_glui ) { + if ( TEST_AND( curr_glui->flags, GLUI_SUBWINDOW) AND + curr_glui->parent_window == this->parent_window ) { + + if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_LEFT ) ) { + } + else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_BOTTOM ) ) { + } + else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_RIGHT ) ) { + } + else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_TOP ) AND + ( TEST_AND( this->flags,GLUI_SUBWINDOW_LEFT ) OR + TEST_AND( this->flags,GLUI_SUBWINDOW_RIGHT ) ) ) { + /** If we are a RIGHT or LEFT subwindow, and there exists some + TOP subwindow, bump our position down **/ + + new_y += curr_glui->h; + } + + /** CHeck multiple subwins at same position **/ + /** We check the glui_id's: only the glui with the higher + ID number (meaning it was created later) gets bumped over **/ + if ( curr_glui != this AND this->glui_id > curr_glui->glui_id ) { + if ( TEST_AND( this->flags,GLUI_SUBWINDOW_LEFT ) AND + TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_LEFT ) ) { + new_x += curr_glui->w; + } + else if ( TEST_AND( this->flags,GLUI_SUBWINDOW_TOP ) AND + TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_TOP ) ) { + new_y += curr_glui->h; + } + else if ( TEST_AND( this->flags,GLUI_SUBWINDOW_BOTTOM ) AND + TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_BOTTOM ) ) { + new_y -= curr_glui->h; + } + else if ( TEST_AND( this->flags,GLUI_SUBWINDOW_RIGHT ) AND + TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_RIGHT ) ) { + new_x -= curr_glui->w; + } + + } + } + + curr_glui = (GLUI*) curr_glui->next(); + } + + + + CLAMP( new_x, 0, new_x ); + CLAMP( new_y, 0, new_y ); + + glutPositionWindow( new_x, new_y ); + /* glutPostRedisplay(); */ + + glutSetWindow( old_window ); + } +} + + +/********************************* GLUI_Master_Object::reshape() **********/ +/* This gets called by the user from a GLUT reshape callback. So we look */ +/* for subwindows that belong to the current window */ + +void GLUI_Master_Object::reshape( void ) +{ + GLUI *glui; + int current_window; + + current_window = glutGetWindow(); + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND + glui->parent_window == current_window ) { + glutSetWindow( glui->get_glut_window_id()); + glui->check_subwindow_position(); + } + + glui = (GLUI*) glui->next(); + } + + glutSetWindow(current_window); +} + + +/**************************** GLUI_Master_Object::set_glutReshapeFunc() *****/ + +void GLUI_Master_Object::set_glutReshapeFunc(void (*f)(int width, int height)) +{ + glutReshapeFunc( glui_reshape_func ); + add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_RESHAPE, (void*) f); +} + + +/**************************** GLUI_Master_Object::set_glutKeyboardFunc() ****/ + +void GLUI_Master_Object::set_glutKeyboardFunc(void (*f)(unsigned char key, + int x, int y)) +{ + glutKeyboardFunc( glui_keyboard_func ); + add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_KEYBOARD, (void*) f); +} + + +/*********************** GLUI_Master_Object::set_glutSpecialFunc() **********/ + +void GLUI_Master_Object::set_glutSpecialFunc(void (*f)(int key, + int x, int y)) +{ + glutSpecialFunc( glui_special_func ); + add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_SPECIAL, (void*) f); +} + + +/*********************** GLUI_Master_Object::set_glutMouseFunc() **********/ + +void GLUI_Master_Object::set_glutMouseFunc(void (*f)(int button, int state, + int x, int y)) +{ + glutMouseFunc( glui_mouse_func ); + add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_MOUSE, (void*) f); +} + + +/****************************** glui_parent_window_reshape_func() **********/ +/* This is the reshape callback for a window that contains subwindows */ + +void glui_parent_window_reshape_func( int w, int h ) +{ + int current_window; + GLUI *glui; + int first = true; + + /* printf( "glui_parent_window_reshape_func: %d\n", glutGetWindow() ); */ + + current_window = glutGetWindow(); + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND + glui->parent_window == current_window ) { + glutSetWindow( glui->get_glut_window_id()); + glui->check_subwindow_position(); + glutSetWindow( current_window ); + + if ( first ) { + if (glui->glut_reshape_CB) glui->glut_reshape_CB( w, h ); + + first = false; + } + } + + glui = (GLUI*) glui->next(); + } +} + + +/****************************** glui_parent_window_keyboard_func() **********/ + +void glui_parent_window_keyboard_func(unsigned char key, int x, int y) +{ + /* printf( "glui_parent_window_keyboard_func: %d\n", glutGetWindow() ); */ + + int current_window; + GLUI *glui; + + current_window = glutGetWindow(); + + if ( GLUI_Master.active_control_glui AND GLUI_Master.active_control ) { + glutSetWindow( GLUI_Master.active_control_glui->get_glut_window_id() ); + + GLUI_Master.active_control_glui->keyboard(key,x,y); + + glutSetWindow( current_window ); + } + else { + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND + glui->parent_window == current_window AND + glui->glut_keyboard_CB ) + { + glui->glut_keyboard_CB( key, x, y ); + break; + } + + glui = (GLUI*) glui->next(); + } + } +} + + +/****************************** glui_parent_window_special_func() **********/ + +void glui_parent_window_special_func(int key, int x, int y) +{ + /*printf( "glui_parent_window_special_func: %d\n", glutGetWindow() ); */ + + int current_window; + GLUI *glui; + + /** If clicking in the main area of a window w/subwindows, + deactivate any current control **/ + if ( GLUI_Master.active_control_glui != NULL ) + GLUI_Master.active_control_glui->deactivate_current_control(); + + /*** Now pass on the mouse event ***/ + + current_window = glutGetWindow(); + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND + glui->parent_window == current_window ) + { + glutSetWindow( glui->get_glut_window_id()); + if (glui->glut_special_CB) glui->glut_special_CB( key, x, y ); + break; + } + + glui = (GLUI*) glui->next(); + } +} + + +/****************************** glui_parent_window_mouse_func() **********/ + +void glui_parent_window_mouse_func(int button, int state, int x, int y) +{ + int current_window; + GLUI *glui; + + /** If clicking in the main area of a window w/subwindows, + deactivate any current control **/ + if ( GLUI_Master.active_control_glui != NULL ) + GLUI_Master.active_control_glui->deactivate_current_control(); + + + /*** Now pass on the mouse event ***/ + + current_window = glutGetWindow(); + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + while( glui ) { + if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND + glui->parent_window == current_window AND + glui->glut_mouse_CB) + { + glutSetWindow( glui->get_glut_window_id()); + glui->glut_mouse_CB( button, state, x, y ); + break; + } + + glui = (GLUI*) glui->next(); + } +} + + +/************************** GLUI_Master_Object::find_glut_window() **********/ + +GLUI_Glut_Window *GLUI_Master_Object::find_glut_window( int window_id ) +{ + GLUI_Glut_Window *window; + + window = (GLUI_Glut_Window*) glut_windows.first_child(); + while( window ) { + if ( window->glut_window_id == window_id ) + return window; + + window = (GLUI_Glut_Window*) window->next(); + } + + /*** Window not found - return NULL ***/ + return NULL; +} + + +/******************** GLUI_Master_Object::add_cb_to_glut_window() **********/ + +void GLUI_Master_Object::add_cb_to_glut_window(int window_id, + int cb_type,void *cb) +{ + GLUI_Glut_Window *window; + + window = find_glut_window( window_id ); + if ( NOT window ) { + /*** Allocate new window structure ***/ + + window = new GLUI_Glut_Window; + window->glut_window_id = window_id; + window->link_this_to_parent_last( (GLUI_Node*) &this->glut_windows ); + } + + switch( cb_type ) { + case GLUI_GLUT_RESHAPE: + window->glut_reshape_CB = (void(*)(int,int)) cb; + break; + case GLUI_GLUT_DISPLAY: + window->glut_display_CB = (void(*)()) cb; + break; + case GLUI_GLUT_KEYBOARD: + window->glut_keyboard_CB = (void(*)(unsigned char,int,int)) cb; + break; + case GLUI_GLUT_SPECIAL: + window->glut_special_CB = (void(*)(int,int,int)) cb; + break; + case GLUI_GLUT_MOUSE: + window->glut_mouse_CB = (void(*)(int,int,int,int)) cb; + break; + case GLUI_GLUT_MOTION: + window->glut_motion_CB = (void(*)(int,int)) cb; + break; + case GLUI_GLUT_PASSIVE_MOTION: + window->glut_passive_motion_CB = (void(*)(int,int)) cb; + break; + case GLUI_GLUT_ENTRY: + window->glut_entry_CB = (void(*)(int)) cb; + break; + case GLUI_GLUT_VISIBILITY: + window->glut_visibility_CB= (void(*)(int)) cb; + break; + } +} + + +/************* GLUI_Master_Object::set_left_button_glut_menu_control() *****/ + +void GLUI_Master_Object::set_left_button_glut_menu_control( + GLUI_Control *control ) +{ + curr_left_button_glut_menu = control; +} + + +/******************************* GLUI_Main::set_ortho_projection() **********/ + +void GLUI_Main::set_ortho_projection( void ) +{ + int win_h, win_w; + + win_w = glutGet( GLUT_WINDOW_WIDTH ); + win_h = glutGet( GLUT_WINDOW_HEIGHT ); + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + /* gluOrtho2D( 0.0, (float) win_w, 0.0, (float) win_h ); */ + glOrtho( 0.0, (float)win_w, 0.0, (float) win_h, -1000.0, 1000.0 ); + + glMatrixMode( GL_MODELVIEW ); + + return; /****-----------------------------------------------***/ + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + /*** Rotate image so y increases upwards, contrary to OpenGL axes ***/ + glTranslatef( (float) win_w/2.0, (float) win_h/2.0, 0.0 ); + glRotatef( 180.0, 0.0, 1.0, 0.0 ); + glRotatef( 180.0, 0.0, 0.0, 1.0 ); + glTranslatef( (float) -win_w/2.0, (float) -win_h/2.0, 0.0 ); +} + + +/******************************* GLUI_Main::set_viewport() **********/ + +void GLUI_Main::set_viewport( void ) +{ + glViewport( 0, 0, main_panel->w, main_panel->h ); +} + + +/****************************** GLUI_Main::refresh() ****************/ + +void GLUI_Main::refresh( void ) +{ + int orig; + + /****** GLUI_Glut_Window *glut_window; + int current_window; + current_window = glutGetWindow(); + glut_window = GLUI_Master.find_glut_window( current_window ); + if ( glut_window ) { + glut_window->glut_reshape_CB(w,h); + ******/ + + orig = glutGetWindow(); + + pack_controls(); + + if ( glut_window_id > 0 ) + glutSetWindow( glut_window_id ); + + + if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) { + /*** GLUI subwindow ***/ + + check_subwindow_position(); + } + else { + /*** Standalone GLUI window ***/ + + glutReshapeWindow( this->h, this->w ); + + } + + glutPostRedisplay(); + glutSetWindow( orig); +} + + + +/***************** GLUI_Master_Object::get_main_gfx_viewport() ***********/ + +void GLUI_Master_Object::get_viewport_area( int *x, int *y, + int *w, int *h ) +{ + GLUI *curr_glui; + int curr_x, curr_y, curr_w, curr_h; + int curr_window; + + curr_window = glutGetWindow(); + curr_x = 0; + curr_y = 0; + curr_w = glutGet( GLUT_WINDOW_WIDTH ); + curr_h = glutGet( GLUT_WINDOW_HEIGHT ); + + curr_glui = (GLUI*) gluis.first_child(); + while( curr_glui ) { + if ( TEST_AND( curr_glui->flags, GLUI_SUBWINDOW) AND + curr_glui->parent_window == curr_window ) { + + /* printf( "%s -> %d %d %d\n", curr_glui->window_name.c_str(), curr_glui->flags, + curr_glui->w, curr_glui->h );*/ + + if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_LEFT ) ) { + curr_x += curr_glui->w; + curr_w -= curr_glui->w; + } + else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_BOTTOM ) ) { + curr_y += curr_glui->h; + curr_h -= curr_glui->h; + } + else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_RIGHT ) ) { + curr_w -= curr_glui->w; + } + else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_TOP ) ) { + curr_h -= curr_glui->h; + } + } + + curr_glui = (GLUI*) curr_glui->next(); + } + + curr_x = MAX( 0, curr_x ); + curr_y = MAX( 0, curr_y ); + curr_w = MAX( 0, curr_w ); + curr_h = MAX( 0, curr_h ); + + *x = curr_x; + *y = curr_y; + *w = curr_w; + *h = curr_h; +} + + +/*****************GLUI_Master_Object::auto_set_main_gfx_viewport() **********/ + +void GLUI_Master_Object::auto_set_viewport( void ) +{ + int x, y, w, h; + + get_viewport_area( &x, &y, &w, &h ); + glViewport( MAX(x,0), MAX(y,0), MAX(w,0), MAX(h,0) ); +} + + + +/***************************************** GLUI::show() **********************/ + +void GLUI::show( void ) +{ + int orig_window; + + orig_window = main_panel->set_to_glut_window(); + + glutShowWindow(); + + main_panel->restore_window(orig_window); +} + + + +/***************************************** GLUI::hide() **********************/ + +void GLUI::hide( void ) +{ + int orig_window; + + this->deactivate_current_control(); + + orig_window = main_panel->set_to_glut_window(); + + glutHideWindow(); + + main_panel->restore_window(orig_window); +} + + +/**************** GLUI_DrawingSentinal **************/ +GLUI_DrawingSentinal::GLUI_DrawingSentinal(GLUI_Control *c_) + :c(c_) +{ + orig_win = c->set_to_glut_window(); + orig_buf = c->glui->set_current_draw_buffer(); +} +GLUI_DrawingSentinal::~GLUI_DrawingSentinal() { + c->glui->restore_draw_buffer(orig_buf); + c->restore_window(orig_win); +} + + +void GLUI_Master_Object::glui_setIdleFuncIfNecessary( void ) +{ + GLUI *glui; + + glui = (GLUI*) GLUI_Master.gluis.first_child(); + int necessary; + if (this->glut_idle_CB) + necessary = true; + else { + necessary = false; + while( glui ) { + if( glui->needs_idle() ) { + necessary = true; + break; + } + glui = (GLUI*) glui->next(); + } + } + if( necessary ) + glutIdleFunc( glui_idle_func ); + else + glutIdleFunc( NULL ); +} diff --git a/Extras/glui/glui_add_controls.cpp b/Extras/glui/glui_add_controls.cpp new file mode 100644 index 000000000..b1d52f431 --- /dev/null +++ b/Extras/glui/glui_add_controls.cpp @@ -0,0 +1,319 @@ +/**************************************************************************** + + GLUI User Interface Toolkit (LGPL) + --------------------------- + + glui_add_controls.cpp - Routines for adding controls to a GLUI window + +Note: these routines are all deprecated. Keeping them all here +prevents the linker from dragging in all the .o files, even for controls +that aren't used. + + -------------------------------------------------- + + 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 "GL/glui.h" +#include "glui_internal.h" + + +/*********************************** GLUI:: add_checkbox() ************/ + +GLUI_Checkbox *GLUI:: add_checkbox( const char *name, int *value_ptr, + int id, GLUI_CB callback ) +{ + return add_checkbox_to_panel( main_panel, + name, value_ptr, id, callback ); +} + + +/*********************************** GLUI:: add_checkbox_to_panel() **********/ + +GLUI_Checkbox *GLUI::add_checkbox_to_panel( GLUI_Panel *panel, + const char *name, int *value_ptr, + int id, + GLUI_CB callback ) +{ + return new GLUI_Checkbox( panel, name, value_ptr, id, callback ); +} + +/********************************************* GLUI::add_panel() *************/ + +GLUI_Panel *GLUI::add_panel( const char *name, int type ) +{ + return add_panel_to_panel( main_panel, name, type ); +} + + +/**************************************** GLUI::add_panel_to_panel() *********/ + +GLUI_Panel *GLUI::add_panel_to_panel( GLUI_Panel *parent_panel, + const char *name, int type ) +{ + return new GLUI_Panel( parent_panel, name, type ); +} + + +/***************************** GLUI::add_radiogroup() ***************/ + +GLUI_RadioGroup *GLUI::add_radiogroup( int *value_ptr, + int user_id, GLUI_CB callback) +{ + return add_radiogroup_to_panel( main_panel, value_ptr, + user_id, callback ); +} + + +/***************************** GLUI::add_radiogroup_to_panel() ***************/ + +GLUI_RadioGroup *GLUI::add_radiogroup_to_panel( + GLUI_Panel *panel, int *value_ptr, + int user_id, GLUI_CB callback + ) +{ + return new GLUI_RadioGroup( panel, value_ptr, user_id, callback ); +} + + +/***************************** GLUI::add_radiobutton_to_group() *************/ + +GLUI_RadioButton *GLUI::add_radiobutton_to_group( GLUI_RadioGroup *group, + const char *name ) +{ + return new GLUI_RadioButton( group, name ); +} + + +/********************************** GLUI::add_statictext() ************/ + +GLUI_StaticText *GLUI::add_statictext( const char *name ) +{ + return add_statictext_to_panel( main_panel, name ); +} + + +/******************************* GLUI::add_statictext_to_panel() **********/ + +GLUI_StaticText *GLUI::add_statictext_to_panel( GLUI_Panel *panel, + const char *name ) +{ + return new GLUI_StaticText( panel, name ); +} + + +/***************************************** GLUI:: add_button() ************/ + +GLUI_Button *GLUI:: add_button( const char *name, + int id, GLUI_CB callback ) +{ + return add_button_to_panel( main_panel, + name, id, callback ); +} + +/*********************************** GLUI:: add_button_to_panel() **********/ + +GLUI_Button *GLUI::add_button_to_panel( GLUI_Panel *panel, + const char *name, + int id, + GLUI_CB callback ) +{ + return new GLUI_Button( panel, name, id, callback ); +} + +/********************************** GLUI::add_separator() ************/ + +void GLUI::add_separator( void ) +{ + add_separator_to_panel( main_panel ); +} + + +/******************************* GLUI::add_separator_to_panel() **********/ + +void GLUI::add_separator_to_panel( GLUI_Panel *panel ) +{ + new GLUI_Separator( panel ); +} + + +/********************************** GLUI::add_edittext() ************/ + +GLUI_EditText *GLUI::add_edittext( const char *name, + int data_type, void *data, + int id, GLUI_CB callback) +{ + return add_edittext_to_panel( main_panel, name, data_type, data, + id, callback ); +} + + +/******************************* GLUI::add_edittext_to_panel() **********/ + +GLUI_EditText *GLUI::add_edittext_to_panel( GLUI_Panel *panel, + const char *name, + int data_type, void *data, + int id, GLUI_CB callback) +{ + return new GLUI_EditText( panel, name, data_type, data, id, callback ); +} + +/********************************** GLUI::add_edittext() ************/ + +GLUI_EditText *GLUI::add_edittext( const char *name, + GLUI_String & data, + int id, GLUI_CB callback) +{ + return add_edittext_to_panel( main_panel, name, data, id, callback ); +} + + +/******************************* GLUI::add_edittext_to_panel() **********/ + +GLUI_EditText* +GLUI::add_edittext_to_panel( GLUI_Panel *panel, const char *name, + GLUI_String& data, + int id, GLUI_CB callback) +{ + return new GLUI_EditText( panel, name, GLUI_EDITTEXT_STRING, &data, id, callback ); +} + +/********************************** GLUI::add_spinner() ************/ + +GLUI_Spinner *GLUI::add_spinner( const char *name, + int data_type, void *data, + int id, GLUI_CB callback) +{ + return add_spinner_to_panel( main_panel, name, data_type, data, + id, callback ); +} + + +/******************************* GLUI::add_spinner_to_panel() **********/ + +GLUI_Spinner *GLUI::add_spinner_to_panel( + GLUI_Panel *panel, const char *name, + int data_type, void *data, + int id, GLUI_CB callback +) +{ + return new GLUI_Spinner( panel, name, data_type, data, id, callback ); +} + + +/********************************** GLUI::add_column() ************/ + +void GLUI::add_column( int draw_bar ) +{ + add_column_to_panel( main_panel, draw_bar ); +} + + +/******************************* GLUI::add_column_to_panel() **********/ + +void GLUI::add_column_to_panel( GLUI_Panel *panel, int draw_bar ) +{ + new GLUI_Column( panel, draw_bar ); +} + + +/*********************************** GLUI:: add_listbox() ************/ + +GLUI_Listbox *GLUI:: add_listbox( const char *name, int *value_ptr, + int id, GLUI_CB callback ) +{ + return add_listbox_to_panel( main_panel, + name, value_ptr, id, callback ); +} + + +/*********************************** GLUI:: add_listbox_to_panel() **********/ + +GLUI_Listbox *GLUI::add_listbox_to_panel( GLUI_Panel *panel, + const char *name, int *value_ptr, + int id, + GLUI_CB callback ) +{ + return new GLUI_Listbox( panel, name, value_ptr, id, callback ); +} + + +/*********************************** GLUI:: add_rotation() ************/ + +GLUI_Rotation *GLUI:: add_rotation( const char *name, float *value_ptr, + int id, GLUI_CB callback ) +{ + return add_rotation_to_panel( main_panel, name, value_ptr, id, callback ); +} + + +/*********************************** GLUI:: add_rotation_to_panel() **********/ + +GLUI_Rotation *GLUI::add_rotation_to_panel( GLUI_Panel *panel, + const char *name, float *value_ptr, + int id, + GLUI_CB callback ) +{ + return new GLUI_Rotation( panel, name, value_ptr, id, callback ); +} + + +/*********************************** GLUI:: add_translation() ************/ + +GLUI_Translation *GLUI:: add_translation( const char *name, int trans_type, + float *value_ptr, int id, + GLUI_CB callback ) +{ + return add_translation_to_panel( main_panel,name,trans_type, + value_ptr, id, callback ); +} + + +/*********************************** GLUI:: add_translation_to_panel() **********/ + +GLUI_Translation *GLUI::add_translation_to_panel( + GLUI_Panel *panel, const char *name, + int trans_type, float *value_ptr, + int id, GLUI_CB callback + ) +{ + return new GLUI_Translation(panel, name, trans_type, value_ptr, id, callback); +} + + +/********************************** GLUI::add_rollout() **************/ + +GLUI_Rollout *GLUI::add_rollout( const char *name, int open, int type) +{ + return add_rollout_to_panel( main_panel, name, open, type); +} + + +/****************************** GLUI::add_rollout_to_panel() *********/ + +GLUI_Rollout *GLUI::add_rollout_to_panel(GLUI_Panel *panel, const char *name, + int open, int type) +{ + return new GLUI_Rollout( panel, name, open, type ); +} + + + diff --git a/Extras/glui/glui_bitmap_img_data.cpp b/Extras/glui/glui_bitmap_img_data.cpp new file mode 100644 index 000000000..6ec7e6df4 --- /dev/null +++ b/Extras/glui/glui_bitmap_img_data.cpp @@ -0,0 +1,138 @@ +/** + Bitmaps for all GLUI images. + + These were converted from original PPM images + (mostly lost) with the tools/ppm2array program. + + The images here are extracted in typical OpenGL + bottom-to-top fashion. + + FIXME: don't use greyscale brightness here--this prevents + people changing the background color. Instead, use a code + indicating the underlying purpose of the pixel: + 0 = shadows; outlines; UI elements (check boxes, arrows) + 64 = disabled shadows and UI elements + 128 = shadowing, disabled + 192 = disabled white; background + 255 = highlights; checkbox/radio background + + I'm thinking the way to do this would be to have an +enum { + BG = 0, // Background shines through-- totally alpha transparent + BS, // Background of scrollbar/spin box-- opaque gray + SB, // Shadowed-black element-- strong alpha blend to black + SD, // Shadowed-dark element-- weak alpha blend to black + HL, // Highlight-light-- weak alpha blend to white + HW, // Highlight-white-- strong alpha blend to white + UB, // User-interface black-- arrows, checkboxes, radio buttons + UW, // User-interface white-- backgrounds of checkboxes and radio buttons +}; + + Orion Sky Lawlor, olawlor@acm.org, 2006/05/04 (LGPL) +*/ + +/*----------------------- checkboxes --------------------------*/ +unsigned char glui_img_checkbox_0[] = { 13, 13, /* width, height */ +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 255, +}; + + +unsigned char glui_img_checkbox_0_dis[] = { 13, 13, /* width, height */ +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 255, +}; + + +unsigned char glui_img_checkbox_1[] = { 13, 13, /* width, height */ +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 0, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 0, 0, 0, 255, 255, 255, 255, 192, 255, 128, 0, 255, 0, 0, 0, 0, 0, 255, 255, 255, 192, 255, 128, 0, 255, 0, 0, 255, 0, 0, 0, 255, 255, 192, 255, 128, 0, 255, 0, 255, 255, 255, 0, 0, 0, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 0, 0, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 255, +}; + + +unsigned char glui_img_checkbox_1_dis[] = { 13, 13, /* width, height */ +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 64, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 64, 64, 64, 192, 192, 192, 192, 192, 255, 128, 64, 192, 64, 64, 64, 64, 64, 192, 192, 192, 192, 255, 128, 64, 192, 64, 64, 192, 64, 64, 64, 192, 192, 192, 255, 128, 64, 192, 64, 192, 192, 192, 64, 64, 64, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 64, 64, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 64, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 255, +}; + + +/*------------------------------- arrows -------------------------------------*/ +unsigned char glui_img_downarrow[] = { 16, 16, /* width, height */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 0, 0, 0, 0, 0, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 0, 0, 0, 0, 0, 0, 0, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, +}; + + +unsigned char glui_img_leftarrow[] = { 16, 16, /* width, height */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 0, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, +}; + +unsigned char glui_img_rightarrow[] = { 16, 16, /* width, height */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 0, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, +}; + +unsigned char glui_img_uparrow[] = { 16, 16, /* width, height */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 0, 0, 0, 0, 0, 0, 0, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 0, 0, 0, 0, 0, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, +}; + +/*------------------ listboxes ---------------------*/ +unsigned char glui_img_listbox_down[] = { 11, 17, /* width, height */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 127, 191, 191, 191, 127, 0, 127, 191, 191, 191, 127, 127, 127, 191, 191, 127, 0, 127, 191, 191, 127, 127, 127, 127, 127, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, +}; + + +unsigned char glui_img_listbox_up[] = { 11, 17, /* width, height */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 0, 191, 191, 191, 127, 0, 191, 255, 191, 191, 0, 0, 0, 191, 191, 127, 0, 191, 255, 191, 0, 0, 0, 0, 0, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 255, 255, 255, 255, 255, 255, 255, 127, 0, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 0, +}; + +unsigned char glui_img_listbox_up_dis[] = { 11, 17, /* width, height */ +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 191, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 254, 191, 191, 191, 127, 127, 191, 255, 191, 191, 127, 127, 254, 191, 191, 127, 127, 191, 255, 191, 127, 127, 127, 127, 254, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 255, 255, 255, 255, 255, 255, 255, 127, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, +}; + +/*--------------------------- radio buttons -------------------------*/ +unsigned char glui_img_radiobutton_0[] = { 14, 14, /* width, height */ +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 255, 255, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 192, 128, 192, 192, 255, 255, 255, 255, 192, 192, 255, 192, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 192, 128, 0, 0, 255, 255, 255, 255, 0, 0, 255, 192, 192, 192, 192, 192, 128, 128, 0, 0, 0, 0, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +}; + + +unsigned char glui_img_radiobutton_0_dis[] = { 14, 14, /* width, height */ +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 255, 255, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 192, 128, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 192, 128, 64, 64, 192, 192, 192, 192, 64, 64, 255, 192, 192, 192, 192, 192, 128, 128, 64, 64, 64, 64, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +}; + + +unsigned char glui_img_radiobutton_1[] = { 14, 14, /* width, height */ +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 255, 255, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 192, 128, 192, 192, 255, 255, 255, 255, 192, 192, 255, 192, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 128, 0, 255, 255, 255, 0, 0, 255, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 0, 0, 0, 0, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 0, 0, 0, 0, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 255, 0, 0, 255, 255, 255, 192, 255, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 192, 128, 0, 0, 255, 255, 255, 255, 0, 0, 255, 192, 192, 192, 192, 192, 128, 128, 0, 0, 0, 0, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +}; + + +unsigned char glui_img_radiobutton_1_dis[] = { 14, 14, /* width, height */ +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 255, 255, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 192, 128, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 128, 64, 192, 192, 192, 64, 64, 192, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 64, 64, 64, 64, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 64, 64, 64, 64, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 192, 64, 64, 192, 192, 192, 192, 255, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 192, 128, 64, 64, 192, 192, 192, 192, 64, 64, 255, 192, 192, 192, 192, 192, 128, 128, 64, 64, 64, 64, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +}; + + + +/*----------------- spinners ----------------------------*/ +unsigned char glui_img_spindown_0[] = { 12, 8, /* width, height */ +255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 255, 191, 191, 191, 191, 0, 127, 191, 191, 191, 127, 0, 255, 191, 191, 191, 0, 0, 0, 127, 191, 191, 127, 0, 255, 191, 191, 0, 0, 0, 0, 0, 127, 191, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, +}; + + +unsigned char glui_img_spindown_1[] = { 12, 8, /* width, height */ +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 191, 191, 191, 127, 0, 191, 191, 191, 191, 255, 0, 127, 191, 191, 127, 0, 0, 0, 191, 191, 191, 255, 0, 127, 191, 127, 0, 0, 0, 0, 0, 191, 191, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 191, 255, +}; + + +unsigned char glui_img_spindown_dis[] = { 12, 8, /* width, height */ +255, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 255, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 64, 255, 191, 191, 191, 191, 127, 255, 191, 191, 191, 127, 64, 255, 191, 191, 191, 127, 127, 127, 255, 191, 191, 127, 64, 255, 191, 191, 127, 127, 127, 127, 127, 255, 191, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, +}; + + +unsigned char glui_img_spinup_0[] = { 12, 8, /* width, height */ +255, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 255, 191, 191, 0, 0, 0, 0, 0, 127, 191, 127, 0, 255, 191, 191, 191, 0, 0, 0, 127, 191, 191, 127, 0, 255, 191, 191, 191, 191, 0, 127, 191, 191, 191, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +}; + + +unsigned char glui_img_spinup_1[] = { 12, 8, /* width, height */ + 0, 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 191, 127, 0, 0, 0, 0, 0, 191, 191, 255, 0, 127, 191, 191, 127, 0, 0, 0, 191, 191, 191, 255, 0, 127, 191, 191, 191, 127, 0, 191, 191, 191, 191, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 191, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, +}; + + +unsigned char glui_img_spinup_dis[] = { 12, 8, /* width, height */ +255, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 64, 255, 191, 191, 127, 127, 127, 127, 127, 255, 191, 127, 64, 255, 191, 191, 191, 127, 127, 127, 255, 191, 191, 127, 64, 255, 191, 191, 191, 191, 127, 255, 191, 191, 191, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +}; + diff --git a/Extras/glui/glui_bitmaps.cpp b/Extras/glui/glui_bitmaps.cpp new file mode 100644 index 000000000..8bebf5d8f --- /dev/null +++ b/Extras/glui/glui_bitmaps.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_bitmaps.cpp + +Draws the hardcoded images listed in glui_bitmap_img_data with OpenGL. + +FIXME: upload the images to a texture. This will allow them to be: + - Drawn with alpha blending + - Drawn at random sizes and angles onscreen + - Drawn much faster than with glDrawPixels + + -------------------------------------------------- + + 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 "GL/glui.h" +#include "glui_internal.h" +#include + +/************ Image Bitmap arrays **********/ + +extern unsigned char glui_img_checkbox_0[]; +extern unsigned char glui_img_checkbox_1[]; +extern unsigned char glui_img_radiobutton_0[]; +extern unsigned char glui_img_radiobutton_1[]; +extern unsigned char glui_img_uparrow[]; +extern unsigned char glui_img_downarrow[]; +extern unsigned char glui_img_leftarrow[]; +extern unsigned char glui_img_rightarrow[]; +extern unsigned char glui_img_spinup_0[]; +extern unsigned char glui_img_spinup_1[]; +extern unsigned char glui_img_spindown_0[]; +extern unsigned char glui_img_spindown_1[]; +extern unsigned char glui_img_checkbox_0_dis[]; +extern unsigned char glui_img_checkbox_1_dis[]; +extern unsigned char glui_img_radiobutton_0_dis[]; +extern unsigned char glui_img_radiobutton_1_dis[]; +extern unsigned char glui_img_spinup_dis[]; +extern unsigned char glui_img_spindown_dis[]; +extern unsigned char glui_img_listbox_up[]; +extern unsigned char glui_img_listbox_down[]; +extern unsigned char glui_img_listbox_up_dis[]; + + +// These must be in the same order as the GLUI_STDBITMAP enums from glui.h! +unsigned char *bitmap_arrays[] = { + glui_img_checkbox_0, + glui_img_checkbox_1, + glui_img_radiobutton_0, + glui_img_radiobutton_1, + glui_img_uparrow, + glui_img_downarrow, + glui_img_leftarrow, + glui_img_rightarrow, + glui_img_spinup_0, + glui_img_spinup_1, + glui_img_spindown_0, + glui_img_spindown_1, + glui_img_checkbox_0_dis, + glui_img_checkbox_1_dis, + glui_img_radiobutton_0_dis, + glui_img_radiobutton_1_dis, + glui_img_spinup_dis, + glui_img_spindown_dis, + glui_img_listbox_up, + glui_img_listbox_down, + glui_img_listbox_up_dis, +}; + + +/************************************ GLUI_Bitmap::load_from_array() ********/ + +GLUI_Bitmap::GLUI_Bitmap() +: pixels(NULL), + w(0), + h(0) +{ +} + +GLUI_Bitmap::~GLUI_Bitmap() +{ + if (pixels) + { + free(pixels); + pixels = NULL; + } +} + +/* Create bitmap from greyscale byte array */ +void GLUI_Bitmap::init_grey(unsigned char *array) +{ + w = array[0]; h = array[1]; + pixels = (unsigned char *) malloc(w*h*3); + assert(pixels); + + for(int i = 0; i=0 && i=0 && i=0 && iadd_control( this ); +} + + +/****************************** GLUI_Button::mouse_down_handler() **********/ + +int GLUI_Button::mouse_down_handler( int local_x, int local_y ) +{ + int_val = 1; /** A button always in unpressed before here, so + now we invariably set it to 'depressed' **/ + + currently_inside = true; + redraw(); + + return false; +} + + +/****************************** GLUI_Button::mouse_up_handler() **********/ + +int GLUI_Button::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + set_int_val( 0 ); /** A button always turns off after you press it **/ + + currently_inside = false; + redraw(); + + if ( inside ) { + /*** Invoke the user's callback ***/ + execute_callback(); + } + + return false; +} + + +/****************************** GLUI_Button::mouse_held_down_handler() ******/ + +int GLUI_Button::mouse_held_down_handler( int local_x, int local_y, + bool new_inside) +{ + if (new_inside != currently_inside) { + currently_inside = new_inside; + redraw(); + } + + return false; +} + + +/****************************** GLUI_Button::key_handler() **********/ + +int GLUI_Button::key_handler( unsigned char key,int modifiers ) +{ + return false; +} + +/********************************************** GLUI_Button::draw() **********/ + +void GLUI_Button::draw( int x, int y ) +{ + if (currently_inside) draw_pressed(); + else { + glui->draw_raised_box( 0, 0, w, h ); + draw_text( 0 ); + } +} + + +/************************************** GLUI_Button::draw_pressed() ******/ + +void GLUI_Button::draw_pressed( void ) +{ + glColor3f( 0.0, 0.0, 0.0 ); + + draw_text( 1 ); + + glBegin( GL_LINE_LOOP ); + glVertex2i( 0, 0 ); glVertex2i( w, 0 ); + glVertex2i( w, h ); glVertex2i( 0, h ); + glEnd(); + + glBegin( GL_LINE_LOOP ); + glVertex2i( 1, 1 ); glVertex2i( w-1, 1 ); + glVertex2i( w-1, h-1 ); glVertex2i( 1, h-1 ); + glEnd(); +} + + +/**************************************** GLUI_Button::draw_text() **********/ + +void GLUI_Button::draw_text( int sunken ) +{ + int string_width; + + glColor3ub( glui->bkgd_color.r, glui->bkgd_color.g, glui->bkgd_color.b ); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( 2, 2 ); glVertex2i( w-2, 2 ); + glVertex2i( w-2, h-2 ); glVertex2i( 2, h-2 ); + glEnd(); + + glColor3ub( 0,0,0 ); + + string_width = _glutBitmapWidthString( glui->font, + this->name.c_str() ); + if ( NOT sunken ) { + draw_name( MAX((w-string_width),0)/2, 13); + } + else { + draw_name( MAX((w-string_width),0)/2 + 1, 13 + 1); + } + + if ( active ) { + glEnable( GL_LINE_STIPPLE ); + glLineStipple( 1, 0x5555 ); + + glColor3f( 0., 0., 0. ); + + glBegin( GL_LINE_LOOP ); + glVertex2i( 3, 3 ); glVertex2i( w-3, 3 ); + glVertex2i( w-3, h-3 ); glVertex2i( 3, h-3 ); + glEnd(); + + glDisable( GL_LINE_STIPPLE ); + } +} + + +/************************************** GLUI_Button::update_size() **********/ + +void GLUI_Button::update_size( void ) +{ + int text_size; + + if ( NOT glui ) + return; + + text_size = string_width( name ); + + if ( w < text_size + 16 ) + w = text_size + 16 ; +} diff --git a/Extras/glui/glui_checkbox.cpp b/Extras/glui/glui_checkbox.cpp new file mode 100644 index 000000000..3bf3984d3 --- /dev/null +++ b/Extras/glui/glui_checkbox.cpp @@ -0,0 +1,188 @@ + +/**************************************************************************** + + GLUI User Interface Toolkit (LGPL) + --------------------------- + + glui_checkbox - GLUI_Checkbox 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_Checkbox::GLUI_Checkbox() **********/ + +GLUI_Checkbox::GLUI_Checkbox( GLUI_Node *parent, + const char *name, int *value_ptr, + int id, + GLUI_CB cb ) +{ + common_init(); + + set_ptr_val( value_ptr ); + set_name( name ); + user_id = id; + callback = cb; + + parent->add_control( this ); + + init_live(); +} + +/****************************** GLUI_Checkbox::mouse_down_handler() **********/ + +int GLUI_Checkbox::mouse_down_handler( int local_x, int local_y ) +{ + orig_value = int_val; + int_val = !int_val; + + currently_inside = true; + redraw(); + + return false; +} + + +/****************************** GLUI_Checkbox::mouse_up_handler() **********/ + +int GLUI_Checkbox::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + if ( NOT inside ) { /* undo effect on value */ + int_val = orig_value; + } + else { + set_int_val( int_val ); + + /*** Invoke the callback ***/ + execute_callback(); + } + + return false; +} + + +/****************************** GLUI_Checkbox::mouse_held_down_handler() ******/ + +int GLUI_Checkbox::mouse_held_down_handler( int local_x, int local_y, + bool inside) +{ + /********** Toggle checked and unchecked bitmap if we're entering or + leaving the checkbox area **********/ + if ( inside != currently_inside ) { + int_val = !int_val; + currently_inside = inside; + redraw(); + } + + return false; +} + + +/****************************** GLUI_Checkbox::key_handler() **********/ + +int GLUI_Checkbox::key_handler( unsigned char key,int modifiers ) +{ + return false; +} + + +/****************************** GLUI_Checkbox::draw() **********/ + +void GLUI_Checkbox::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + if ( int_val != 0 ) { + if ( enabled ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_CHECKBOX_ON, 0, 0 ); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_CHECKBOX_ON_DIS, 0, 0 ); + } + else { + if ( enabled ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_CHECKBOX_OFF, 0, 0 ); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_CHECKBOX_OFF_DIS, 0, 0 ); + } + + draw_active_area(); + + draw_name( text_x_offset, 10); +} + +/**************************** GLUI_Checkbox::draw_active_area() **************/ + +void GLUI_Checkbox::draw_active_area( void ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int text_width, left, right; + + text_width = _glutBitmapWidthString( glui->font, name.c_str() ); + left = text_x_offset-3; + right = left + 7 + text_width; + + if ( active ) { + glEnable( GL_LINE_STIPPLE ); + glLineStipple( 1, 0x5555 ); + glColor3f( 0., 0., 0. ); + } else { + glColor3ub( glui->bkgd_color.r, glui->bkgd_color.g, glui->bkgd_color.b ); + } + + glBegin( GL_LINE_LOOP ); + glVertex2i(left,0); glVertex2i( right,0); + glVertex2i(right,h+1); glVertex2i( left,h+1); + glEnd(); + + glDisable( GL_LINE_STIPPLE ); +} + + +/************************************ GLUI_Checkbox::update_size() **********/ + +void GLUI_Checkbox::update_size( void ) +{ + int text_size; + + if ( NOT glui ) + return; + + text_size = _glutBitmapWidthString( glui->font, name.c_str() ); + + /* if ( w < text_x_offset + text_size + 6 ) */ + w = text_x_offset + text_size + 6 ; +} + + +/********************************* GLUI_Checkbox::set_int_val() **************/ + +void GLUI_Checkbox::set_int_val( int new_val ) +{ + int_val = new_val; + + /*** Update the variable we're (possibly) pointing to ***/ + output_live(true); + redraw(); +} diff --git a/Extras/glui/glui_column.cpp b/Extras/glui/glui_column.cpp new file mode 100644 index 000000000..172d3c1e6 --- /dev/null +++ b/Extras/glui/glui_column.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** + GLUI User Interface Toolkit + --------------------------- + + glui_column.cpp - GLUI_Column 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_Column::GLUI_Column() ************/ + +GLUI_Column::GLUI_Column( GLUI_Node *parent, int draw_bar ) +{ + common_init(); + int_val = draw_bar; /* Whether to draw vertical bar or not */ + + parent->add_control( this ); +} + +/**************************************** GLUI_Column::draw() ************/ + +void GLUI_Column::draw( int x, int y ) +{ + int panel_x, panel_y, panel_w, panel_h, panel_x_off, panel_y_off; + int y_diff; + + if ( int_val == 1 ) { /* Draw a vertical bar */ + GLUI_DRAWINGSENTINAL_IDIOM + if ( parent() != NULL ) { + get_this_column_dims(&panel_x, &panel_y, &panel_w, &panel_h, + &panel_x_off, &panel_y_off); + + y_diff = y_abs - panel_y; + + if ( 0 ) { + glLineWidth(1.0); + glBegin( GL_LINES ); + glColor3f( .5, .5, .5 ); + glVertex2i( -GLUI_XOFF+1, -y_diff + GLUI_SEPARATOR_HEIGHT/2 ); + glVertex2i( -GLUI_XOFF+1, -y_diff + panel_h - GLUI_SEPARATOR_HEIGHT/2); + + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i( -GLUI_XOFF+2, -y_diff + GLUI_SEPARATOR_HEIGHT/2 ); + glVertex2i( -GLUI_XOFF+2, -y_diff + panel_h - GLUI_SEPARATOR_HEIGHT/2); + glEnd(); + } + else { + glLineWidth(1.0); + glBegin( GL_LINES ); + glColor3f( .5, .5, .5 ); + glVertex2i( -2, 0 ); + glVertex2i( -2, h ); + /*glVertex2i( 0, -y_diff + GLUI_SEPARATOR_HEIGHT/2 ); */ + /*glVertex2i( 0, -y_diff + panel_h - GLUI_SEPARATOR_HEIGHT/2); */ + + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i( -1, 0 ); + glVertex2i( -1, h ); + /*glVertex2i( 1, -y_diff + GLUI_SEPARATOR_HEIGHT/2 ); */ + /*glVertex2i( 1, -y_diff + panel_h - GLUI_SEPARATOR_HEIGHT/2); */ + glEnd(); + } + } + } +} + diff --git a/Extras/glui/glui_commandline.cpp b/Extras/glui/glui_commandline.cpp new file mode 100644 index 000000000..9f823d99f --- /dev/null +++ b/Extras/glui/glui_commandline.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_commandline.cpp - GLUI_CommandLine control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher, 2005 William Baxter + + 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 + + This program is -not- in the public domain. + +*****************************************************************************/ + +#include "GL/glui.h" +#include "glui_internal.h" + +/****************************** GLUI_CommandLine::GLUI_CommandLine() **********/ +GLUI_CommandLine::GLUI_CommandLine( GLUI_Node *parent, const char *name, + void *data, int id, GLUI_CB cb ) +{ + common_init(); + set_name( name ); + + data_type = GLUI_EDITTEXT_TEXT; + ptr_val = data; + user_id = id; + callback = cb; + + live_type = GLUI_LIVE_TEXT; + + parent->add_control( this ); + + init_live(); +} + +/****************************** GLUI_CommandLine::key_handler() **********/ + +int GLUI_CommandLine::key_handler( unsigned char key,int modifiers ) +{ + int ret; + + if ( NOT glui ) + return false; + + if ( debug ) + dump( stdout, "-> CMD_TEXT KEY HANDLER" ); + + if ( key == 13 ) { /* RETURN */ + commit_flag = true; + } + + ret = Super::key_handler( key, modifiers ); + + if ( debug ) + dump( stdout, "<- CMD_TEXT KEY HANDLER" ); + + return ret; +} + + +/****************************** GLUI_CommandLine::deactivate() **********/ + +void GLUI_CommandLine::deactivate( void ) +{ + // if the commit_flag is set, add the current command to + // history and call deactivate as normal + + // Trick deactivate into calling callback if and only if commit_flag set. + // A bit subtle, but deactivate checks that orig_text and text + // are the same to decide whether or not to call the callback. + // Force them to be different for commit, and the same for no commit. + if (commit_flag) { + add_to_history(text.c_str()); + orig_text = ""; + Super::deactivate( ); + set_text( "" ); + commit_flag = false; + } + else { + orig_text = text; + } +} + +/**************************** GLUI_CommandLine::special_handler() **********/ + +int GLUI_CommandLine::special_handler( int key,int modifiers ) +{ + if ( NOT glui ) + return false; + + if ( debug ) + printf( "CMD_TEXT SPECIAL:%d - mod:%d subs:%d/%d ins:%d sel:%d/%d\n", + key, modifiers, substring_start, substring_end,insertion_pt, + sel_start, sel_end ); + + if ( key == GLUT_KEY_UP ) // PREVIOUS HISTORY + { + scroll_history(-1); + } + else if ( key == GLUT_KEY_DOWN ) // NEXT HISTORY + { + scroll_history(+1); + } + else { + return Super::special_handler( key, modifiers ); + } + return false; +} + + + +/**************************** GLUI_CommandLine::scroll_history() ********/ + +void GLUI_CommandLine::scroll_history( int direction ) +{ + recall_history(curr_hist + direction); +} + +/**************************** GLUI_CommandLine::recall_history() ********/ + +void GLUI_CommandLine::recall_history( int hist_num ) +{ + if (hist_num < oldest_hist OR + hist_num > newest_hist OR + hist_num == curr_hist) + return; + + // Commit the current text first before we blow it away! + if (curr_hist == newest_hist) { + get_history_str(newest_hist) = text; + } + + curr_hist = hist_num; + set_text(get_history_str(curr_hist)); + sel_end = sel_start = insertion_pt = (int)text.length(); + update_and_draw_text(); +} + +/**************************** GLUI_CommandLine::add_to_history() ********/ + +void GLUI_CommandLine::add_to_history( const char *cmd ) +{ + if (cmd[0]=='\0') return; // don't add if it's empty + + curr_hist = newest_hist; + get_history_str(newest_hist) = text; + + newest_hist = ++curr_hist; + if ( newest_hist >= HIST_SIZE ) + { + // bump oldest off the list + hist_list.erase(hist_list.begin()); + hist_list.push_back(""); + + oldest_hist++; + } +} + +/**************************** GLUI_CommandLine::reset_history() ********/ + +void GLUI_CommandLine::reset_history( void ) +{ + oldest_hist = newest_hist = curr_hist = 0; +} + + + +/*************************************** GLUI_CommandLine::dump() **************/ + +void GLUI_CommandLine::dump( FILE *out, const char *name ) +{ + fprintf( out, + "%s (commandline@%p): ins_pt:%d subs:%d/%d sel:%d/%d len:%d\n", + name, this, + insertion_pt, substring_start, substring_end, sel_start, sel_end, + (int)text.length()); +} + + diff --git a/Extras/glui/glui_control.cpp b/Extras/glui/glui_control.cpp new file mode 100644 index 000000000..056916f3b --- /dev/null +++ b/Extras/glui/glui_control.cpp @@ -0,0 +1,1203 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_control.cpp - top-level GLUI_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" + +int _glui_draw_border_only = 0; + +/*************************** Drawing Utility routines *********************/ + +/* Redraw this control. */ +void GLUI_Control::redraw(void) { + if (glui==NULL || hidden) return; + if (glui->should_redraw_now(this)) + translate_and_draw_front(); +} + +/** Redraw everybody in our window. */ +void GLUI_Control::redraw_window(void) { + if (glui==NULL || hidden) return; + if ( glui->get_glut_window_id() == -1 ) return; + int orig = set_to_glut_window(); + glutPostRedisplay(); + restore_window(orig); +} + + + +/* GLUI_Control::translate_and_draw_front() ********/ + +void GLUI_Control::translate_and_draw_front() +{ + GLUI_DRAWINGSENTINAL_IDIOM + + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + translate_to_origin(); + draw(0,0); + glPopMatrix(); +} + + +/********** GLUI_Control::set_to_bkgd_color() ********/ + +void GLUI_Control::set_to_bkgd_color( void ) +{ + if ( NOT glui ) + return; + + glColor3ub( glui->bkgd_color.r, glui->bkgd_color.g, glui->bkgd_color.b ); +} + +/******** GLUI_Control::draw_box_inwards_outline() ********/ + +void GLUI_Control::draw_box_inwards_outline( int x_min, int x_max, int y_min, int y_max ) +{ + glBegin( GL_LINES ); + glColor3f( .5, .5, .5 ); + glVertex2i( x_min, y_min ); glVertex2i( x_max, y_min ); + glVertex2i( x_min, y_min ); glVertex2i( x_min, y_max ); + + glColor3f( 1., 1., 1. ); + glVertex2i( x_min, y_max ); glVertex2i( x_max, y_max ); + glVertex2i( x_max, y_max ); glVertex2i( x_max, y_min ); + + if ( enabled ) + glColor3f( 0., 0., 0. ); + else + glColor3f( .25, .25, .25 ); + + glVertex2i( x_min+1, y_min+1 ); glVertex2i( x_max-1, y_min+1 ); + glVertex2i( x_min+1, y_min+1 ); glVertex2i( x_min+1, y_max-1 ); + + glColor3f( .75, .75, .75 ); + glVertex2i( x_min+1, y_max-1 ); glVertex2i( x_max-1, y_max-1 ); + glVertex2i( x_max-1, y_max-1 ); glVertex2i( x_max-1, y_min+1 ); + glEnd(); +} + + +/******* GLUI_Control::draw_box() **********/ + +void GLUI_Control::draw_box( int x_min, int x_max, int y_min, int y_max, float r, float g, float b) +{ + if ( r == 1.0 AND g == 1.0 AND b == 1.0 AND NOT enabled AND glui ) { + draw_bkgd_box( x_min, x_max, y_min, y_max ); + return; + } + + glColor3f( r, g, b ); + glBegin( GL_QUADS ); + glVertex2i( x_min, y_min ); glVertex2i( x_max, y_min ); + glVertex2i( x_max, y_max ); glVertex2i( x_min, y_max ); + glEnd(); +} + + +/******* GLUI_Control::draw_bkgd_box() **********/ + +void GLUI_Control::draw_bkgd_box( int x_min, int x_max, int y_min, int y_max ) +{ + set_to_bkgd_color(); + + glBegin( GL_QUADS ); + glVertex2i( x_min, y_min ); glVertex2i( x_max, y_min ); + glVertex2i( x_max, y_max ); glVertex2i( x_min, y_max ); + glEnd(); +} + + +/**** GLUI_Control::draw_active_area() ********/ + +void GLUI_Control::draw_active_box( int x_min, int x_max, int y_min, int y_max ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + if ( active ) { + glEnable( GL_LINE_STIPPLE ); + glLineStipple( 1, 0x5555 ); + glColor3f( 0., 0., 0. ); + } else { + set_to_bkgd_color(); + } + + glBegin( GL_LINE_LOOP ); + glVertex2i(x_min, y_min); glVertex2i( x_max, y_min ); + glVertex2i(x_max, y_max); glVertex2i( x_min, y_max ); + glEnd(); + + glDisable( GL_LINE_STIPPLE ); +} + + +/**** GLUI_Control::draw_emboss_box() ********/ + +void GLUI_Control::draw_emboss_box(int x_min,int x_max,int y_min,int y_max) +{ + glLineWidth( 1.0 ); + glColor3f( 1.0, 1.0, 1.0 ); + + glBegin( GL_LINE_LOOP ); + glVertex2i( x_min, y_min ); glVertex2i( x_max, y_min ); + glVertex2i( x_max, y_max ); glVertex2i( x_min, y_max ); + glEnd(); + + glBegin( GL_LINE_LOOP ); + glVertex2i( x_min+1, y_min+1 ); glVertex2i( x_max-1, y_min+1 ); + glVertex2i( x_max-1, y_max-1 ); glVertex2i( x_min+1, y_max-1 ); + glEnd(); + + glColor3f( .5, .5, .5 ); + glBegin( GL_LINE_LOOP ); + glVertex2i( x_min, y_min ); + glVertex2i( x_max-1, y_min ); + glVertex2i( x_max-1, y_max-1 ); + glVertex2i( x_min, y_max-1 ); + glEnd(); +} + + + +/******* GLUT_Control::draw_recursive() **********/ + +void GLUI_Control::draw_recursive( int x, int y ) +{ + GLUI_Control *node; + + /* printf( "%s %d\n", this->name.c_str(), this->hidden );*/ + if ( NOT can_draw() ) + return; + + /*if ( 1 ) { -- Debugging to check control width + glColor3f( 1.0, 0.0, 0.0 ); + glBegin( GL_LINES ); + glVertex2i( x_abs, y_abs );00 + glVertex2i( x_abs+w, y_abs ); + + glEnd(); + }*/ + + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + + glTranslatef( (float) this->x_abs + .5, + (float) this->y_abs + .5, + 0.0 ); + + if ( NOT _glui_draw_border_only ) { + if ( NOT strcmp( name.c_str(), "Rollout" ) ) { + } + + this->draw( this->x_off, this->y_off_top ); + } + else + { + if ( dynamic_cast(this) ) { + /* printf( "%s w/h: %d/%d\n", (char*) name, w, h ); */ + /*w = 2; */ + } + + /* The following draws the area of each control */ + glColor3f( 1.0, 0.0, 0.0 ); + glBegin( GL_LINE_LOOP ); + glVertex2i( 0, 0 ); glVertex2i( w, 0 ); + glVertex2i( w, h ); glVertex2i( 0, h ); + glEnd(); + } + glPopMatrix(); + + node = (GLUI_Control*) first_child(); + while( node ) { + node->draw_recursive( node->x_abs, node->y_abs ); + node = (GLUI_Control*) node->next(); + } +} + + +/****** GLUI_Control::set_to_glut_window() *********/ +/* Sets the current window to the glut window associated with this control */ + +int GLUI_Control::set_to_glut_window() +{ + int orig_window; + + if ( NOT glui) + return 1; + + orig_window = glutGetWindow(); + + glutSetWindow( glui->get_glut_window_id()); + + return orig_window; +} + + +/********** GLUI_Control::restore_window() *********/ + +void GLUI_Control::restore_window(int orig) +{ + if ( orig > 0 ) + glutSetWindow( orig ); +} + + + +/****************************** Text ***************************/ + +/*************** GLUI_Control::set_font() **********/ + +void GLUI_Control::set_font(void *new_font) +{ + font = new_font; + redraw(); +} + + +/********** GLUI_Control::draw_string() ************/ + +void GLUI_Control::draw_string( const char *text ) +{ + _glutBitmapString( get_font(), text ); +} + + +/**************** GLUI_Control::draw_char() ********/ + +void GLUI_Control::draw_char(char c) +{ + glutBitmapCharacter( get_font(), c ); +} + + +/*********** GLUI_Control::string_width() **********/ + +int GLUI_Control::string_width(const char *text) +{ + return _glutBitmapWidthString( get_font(), text ); +} + + +/************* GLUI_Control::char_width() **********/ + +int GLUI_Control::char_width(char c) +{ /* Hash table for faster character width lookups - JVK + Speeds up the textbox a little bit. + */ + int hash_index = c % CHAR_WIDTH_HASH_SIZE; + if (char_widths[hash_index][0] != c) { + char_widths[hash_index][0] = c; + char_widths[hash_index][1] = glutBitmapWidth( get_font(), c ); + } + return char_widths[hash_index][1]; +} + + +/*************** GLUI_Control::get_font() **********/ + +void *GLUI_Control::get_font( void ) +{ + /*** Does this control have its own font? ***/ + if ( this->font != NULL ) + return this->font; + + /*** Does the parent glui have a font? ***/ + if ( glui ) + return glui->font; + + /*** Return the default font ***/ + return GLUT_BITMAP_HELVETICA_12; +} + + +/************* GLUI_Control::draw_name() ***********/ +/* This draws the name of the control as either black (if enabled), or */ +/* embossed if disabled. */ + +void GLUI_Control::draw_name(int x, int y) +{ + if ( NOT can_draw() ) + return; + + if ( enabled ) + { + set_to_bkgd_color(); + glRasterPos2i(x+1, y+1); + draw_string(name); + glColor3b( 0, 0, 0 ); + glRasterPos2i(x, y); + draw_string(name); + } + else + { /* Control is disabled - emboss the string */ + glColor3f( 1.0f, 1.0f, 1.0f ); + glRasterPos2i(x+1, y+1); + draw_string(name); + glColor3f( .4f, .4f, .4f ); + glRasterPos2i(x, y); + draw_string(name); + } +} + + +/**************************** Layout and Packing *********************/ + +/****** GLUI_Control::align() **************/ + +void GLUI_Control::align() +{ + int col_x, col_y, col_w, col_h, col_x_off, col_y_off; + int orig_x_abs; + + orig_x_abs = x_abs; + + /* Fix alignment bug relating to columns */ + /*return; */ + + if ( NOT parent() ) + return; /* Clearly this shouldn't happen, though */ + + get_this_column_dims(&col_x, &col_y, &col_w, &col_h, + &col_x_off, &col_y_off); + + if ( dynamic_cast(this) ) { + /* if ( this->prev() != NULL ) { + ((GLUI_Control*)prev())->get_this_column_dims(&col_x, &col_y, &col_w, &col_h, + &col_x_off, &col_y_off); + + x_abs = col_x + col_w; + } + else { + x_abs = ((GLUI_Control*)parent())->x_abs; + } + */ + return; + } + + if ( alignment == GLUI_ALIGN_LEFT ) { + x_abs = col_x + col_x_off; + } + else if ( alignment == GLUI_ALIGN_RIGHT ) { + x_abs = col_x + col_w - col_x_off - this->w; + } + else if ( alignment == GLUI_ALIGN_CENTER ) { + x_abs = col_x + (col_w - this->w) / 2; + } + + if ( this->is_container ) { + /*** Shift all child columns ***/ + int delta = x_abs - orig_x_abs; + + GLUI_Control *node; + + node = (GLUI_Control*) this->first_child(); + while( node != NULL ) { + if ( dynamic_cast(node) ) { + node->x_abs += delta; + } + + node = (GLUI_Control*) node->next(); + } + } + +} + + +/************** GLUI_Control::pack() ************/ +/* Recalculate positions and offsets */ + +void GLUI_Control::pack_old(int x, int y) +{ + GLUI_Control *node; + int max_w, curr_y, curr_x, max_y; + int x_in = x, y_in =y; + int x_margin, y_margin_top, y_margin_bot; + int y_top_column; + int column_x; + GLUI_Column *curr_column = NULL; + this->update_size(); + x_margin = this->x_off; + y_margin_top = this->y_off_top; + y_margin_bot = this->y_off_bot; + this->x_abs = x_in; + this->y_abs = y_in; + max_w = -1; + max_y = -1; + curr_x = this->x_abs + x_margin; + curr_y = this->y_abs + y_margin_top; + /*** Record start of this set of columns ***/ + y_top_column = curr_y; + column_x = 0; + if ( this == glui->main_panel ) { + x=x; + } + /*** Iterate over children, packing them first ***/ + node = (GLUI_Control*) this->first_child(); + while( node != NULL ) { + if ( dynamic_cast(node) && !node->collapsible) { + /* Pad some space above fixed size panels */ + curr_y += GLUI_ITEMSPACING; + } + else if ( dynamic_cast(node)) { + curr_column = (GLUI_Column*) node; + if ( 1 ) { + column_x += max_w + 2 * x_margin; + curr_x += max_w + 2 * x_margin; + } + else { + column_x += max_w + 0 * x_margin; + curr_x += max_w + 0 * x_margin; + } + /*node->pack( curr_x, curr_y ); */ + node->x_abs = curr_x; + node->y_abs = y_top_column; + node->w = 2; + node->h = curr_y - y_top_column; + curr_x += x_margin * 3 + 40; + curr_y = y_top_column; + max_w = 0; + node = (GLUI_Control*) node->next(); + continue; + } + node->pack( curr_x, curr_y ); + if ( dynamic_cast(node) && !node->collapsible) + /* Pad some space below fixed size panels */ + curr_y += GLUI_ITEMSPACING; + curr_y += node->h; + if ( node->w > max_w ) { + max_w = node->w; + if ( curr_column != NULL ) + curr_column->w = max_w; + } + node = (GLUI_Control*) node->next(); + if ( node ) { + curr_y += GLUI_ITEMSPACING; + } + if ( curr_y > max_y ) + max_y = curr_y; + } + if ( this->is_container ) { + max_y += y_margin_bot; /*** Add bottom border inside box */ + if ( this->first_child() ) { + if ( dynamic_cast(this) ) { + /** We don't want the rollout to shrink in width when it's + closed **/ + this->w = MAX(this->w, column_x + max_w + 2 * x_margin ); + } + else { + this->w = column_x + max_w + 2 * x_margin; + } + this->h = (max_y - y_in); + } + else { /* An empty container, so just assign default w & h */ + this->w = GLUI_DEFAULT_CONTROL_WIDTH; + this->h = GLUI_DEFAULT_CONTROL_HEIGHT; + } + /** Expand panel if necessary (e.g., to include all the text in + a panel label) **/ + this->update_size(); + } +} + +/*** GLUI_Control::get_this_column_dims() **********/ +/* Gets the x,y,w,h,and x/y offsets of the column to which a control belongs */ + +void GLUI_Control::get_this_column_dims( int *col_x, int *col_y, + int *col_w, int *col_h, + int *col_x_off, int *col_y_off ) +{ + GLUI_Control *node, *parent_ptr; + int parent_h, parent_y_abs; + + parent_ptr = (GLUI_Control*) parent(); + + if ( parent_ptr==NULL ) + return; + + parent_h = parent_ptr->h; + parent_y_abs = parent_ptr->y_abs; + + if ( dynamic_cast(parent_ptr) AND + parent_ptr->int_val == GLUI_PANEL_EMBOSSED AND + parent_ptr->name != "" ) { + parent_h -= GLUI_PANEL_EMBOSS_TOP; + parent_y_abs += GLUI_PANEL_EMBOSS_TOP; + } + + if ( 0 ) { + GLUI_Node *first, *last, *curr; + + /** Look for first control in this column **/ + first = this; + while (first->prev() AND !dynamic_cast(first->prev()) ) + first = first->prev(); + + /** Look for last control in this column **/ + last = this; + while ( last->next() AND !dynamic_cast(first->next()) ) + last = last->next(); + + curr = first; + int max_w = -1; + do { + if ( ((GLUI_Control*)curr)->w > max_w ) + max_w = ((GLUI_Control*)curr)->w; + + if ( curr == last ) + break; + + curr = curr->next(); + } while( curr != NULL ); + + *col_x = ((GLUI_Control*)first)->x_abs; + *col_y = ((GLUI_Control*)first)->y_abs; + *col_w = max_w; + if ( parent() ) { + *col_h = ((GLUI_Control*)parent())->h; + *col_x_off = ((GLUI_Control*)parent())->x_off; + } + else { + *col_h = 10; + *col_x_off = 0; + } + *col_y_off = 0; + + return; + } + + if ( 1 ) { /* IS THIS WRONG? */ + /*** Look for preceding column ***/ + node = (GLUI_Control*) this->prev(); + while( node ) { + if ( dynamic_cast(node) ) { + *col_x = node->x_abs; + *col_y = parent_y_abs; + *col_w = node->w; + *col_h = parent_h; + *col_x_off = node->x_off; + *col_y_off = 0; + + return; + } + + node = (GLUI_Control*) node->prev(); + } + + /*** Nope, Look for next column ***/ + node = (GLUI_Control*) this->next(); + while( node ) { + if ( dynamic_cast(node) ) { + *col_x = parent_ptr->x_abs; + *col_y = parent_y_abs; + *col_w = node->x_abs - parent_ptr->x_abs; + *col_h = parent_h; + *col_x_off = node->x_off; + *col_y_off = 0; + + return; + } + + node = (GLUI_Control*) node->next(); + } + + /*** This is single-column panel, so return panel dims ***/ + *col_x = parent_ptr->x_abs; + *col_y = parent_y_abs; + *col_w = parent_ptr->w; + *col_h = parent_h; + *col_x_off = parent_ptr->x_off; + *col_y_off = 0; + } +} + + +void GLUI_Control::pack( int x, int y ) +{ + GLUI_Control *node; + int max_w, curr_y, curr_x, max_y; + int x_in = x, y_in =y; + int x_margin, y_margin_top, y_margin_bot; + int y_top_column; + int column_x; + GLUI_Column *curr_column = NULL; + + this->update_size(); + + x_margin = this->x_off; + y_margin_top = this->y_off_top; + y_margin_bot = this->y_off_bot; + + this->x_abs = x_in; + this->y_abs = y_in; + + max_w = 0; + max_y = 0; + curr_x = this->x_abs + x_margin; + curr_y = this->y_abs + y_margin_top; + + /*** Record start of this set of columns ***/ + + y_top_column = curr_y; + column_x = curr_x; + + /*** Iterate over children, packing them first ***/ + + node = (GLUI_Control*) this->first_child(); + while( node != NULL ) { + if ( dynamic_cast(node) && !node->collapsible) { + /* Pad some space above fixed-size panels */ + curr_y += GLUI_ITEMSPACING; + } + else if ( dynamic_cast(node) ) { + curr_column = (GLUI_Column*) node; + curr_x += max_w + 1 * x_margin; + column_x = curr_x; + + node->x_abs = curr_x; + node->y_abs = y_top_column; + node->w = 2; + node->h = curr_y - y_top_column; + + curr_x += x_margin * 1; + curr_y = y_top_column; + max_w = 0; + + node = (GLUI_Control*) node->next(); + continue; + } + + node->pack( curr_x, curr_y ); + + if ( dynamic_cast(node) && !node->collapsible) + /* Pad some space below fixed-size panels */ + curr_y += GLUI_ITEMSPACING; + + curr_y += node->h; + + if ( node->w > max_w ) { + max_w = node->w; + if ( curr_column != NULL ) + curr_column->w = max_w + x_margin; + } + + if ( curr_y > max_y ) { + max_y = curr_y; + if ( curr_column != NULL ) + curr_column->h = max_y - y_top_column; + } + + node = (GLUI_Control*) node->next(); + + if ( node ) { + curr_y += GLUI_ITEMSPACING; + } + + } + + if ( this->is_container ) { + max_y += y_margin_bot; /*** Add bottom border inside box */ + + if ( this->first_child() ) { + this->w = column_x + max_w + 2 * x_margin - x_in; + this->h = (max_y - y_in); + } + else { /* An empty container, so just assign default w & h */ + if ( !dynamic_cast(this) && + !dynamic_cast(this) ) { + this->w = GLUI_DEFAULT_CONTROL_WIDTH; + this->h = GLUI_DEFAULT_CONTROL_HEIGHT; + } + } + + /** Expand panel if necessary (e.g., to include all the text in + a panel label) **/ + this->update_size(); + + + /*** Now we step through the GLUI_Columns, setting the 'h' ***/ + node = (GLUI_Control*) this->first_child(); + while( node != NULL ) { + if ( dynamic_cast(node) ) { + node->h = this->h - y_margin_bot - y_margin_top; + } + + node = (GLUI_Control*) node->next(); + } + } +} + + + +/******************************** Live Variables **************************/ +/*********** GLUI_Control::sync_live() ************/ +/* Reads live variable and sets control to its current value */ +/* This function is recursive, and operates on control's children */ + +void GLUI_Control::sync_live(int recurse, int draw_it) +{ + GLUI_Node *node; + int sync_it=true; + int i; + float *fp; + bool changed = false; + + /*** If this is currently active control, and mouse button is down, + don't sync ***/ + if ( glui ) + { + if ( this == glui->active_control AND glui->mouse_button_down ) + sync_it = false; + + /*** Actually, just disable syncing if button is down ***/ + /*** Nope, go ahead and sync if mouse is down - this allows syncing in + callbacks ***/ + if ( 0 ) { /* THIS CODE BELOW SHOULD NOT BE EXECUTED */ + if ( glui->mouse_button_down ) { + /* printf( "Can't sync\n" ); */ + return; + } + } + } + + /*** If this control has a live variable, we check its current value + against the stored value in the control ***/ + + if ( ptr_val != NULL ) { + if ( live_type == GLUI_LIVE_NONE OR NOT sync_it ) { + } + else if ( live_type == GLUI_LIVE_INT ) { + if ( *((int*)ptr_val) != last_live_int ) { + set_int_val( *((int*)ptr_val) ); + last_live_int = *((int*)ptr_val); + changed = true; + } + } + else if ( live_type == GLUI_LIVE_FLOAT ) { + if ( *((float*)ptr_val) != last_live_float ) { + set_float_val( *((float*)ptr_val) ); + last_live_float = *((float*)ptr_val); + changed = true; + } + } + else if ( live_type == GLUI_LIVE_TEXT ) { + if ( last_live_text.compare((const char*)ptr_val) != 0 ) { + set_text( (char*) ptr_val ); + last_live_text = (const char*)ptr_val; + changed = true; + } + } + else if ( live_type == GLUI_LIVE_STRING ) { + if ( last_live_text.compare(((std::string*) ptr_val)->c_str()) != 0 ) { + set_text( ((std::string*) ptr_val)->c_str()); + last_live_text = *((std::string*) ptr_val); + changed = true; + } + } + else if ( live_type == GLUI_LIVE_FLOAT_ARRAY ) { + /*** Step through the arrays, and see if they're the same ***/ + + fp = (float*) ptr_val; + for ( i=0; ifirst_child(); + while( node ) { + ((GLUI_Control*) node)->sync_live(true, true); + node = node->next(); + } + + if ( collapsible == true AND is_open == false ) { + /** Here we have a collapsed control (e.g., a rollout that is closed **/ + /** We need to go in and sync all the collapsed controls inside **/ + + node = this->collapsed_node.first_child(); + while( node ) { + ((GLUI_Control*) node)->sync_live(true, false); + node = node->next(); + } + } + } +} + + +/********** GLUI_Control::output_live() ************/ +/* Writes current value of control to live variable. */ + +void GLUI_Control::output_live(int update_main_gfx) +{ + int i; + float *fp; + + if ( ptr_val == NULL ) + return; + + if ( NOT live_inited ) + return; + + if ( live_type == GLUI_LIVE_NONE ) { + } + else if ( live_type == GLUI_LIVE_INT ) { + *((int*)ptr_val) = int_val; + last_live_int = int_val; + } + else if ( live_type == GLUI_LIVE_FLOAT ) { + *((float*)ptr_val) = float_val; + last_live_float = float_val; + } + else if ( live_type == GLUI_LIVE_TEXT ) { + strncpy( (char*) ptr_val, text.c_str(), text.length()+1); + last_live_text = text; + } + else if ( live_type == GLUI_LIVE_STRING ) { + (*(std::string*)ptr_val)= text.c_str(); + last_live_text = text; + } + else if ( live_type == GLUI_LIVE_FLOAT_ARRAY ) { + fp = (float*) ptr_val; + + for( i=0; iglui != NULL ) { + this->glui->post_update_main_gfx(); + } +} + + +/****** GLUI_Control::execute_callback() **********/ + +void GLUI_Control::execute_callback() +{ + int old_window; + + old_window = glutGetWindow(); + + if ( glui AND glui->main_gfx_window_id != -1 ) + glutSetWindow( glui->main_gfx_window_id ); + + this->callback( this ); +// if ( this->callback ) +// this->callback( this->user_id ); + + glutSetWindow( old_window ); +} + + +/************** GLUI_Control::init_live() **********/ +/* Reads in value of a live variable. Called once, when ctrl is created */ + +void GLUI_Control::init_live() +{ + int i; + float *fp; + + if ( ptr_val == NULL ) + return; + + if ( live_type == GLUI_LIVE_NONE ) { + } + else if ( live_type == GLUI_LIVE_INT ) { + set_int_val( *((int*)ptr_val) ); + last_live_int = *((int*)ptr_val); + } + else if ( live_type == GLUI_LIVE_FLOAT ) { + set_float_val( *((float*)ptr_val) ); + last_live_float = *((float*)ptr_val); + } + else if ( live_type == GLUI_LIVE_TEXT ) { + set_text( (const char*) ptr_val ); + last_live_text = (const char*) ptr_val; + } + else if ( live_type == GLUI_LIVE_STRING ) { + set_text( ((std::string*) ptr_val)->c_str() ); + last_live_text = ((std::string*) ptr_val)->c_str(); + } + else if ( live_type == GLUI_LIVE_FLOAT_ARRAY ) { + set_float_array_val( (float*) ptr_val ); + + fp = (float*) ptr_val; + + for( i=0; ienable(); + node = (GLUI_Control*) node->next(); + } +} + + +/***** GLUI_Control::disable() ****************/ + +void GLUI_Control::disable() +{ + GLUI_Control *node; + + enabled = false; + + if ( NOT glui ) + return; + + if ( glui->active_control == this ) + glui->deactivate_current_control(); + redraw(); + + /*** Now recursively disable all buttons below it ***/ + node = (GLUI_Control*) first_child(); + while(node) { + node->disable(); + node = (GLUI_Control*) node->next(); + } +} + +/******* GLUI_Control::set_w() **************/ + +void GLUI_Control::set_w(int new_w) +{ + w = new_w; + update_size(); /* Make sure control is big enough to fit text */ + if (glui) glui->refresh(); +} + + +/**** GLUI_Control::set_h() **************/ + +void GLUI_Control::set_h(int new_h) +{ + h = new_h; + update_size(); /* Make sure control is big enough to fit text */ + if (glui) glui->refresh(); +} + + +/***** GLUI_Control::set_alignment() ******/ + +void GLUI_Control::set_alignment(int new_align) +{ + alignment = new_align; + + if ( glui ) + { + glui->align_controls(this); + redraw_window(); + } +} + + +/***** GLUI_Control::needs_idle() *********/ +/* This method gets overloaded by specific classes, e.g. Spinner. */ +/* It returns whether or not a control needs to receive an idle event or not */ +/* For example, a spinner only needs idle events when the user is holding */ +/* the mouse down in one of the arrows. Otherwise, don't waste cycles */ +/* and OpenGL context switching by calling its idle. */ + +bool GLUI_Control::needs_idle() const +{ + return false; +} + + +/********* GLUI_Control::~GLUI_Control() **********/ + +GLUI_Control::~GLUI_Control() +{ + GLUI_Control *item = (GLUI_Control*) this->first_child(); + + while (item) + { + GLUI_Control *tmp = item; + item = (GLUI_Control*) item->next(); + delete tmp; + } +} + +/********* GLUI_Control::hide_internal() ********/ +/** Sets hidden==true for this control and all its siblings. */ +/** If recurse is true, we go to children as well */ + +void GLUI_Control::hide_internal( int recurse ) +{ + GLUI_Node *node; + + node = (GLUI_Node *) this; + while( node != NULL ) { + ((GLUI_Control*)node)->hidden = true; + + if ( recurse AND node->first_child() != NULL ) + ((GLUI_Control*) node->first_child())->hide_internal(true); + + node = node->next(); + } + + node = this->collapsed_node.first_child(); + while( node != NULL ) { + ((GLUI_Control*)node)->hidden = true; + + if ( recurse AND node->first_child() != NULL ) + ((GLUI_Control*) node->first_child())->hide_internal(true); + + node = node->next(); + } +} + + +/********* GLUI_Control::unhide_internal() ********/ +/** Sets hidden==false for this control and all its siblings. */ +/** If recurse is true, we go to children as well */ + +void GLUI_Control::unhide_internal( int recurse ) +{ + GLUI_Node *node; + + node = (GLUI_Node *) this; + while( node != NULL ) { + /* printf( "unhide: %s [%d]\n", ((GLUI_Control*)node)->name.c_str(), + ((GLUI_Control*)node)->hidden );*/ + ((GLUI_Control*)node)->hidden = false; + + if ( recurse AND node->first_child() != NULL ) + ((GLUI_Control*) node->first_child())->unhide_internal(true); + + node = node->next(); + } + + node = this->collapsed_node.first_child(); + while( node != NULL ) { + ((GLUI_Control*)node)->hidden = false; + + if ( recurse AND node->first_child() != NULL ) + ((GLUI_Control*) node->first_child())->unhide_internal(true); + + node = node->next(); + } +} diff --git a/Extras/glui/glui_edittext.cpp b/Extras/glui/glui_edittext.cpp new file mode 100644 index 000000000..5f2a1d845 --- /dev/null +++ b/Extras/glui/glui_edittext.cpp @@ -0,0 +1,1198 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_edittext.cpp - GLUI_EditText 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" +#include + +/****************************** GLUI_EditText::GLUI_EditText() **********/ + +GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, + int data_type, void *live_var, + int id, GLUI_CB callback ) +{ + if (data_type == GLUI_EDITTEXT_TEXT) { + live_type = GLUI_LIVE_TEXT; + } + else if (data_type == GLUI_EDITTEXT_STRING) { + data_type = GLUI_EDITTEXT_TEXT; // EDITTEXT_STRING doesn't really exist. + // Except as a signal to make a string. + // It's a backwards-compat hack. + live_type = GLUI_LIVE_STRING; + } + else if (data_type == GLUI_EDITTEXT_INT) { + live_type = GLUI_LIVE_INT; + } + else if (data_type == GLUI_EDITTEXT_FLOAT) { + live_type = GLUI_LIVE_FLOAT; + } + common_construct( parent, name, data_type, live_type, live_var, id, callback ); +} + +/****************************** GLUI_EditText::GLUI_EditText() **********/ + +GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, + int text_type, int id, GLUI_CB callback ) +{ + common_construct( parent, name, text_type, GLUI_LIVE_NONE, 0, id, callback); +} + +/****************************** GLUI_EditText::GLUI_EditText() **********/ + +GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, + int *live_var, + int id, GLUI_CB callback ) +{ + common_construct( parent, name, GLUI_EDITTEXT_INT, GLUI_LIVE_INT, live_var, id, callback); +} + +/****************************** GLUI_EditText::GLUI_EditText() **********/ + +GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, + float *live_var, + int id, GLUI_CB callback ) +{ + common_construct( parent, name, GLUI_EDITTEXT_FLOAT, GLUI_LIVE_FLOAT, live_var, id, callback); +} + +/****************************** GLUI_EditText::GLUI_EditText() **********/ + +GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, + char *live_var, + int id, GLUI_CB callback ) +{ + common_construct( parent, name, GLUI_EDITTEXT_TEXT, GLUI_LIVE_TEXT, live_var, id, callback); +} + +/****************************** GLUI_EditText::GLUI_EditText() **********/ + +GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, + std::string &live_var, + int id, GLUI_CB callback ) +{ + common_construct( parent, name, GLUI_EDITTEXT_TEXT, GLUI_LIVE_STRING, &live_var, id, callback); +} + +/****************************** GLUI_EditText::common_construct() **********/ + +void GLUI_EditText::common_construct( GLUI_Node *parent, const char *name, + int data_t, int live_t, void *data, int id, + GLUI_CB cb ) +{ + common_init(); + set_name( name ); + + live_type = live_t; + data_type = data_t; + ptr_val = data; + user_id = id; + callback = cb; + + + if ( live_type == GLUI_LIVE_INT) { + if ( data == NULL ) + set_int_val(int_val); /** Set to some default, in case of no live var **/ + } + else if ( live_type == GLUI_LIVE_FLOAT ) { + num_periods = 1; + if ( data == NULL ) + set_float_val(float_val); /** Set to some default, in case of no live var **/ + } + + parent->add_control( this ); + + init_live(); +} + +/****************************** GLUI_EditText::mouse_down_handler() **********/ + +int GLUI_EditText::mouse_down_handler( int local_x, int local_y ) +{ + int tmp_insertion_pt; + + if ( debug ) dump( stdout, "-> MOUSE DOWN" ); + + tmp_insertion_pt = find_insertion_pt( local_x, local_y ); + if ( tmp_insertion_pt == -1 ) { + if ( glui ) + glui->deactivate_current_control( ); + return false; + } + + insertion_pt = tmp_insertion_pt; + + sel_start = sel_end = insertion_pt; + + if ( can_draw()) + update_and_draw_text(); + + if ( debug ) dump( stdout, "<- MOUSE UP" ); + + return true; +} + + +/******************************** GLUI_EditText::mouse_up_handler() **********/ + +int GLUI_EditText::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + return false; +} + + +/***************************** GLUI_EditText::mouse_held_down_handler() ******/ + +int GLUI_EditText::mouse_held_down_handler( int local_x, int local_y, + bool new_inside) +{ + int tmp_pt; + + if ( NOT new_inside ) + return false; + + if ( debug ) dump( stdout, "-> HELD DOWN" ); + + tmp_pt = find_insertion_pt( local_x, local_y ); + + if ( tmp_pt == -1 AND sel_end != 0 ) { /* moved mouse past left edge */ + special_handler( GLUT_KEY_LEFT, GLUT_ACTIVE_SHIFT ); + } + else if ( tmp_pt == substring_end+1 AND sel_end != (int) text.length()) { + /* moved mouse past right edge */ + special_handler( GLUT_KEY_RIGHT, GLUT_ACTIVE_SHIFT ); + } + else if ( tmp_pt != -1 AND tmp_pt != sel_end ) { + sel_end = insertion_pt = tmp_pt; + + update_and_draw_text(); + } + + if ( debug ) + dump( stdout, "<- HELD DOWN" ); + + return false; +} + + +/****************************** GLUI_EditText::key_handler() **********/ + +int GLUI_EditText::key_handler( unsigned char key,int modifiers ) +{ + int i, regular_key; + /* int has_selection; */ + + if ( NOT glui ) + return false; + + if ( debug ) + dump( stdout, "-> KEY HANDLER" ); + + regular_key = false; + bool ctrl_down = (modifiers & GLUT_ACTIVE_CTRL)!=0; + /* has_selection = (sel_start != sel_end); */ + + if ( key == CTRL('m') ) { /* RETURN */ + /* glui->deactivate_current_control(); */ + deactivate(); /** Force callbacks, etc **/ + activate(GLUI_ACTIVATE_TAB); /** Reselect all text **/ + redraw(); + return true; + } + else if ( key == CTRL('[')) { /* ESCAPE */ + glui->deactivate_current_control(); + return true; + } + else if ( (key == 127 AND !ctrl_down) OR /* FORWARD DELETE */ + ( key == CTRL('d') AND modifiers == GLUT_ACTIVE_CTRL) ) + { + if ( sel_start == sel_end ) { /* no selection */ + if ( insertion_pt < (int)text.length() ) { + /*** See if we're deleting a period in a float data-type box ***/ + if ( data_type == GLUI_EDITTEXT_FLOAT AND text[insertion_pt]=='.' ) + num_periods--; + + /*** Shift over string first ***/ + text.erase(insertion_pt,1); + } + } + else { /* There is a selection */ + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + } + else if ( ((key == 127) AND ctrl_down) OR // Delete word forward + ((key == 'd') AND (modifiers == GLUT_ACTIVE_ALT)) ) + { + if ( sel_start == sel_end ) { /* no selection */ + sel_start = insertion_pt; + sel_end = find_word_break( insertion_pt, +1 ); + } + + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + else if ( key == CTRL('h') ) { /* BACKSPACE */ + if ( sel_start == sel_end ) { /* no selection */ + if ( insertion_pt > 0 ) { + /*** See if we're deleting a period in a float data-type box ***/ + if ( data_type == GLUI_EDITTEXT_FLOAT AND text[insertion_pt-1]=='.' ) + num_periods--; + + /*** Shift over string first ***/ + insertion_pt--; + text.erase(insertion_pt,1); + } + } + else { /* There is a selection */ + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + } + else if ( modifiers == GLUT_ACTIVE_CTRL ) /* CTRL ONLY */ + { + /* Ctrl-key bindings */ + if ( key == CTRL('a') ) { + return special_handler( GLUT_KEY_HOME, 0 ); + } + else if ( key == CTRL('e') ) { + return special_handler( GLUT_KEY_END, 0 ); + } + else if ( key == CTRL('b') ) { + return special_handler( GLUT_KEY_LEFT, 0 ); + } + else if ( key == CTRL('f') ) { + return special_handler( GLUT_KEY_RIGHT, 0 ); + } + else if ( key == CTRL('p') ) { + return special_handler( GLUT_KEY_UP, 0 ); + } + else if ( key == CTRL('n') ) { + return special_handler( GLUT_KEY_DOWN, 0 ); + } + else if ( key == CTRL('u') ) { /* ERASE LINE */ + insertion_pt = 0; + text.erase(0,text.length()); + sel_start = sel_end = 0; + } + else if ( key == CTRL('k') ) { /* KILL TO END OF LINE */ + sel_start = sel_end = insertion_pt; + text.erase(insertion_pt,GLUI_String::npos); + } + } + else if ( modifiers == GLUT_ACTIVE_ALT ) /* ALT ONLY */ + { + if ( key == 'b' ) { // Backward word + return special_handler ( GLUT_KEY_LEFT, GLUT_ACTIVE_CTRL ); + } + if ( key == 'f' ) { // Forward word + return special_handler ( GLUT_KEY_RIGHT, GLUT_ACTIVE_CTRL ); + } + } + else if ( (modifiers & GLUT_ACTIVE_CTRL) OR + (modifiers & GLUT_ACTIVE_ALT) ) + { + /** ignore other keys with modifiers */ + return true; + } + else { /* Regular key */ + regular_key = true; + + /** Check if we only accept numbers **/ + if (data_type == GLUI_EDITTEXT_FLOAT ) { + if ( (key < '0' OR key > '9') AND key != '.' AND key != '-' ) + return true; + + if ( key == '-' ) { /* User typed a '-' */ + + /* If user has first character selected, then '-' is allowed */ + if ( NOT ( MIN(sel_start,sel_end) == 0 AND + MAX(sel_start,sel_end) > 0 ) ) { + + /* User does not have 1st char selected */ + if (insertion_pt != 0 OR text[0] == '-' ) { + return true; /* Can only place negative at beginning of text, + and only one of them */ + } + } + } + + if ( key == '.' ) { + /*printf( "PERIOD: %d\n", num_periods ); */ + + if ( num_periods > 0 ) { + /** We're trying to type a period, but the text already contains + a period. Check whether the period is contained within + is current selection (thus it will be safely replaced) **/ + + int period_found = false; + if ( sel_start != sel_end ) { + for( i=MIN(sel_end,sel_start); i '9') AND key != '-' ) + return true; + + if ( key == '-' ) { /* User typed a '-' */ + + /* If user has first character selected, then '-' is allowed */ + if ( NOT ( MIN(sel_start,sel_end) == 0 AND + MAX(sel_start,sel_end) > 0 ) ) { + + /* User does not have 1st char selected */ + if (insertion_pt != 0 OR text[0] == '-' ) { + return true; /* Can only place negative at beginning of text, + and only one of them */ + } + } + } + } + + /** This is just to get rid of warnings - the flag regular_key is + set if the key was not a backspace, return, whatever. But I + believe if we're here, we know it was a regular key anyway */ + if ( regular_key ) { + } + + /**** If there's a current selection, erase it ******/ + if ( sel_start != sel_end ) { + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + + /******** We insert the character into the string ***/ + + text.insert(insertion_pt,1,key); + + /******** Move the insertion point and substring_end one over ******/ + insertion_pt++; + substring_end++; + + sel_start = sel_end = insertion_pt; + } + + /******** Now redraw text ***********/ + /* Hack to prevent text box from being cleared first **/ + /** int substring_change = update_substring_bounds(); + draw_text_only = + (NOT substring_change AND NOT has_selection AND regular_key ); + */ + + draw_text_only = false; /** Well, hack is not yet working **/ + update_and_draw_text(); + draw_text_only = false; + + + if ( debug ) + dump( stdout, "<- KEY HANDLER" ); + + /*** Now look to see if this string has a period ***/ + num_periods = 0; + for( i=0; i<(int)text.length(); i++ ) + if ( text[i] == '.' ) + num_periods++; + + return true; +} + + +/****************************** GLUI_EditText::activate() **********/ + +void GLUI_EditText::activate( int how ) +{ + if ( debug ) + dump( stdout, "-> ACTIVATE" ); + + active = true; + + if ( how == GLUI_ACTIVATE_MOUSE ) + return; /* Don't select everything if activated with mouse */ + + orig_text = text; + + sel_start = 0; + sel_end = (int)text.length(); + insertion_pt = 0; + + if ( debug ) + dump( stdout, "<- ACTIVATE" ); +} + + +/****************************** GLUI_EditText::deactivate() **********/ + +void GLUI_EditText::deactivate( void ) +{ + int new_int_val; + float new_float_val; + + active = false; + + if ( NOT glui ) + return; + + if ( debug ) + dump( stdout, "-> DISACTIVATE" ); + + sel_start = sel_end = insertion_pt = -1; + + /***** Retrieve the current value from the text *****/ + /***** The live variable will be updated by set_text() ****/ + if ( data_type == GLUI_EDITTEXT_FLOAT ) { + if ( text.length() == 0 ) /* zero-length string - make it "0.0" */ + text = "0.0"; + + new_float_val = atof( text.c_str() ); + + set_float_val( new_float_val ); + } + else if ( data_type == GLUI_EDITTEXT_INT ) { + if ( text.length() == 0 ) /* zero-length string - make it "0" */ + text = "0"; + + new_int_val = atoi( text.c_str() ); + + set_int_val( new_int_val ); + } + else + if ( data_type == GLUI_EDITTEXT_TEXT ) { + set_text(text); /* This will force callbacks and gfx refresh */ + } + + update_substring_bounds(); + + /******** redraw text without insertion point ***********/ + redraw(); + + /***** Now do callbacks if value changed ******/ + if ( orig_text != text ) { + this->execute_callback(); + + if ( 0 ) { + /* THE CODE BELOW IS FROM WHEN SPINNER ALSO MAINTAINED CALLBACKS */ + if ( spinner == NULL ) { /** Are we independent of a spinner? **/ + if ( callback ) { + callback( this ); + } + } + else { /* We're attached to a spinner */ + spinner->do_callbacks(); /* Let the spinner do the callback stuff */ + } + } + } + + if ( debug ) + dump( stdout, "<- DISACTIVATE" ); +} + +/****************************** GLUI_EditText::draw() **********/ + +void GLUI_EditText::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int name_x; + + name_x = MAX(text_x_offset - string_width(this->name) - 3,0); + draw_name( name_x , 13); + + glBegin( GL_LINES ); + glColor3f( .5, .5, .5 ); + glVertex2i( text_x_offset, 0 ); glVertex2i( w, 0 ); + glVertex2i( text_x_offset, 0 ); glVertex2i( text_x_offset, h ); + + glColor3f( 1., 1., 1. ); + glVertex2i( text_x_offset, h ); glVertex2i( w, h ); + glVertex2i( w, h ); glVertex2i( w, 0 ); + + if ( enabled ) + glColor3f( 0., 0., 0. ); + else + glColor3f( .25, .25, .25 ); + glVertex2i( text_x_offset+1, 1 ); glVertex2i( w-1, 1 ); + glVertex2i( text_x_offset+1, 1 ); glVertex2i( text_x_offset+1, h-1 ); + + glColor3f( .75, .75, .75 ); + glVertex2i( text_x_offset+1, h-1 ); glVertex2i( w-1, h-1 ); + glVertex2i( w-1, h-1 ); glVertex2i( w-1, 1 ); + glEnd(); + + /** Find where to draw the text **/ + update_substring_bounds(); + draw_text(0,0); + + draw_insertion_pt(); +} + + + +/************************** GLUI_EditText::update_substring_bounds() *********/ + +int GLUI_EditText::update_substring_bounds( void ) +{ + int box_width; + int text_len = (int)text.length(); + int old_start, old_end; + + old_start = substring_start; + old_end = substring_end; + + /*** Calculate the width of the usable area of the edit box ***/ + box_width = MAX( this->w - this->text_x_offset + - 4 /* 2 * the two-line box border */ + - 2 * GLUI_EDITTEXT_BOXINNERMARGINX, 0 ); + + CLAMP( substring_end, 0, MAX(text_len-1,0) ); + CLAMP( substring_start, 0, MAX(text_len-1,0) ); + + if ( debug ) dump( stdout, "-> UPDATE SS" ); + + if ( insertion_pt >= 0 AND + insertion_pt < substring_start ) { /* cursor moved left */ + substring_start = insertion_pt; + + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_end--; + } + else if ( insertion_pt > substring_end ) { /* cursor moved right */ + substring_end = insertion_pt-1; + + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_start++; + } + else { /* cursor is within old substring bounds */ + if ( last_insertion_pt > insertion_pt ) { /* cursor moved left */ + } + else { + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_end--; + + while(substring_end < text_len-1 + AND substring_width( substring_start, substring_end ) <= box_width) + substring_end++; + } + } + + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_end--; + + last_insertion_pt = insertion_pt; + + /*** No selection if not enabled ***/ + if ( NOT enabled ) { + sel_start = sel_end = 0; + } + + if ( debug ) dump( stdout, "<- UPDATE SS" ); + + if ( substring_start == old_start AND substring_end == old_end ) + return false; /*** bounds did not change ***/ + else + return true; /*** bounds did change ***/ +} + + +/********************************* GLUI_EditText::update_x_offsets() *********/ + +void GLUI_EditText::update_x_offsets( void ) +{ +} + + +/********************************* GLUI_EditText::draw_text() ****************/ + +void GLUI_EditText::draw_text( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int text_x, i, sel_lo, sel_hi; + + if ( debug ) dump( stdout, "-> DRAW_TEXT" ); + + if ( NOT draw_text_only ) { + if ( enabled ) + glColor3f( 1., 1., 1. ); + else + set_to_bkgd_color(); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( text_x_offset+2, 2 ); glVertex2i( w-2, 2 ); + glVertex2i( w-2, h-2 ); glVertex2i( text_x_offset+2, h-2 ); + glEnd(); + } + + /** Find where to draw the text **/ + + text_x = text_x_offset + 2 + GLUI_EDITTEXT_BOXINNERMARGINX; + + /*printf( "text_x: %d substr_width: %d start/end: %d/%d\n", + text_x, substring_width( substring_start, substring_end ), + substring_start, substring_end ); + */ + /** Find lower and upper selection bounds **/ + sel_lo = MIN(sel_start, sel_end ); + sel_hi = MAX(sel_start, sel_end ); + + int sel_x_start, sel_x_end, delta; + + /** Draw selection area dark **/ + if ( sel_start != sel_end ) { + sel_x_start = text_x; + sel_x_end = text_x; + for( i=substring_start; i<=substring_end; i++ ) { + delta = char_width( text[i] ); + + if ( i < sel_lo ) { + sel_x_start += delta; + sel_x_end += delta; + } + else if ( i < sel_hi ) { + sel_x_end += delta; + } + } + + glColor3f( 0.0f, 0.0f, .6f ); + glBegin( GL_QUADS ); + glVertex2i( sel_x_start, 2 ); glVertex2i( sel_x_end, 2 ); + glVertex2i( sel_x_end, h-2 ); glVertex2i( sel_x_start, h-2 ); + glEnd(); + } + + + if ( sel_start == sel_end ) { /* No current selection */ + if ( enabled ) + glColor3b( 0, 0, 0 ); + else + glColor3b( 32, 32, 32 ); + + glRasterPos2i( text_x, 13); + for( i=substring_start; i<=substring_end; i++ ) { + glutBitmapCharacter( get_font(), this->text[i] ); + } + } + else { /* There is a selection */ + int x = text_x; + for( i=substring_start; i<=substring_end; i++ ) { + if ( IN_BOUNDS( i, sel_lo, sel_hi-1)) { /* This character is selected */ + glColor3f( 1., 1., 1. ); + glRasterPos2i( x, 13); + glutBitmapCharacter( get_font(), this->text[i] ); + } + else { + glColor3f( 0., 0., 0. ); + glRasterPos2i( x, 13); + glutBitmapCharacter( get_font(), this->text[i] ); + } + + x += char_width( text[i] ); + } + } + + if ( debug ) dump( stdout, "<- DRAW_TEXT" ); +} + + +/******************************** GLUI_EditText::find_insertion_pt() *********/ +/* This function returns the character numer *before which* the insertion */ +/* point goes */ + +int GLUI_EditText::find_insertion_pt( int x, int y ) +{ + int curr_x, i; + + /*** See if we clicked outside box ***/ + if ( x < this->x_abs + text_x_offset ) + return -1; + + /* We move from right to left, looking to see if the mouse was clicked + to the right of the ith character */ + + curr_x = this->x_abs + text_x_offset + + substring_width( substring_start, substring_end ) + + 2 /* The edittext box has a 2-pixel margin */ + + GLUI_EDITTEXT_BOXINNERMARGINX; /** plus this many pixels blank space + between the text and the box **/ + + /*** See if we clicked in an empty box ***/ + if ( (int) text.length() == 0 ) + return 0; + + /** find mouse click in text **/ + for( i=substring_end; i>=substring_start; i-- ) { + curr_x -= char_width( text[i] ); + + if ( x > curr_x ) { + /* printf( "-> %d\n", i ); */ + + return i+1; + } + } + + return 0; + + /* Well, the mouse wasn't after any of the characters...see if it's + before the beginning of the substring */ + if ( 0 ) { + if ( x > (x_abs + text_x_offset + 2 ) ) + return substring_start; + + return -1; /* Nothing found */ + } +} + + +/******************************** GLUI_EditText::draw_insertion_pt() *********/ + +void GLUI_EditText::draw_insertion_pt( void ) +{ + int curr_x, i; + + if ( NOT can_draw() ) + return; + + /*** Don't draw insertion pt if control is disabled ***/ + if ( NOT enabled ) + return; + + if ( debug ) dump( stdout, "-> DRAW_INS_PT" ); + + if ( sel_start != sel_end OR insertion_pt < 0 ) { + return; /* Don't draw insertion point if there is a current selection */ + } + + /* printf( "insertion pt: %d\n", insertion_pt ); */ + + curr_x = this->x_abs + text_x_offset + + substring_width( substring_start, substring_end ) + + 2 /* The edittext box has a 2-pixel margin */ + + GLUI_EDITTEXT_BOXINNERMARGINX; /** plus this many pixels blank space + between the text and the box **/ + + for( i=substring_end; i>=insertion_pt; i-- ) { + curr_x -= char_width( text[i] ); + } + + glColor3f( 0.0, 0.0, 0.0 ); + glBegin( GL_LINE_LOOP ); + /*** + glVertex2i( curr_x, y_abs + 4 ); + glVertex2i( curr_x, y_abs + 4 ); + glVertex2i( curr_x, y_abs + h - 3 ); + glVertex2i( curr_x, y_abs + h - 3 ); + ***/ + curr_x -= x_abs; + glVertex2i( curr_x, 0 + 4 ); + glVertex2i( curr_x, 0 + 4 ); + glVertex2i( curr_x, 0 + h - 3 ); + glVertex2i( curr_x, 0 + h - 3 ); + glEnd(); + + if ( debug ) dump( stdout, "-> DRAW_INS_PT" ); +} + + + +/******************************** GLUI_EditText::substring_width() *********/ + +int GLUI_EditText::substring_width( int start, int end ) +{ + int i, width; + + width = 0; + + for( i=start; i<=end; i++ ) + width += char_width( text[i] ); + + return width; +} + + +/***************************** GLUI_EditText::update_and_draw_text() ********/ + +void GLUI_EditText::update_and_draw_text( void ) +{ + if ( NOT can_draw() ) + return; + + update_substring_bounds(); + /* printf( "ss: %d/%d\n", substring_start, substring_end ); */ + + redraw(); +} + + +/********************************* GLUI_EditText::special_handler() **********/ + +int GLUI_EditText::special_handler( int key,int modifiers ) +{ + if ( NOT glui ) + return false; + + if ( debug ) + printf( "SPECIAL:%d - mod:%d subs:%d/%d ins:%d sel:%d/%d\n", + key, modifiers, substring_start, substring_end,insertion_pt, + sel_start, sel_end ); + + if ( key == GLUT_KEY_LEFT ) { + if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) { + insertion_pt = find_word_break( insertion_pt, -1 ); + } + else { + insertion_pt--; + } + } + else if ( key == GLUT_KEY_RIGHT ) { + if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) { + insertion_pt = find_word_break( insertion_pt, +1 ); + } + else { + insertion_pt++; + } + } + else if ( key == GLUT_KEY_HOME ) { + insertion_pt = 0; + } + else if ( key == GLUT_KEY_END ) { + insertion_pt = (int) text.length(); + } + + /*** Update selection if shift key is down ***/ + if ( (modifiers & GLUT_ACTIVE_SHIFT ) != 0 ) + sel_end = insertion_pt; + else + sel_start = sel_end = insertion_pt; + + + CLAMP( insertion_pt, 0, (int) text.length()); /* Make sure insertion_pt + is in bounds */ + CLAMP( sel_start, 0, (int) text.length()); /* Make sure insertion_pt + is in bounds */ + CLAMP( sel_end, 0, (int) text.length()); /* Make sure insertion_pt + is in bounds */ + + /******** Now redraw text ***********/ + if ( can_draw()) + update_and_draw_text(); + + return true; +} + + +/****************************** GLUI_EditText::find_word_break() **********/ +/* It looks either left or right (depending on value of 'direction' */ +/* for the beginning of the next 'word', where word are characters */ +/* separated by one of the following tokens: " :-.," */ +/* If there is no next word in the specified direction, this returns */ +/* the beginning of 'text', or the very end. */ + +int GLUI_EditText::find_word_break( int start, int direction ) +{ + int i, j; + char *breaks = " :-.,"; + int num_break_chars = (int)strlen(breaks), text_len = (int)text.length(); + int new_pt; + + /** If we're moving left, we have to start two back, in case we're either + already at the beginning of a word, or on a separating token. + Otherwise, this function would just return the word we're already at **/ + if ( direction == -1 ) { + start -= 2; + } + + /***** Iterate over text in the specified direction *****/ + for ( i=start; i >= 0 AND i < text_len; i += direction ) { + + /** For each character in text, iterate over list of separating tokens **/ + for( j=0; j 0 ) /* Return the end of string */ + return text_len; + else /* Return the beginning of the text */ + return 0; +} + + +/********************************** GLUI_EditText::clear_substring() ********/ + +void GLUI_EditText::clear_substring( int start, int end ) +{ + int i; + + /* + printf( "clearing: %d-%d '", start,end); + for(i=start;ifloat_val = this->float_val; + spinner->int_val = this->int_val; + } + + /*** Now update the live variable ***/ + output_live(true); +} + + +/******************************* GLUI_EditText::set_float_val() ************/ + +void GLUI_EditText::set_float_val( float new_val ) +{ + if ( has_limits == GLUI_LIMIT_CLAMP ) { + /*** Clamp the new value to the existing limits ***/ + + CLAMP( new_val, float_low, float_high ); + } + else if ( has_limits == GLUI_LIMIT_WRAP ) { + /*** Clamp the value cyclically to the limits - that is, if the + value exceeds the max, set it the the minimum, and conversely ***/ + + if ( new_val < float_low ) + new_val = float_high; + if ( new_val > float_high ) + new_val = float_low; + } + + float_val = new_val; + int_val = (int) new_val; /* Mirror the value as an int, too */ + + set_numeric_text(); +} + + +/********************************** GLUI_EditText::set_int_val() ************/ + +void GLUI_EditText::set_int_val( int new_val ) +{ + if ( has_limits == GLUI_LIMIT_CLAMP ) { + /*** Clamp the new value to the existing limits ***/ + + CLAMP( new_val, int_low, int_high ); + } + else if ( has_limits == GLUI_LIMIT_WRAP ) { + /*** Clamp the value cyclically to the limits - that is, if the + value exceeds the max, set it the the minimum, and conversely ***/ + + if ( new_val < int_low ) + new_val = int_high; + if ( new_val > int_high ) + new_val = int_low; + } + + int_val = new_val; + float_val = (float) new_val; /* We mirror the value as a float, too */ + + set_numeric_text(); +} + + +/********************************* GLUI_EditText::set_float_limits() *********/ + +void GLUI_EditText::set_float_limits( float low, float high, int limit_type ) +{ + has_limits = limit_type; + float_low = low; + float_high = high; + + if ( NOT IN_BOUNDS( float_val, float_low, float_high )) + set_float_val( float_low ); + + int_low = (int) float_low; + int_high = (int) float_high; +} + + +/*********************************** GLUI_EditText::set_int_limits() *********/ + +void GLUI_EditText::set_int_limits( int low, int high, int limit_type ) +{ + has_limits = limit_type; + int_low = low; + int_high = high; + + if ( NOT IN_BOUNDS( int_val, int_low, int_high )) + set_int_val( int_low ); + + float_low = (float) int_low; + float_high = (float) int_high; +} + + +/************************************ GLUI_EditText::set_numeric_text() ******/ + +void GLUI_EditText::set_numeric_text( void ) +{ + char buf_num[200]; + int i, text_len; + + if ( data_type == GLUI_EDITTEXT_FLOAT ) { + sprintf( buf_num, "%#g", float_val ); + + num_periods = 0; + text_len = (int) strlen(buf_num); + for ( i=0; i 0 ) { + text_len = (int) strlen(buf_num); + for ( i=text_len-1; i>0; i-- ) { + if ( buf_num[i] == '0' AND buf_num[i-1] != '.' ) + buf_num[i] = '\0'; + else + break; + } + } + set_text( buf_num ); + } + else { + sprintf( buf_num, "%d", int_val ); + set_text( buf_num ); + } + +} + + +/*************************************** GLUI_EditText::dump() **************/ + +void GLUI_EditText::dump( FILE *out, const char *name ) +{ + fprintf( out, + "%s (edittext@%p): ins_pt:%d subs:%d/%d sel:%d/%d len:%d\n", + name, this, + insertion_pt, + substring_start, + substring_end, + sel_start, + sel_end, + (int) text.length()); +} + + +/**************************************** GLUI_EditText::mouse_over() ********/ + +int GLUI_EditText::mouse_over( int state, int x, int y ) +{ + if ( state ) { + /* curr_cursor = GLUT_CURSOR_TEXT; */ + glutSetCursor( GLUT_CURSOR_TEXT ); + } + else { + /* printf( "OUT\n" ); */ + glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); + } + + return true; +} diff --git a/Extras/glui/glui_filebrowser.cpp b/Extras/glui/glui_filebrowser.cpp new file mode 100644 index 000000000..c1b7cbb5d --- /dev/null +++ b/Extras/glui/glui_filebrowser.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_filebrowser.cpp - GLUI_FileBrowser control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + 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 "GL/glui.h" +#include "glui_internal.h" +#include + +#ifdef __GNUC__ +#include +#include +#endif + +#ifdef _WIN32 +#include +#endif + +#include + +GLUI_FileBrowser::GLUI_FileBrowser( GLUI_Node *parent, + const char *name, + int type, + int id, + GLUI_CB cb) +{ + common_init(); + + set_name( name ); + user_id = id; + int_val = type; + callback = cb; + + parent->add_control( this ); + list = new GLUI_List(this, true, 1); + list->set_object_callback( GLUI_FileBrowser::dir_list_callback, this ); + list->set_click_type(GLUI_DOUBLE_CLICK); + this->fbreaddir(this->current_dir.c_str()); +} + +/****************************** GLUI_FileBrowser::draw() **********/ + +void GLUI_FileBrowser::dir_list_callback(GLUI_Control *glui_object) { + GLUI_List *list = dynamic_cast(glui_object); + if (!list) + return; + GLUI_FileBrowser* me = dynamic_cast(list->associated_object); + if (!me) + return; + int this_item; + const char *selected; + this_item = list->get_current_item(); + if (this_item > 0) { /* file or directory selected */ + selected = list->get_item_ptr( this_item )->text.c_str(); + if (selected[0] == '/' || selected[0] == '\\') { + if (me->allow_change_dir) { +#ifdef __GNUC__ + chdir(selected+1); +#endif +#ifdef _WIN32 + SetCurrentDirectory(selected+1); +#endif + me->fbreaddir("."); + } + } else { + me->file = selected; + me->execute_callback(); + } + } +} + + + +void GLUI_FileBrowser::fbreaddir(const char *d) { + GLUI_String item; + int i = 0; + + if (!d) + return; + +#ifdef _WIN32 + + WIN32_FIND_DATA FN; + HANDLE hFind; + //char search_arg[MAX_PATH], new_file_path[MAX_PATH]; + //sprintf(search_arg, "%s\\*.*", path_name); + + hFind = FindFirstFile("*.*", &FN); + if (list) { + list->delete_all(); + if (hFind != INVALID_HANDLE_VALUE) { + do { + int len = strlen(FN.cFileName); + if (FN.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + item = '\\'; + item += FN.cFileName; + } else { + item = FN.cFileName; + } + list->add_item(i,item.c_str()); + i++; + } while (FindNextFile(hFind, &FN) != 0); + + if (GetLastError() == ERROR_NO_MORE_FILES) + FindClose(&FN); + else + perror("fbreaddir"); + } + } + +#elif defined(__GNUC__) + + DIR *dir; + struct dirent *dirp; + struct stat dr; + + if (list) { + list->delete_all(); + if ((dir = opendir(d)) == NULL) + perror("fbreaddir:"); + else { + while ((dirp = readdir(dir)) != NULL) /* open directory */ + { + if (!lstat(dirp->d_name,&dr) && S_ISDIR(dr.st_mode)) /* dir is directory */ + item = dirp->d_name + GLUI_String("/"); + else + item = dirp->d_name; + + list->add_item(i,item.c_str()); + i++; + } + closedir(dir); + } + } +#endif +} + +void ProcessFiles(const char *path_name) +{ + +} + + +void GLUI_FileBrowser::set_w(int w) +{ + if (list) list->set_w(w); +} + +void GLUI_FileBrowser::set_h(int h) +{ + if (list) list->set_h(h); +} diff --git a/Extras/glui/glui_internal.h b/Extras/glui/glui_internal.h new file mode 100644 index 000000000..20efc6f93 --- /dev/null +++ b/Extras/glui/glui_internal.h @@ -0,0 +1,105 @@ +#ifndef GLUI_INTERNAL_H +#define GLUI_INTERNAL_H + +#include +#include + +#ifndef AND +#define AND && +#define OR || +#define NOT ! +#endif + +#ifndef MAX +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#define MIN(a,b) ((a)<(b) ? (a) : (b)) +#endif + +#ifndef ABS +#define ABS(a) ((a)>=0 ? (a) : (-(a))) +#endif + +/******************** bit comparisons and operations ***************/ +#ifndef TEST_BIT +#define TEST_BIT( x, b ) (((x) & (1<<(b))) != 0 ) +#define SET_BIT( x, b ) ((x) |= (1 << (b))) +#define CLEAR_BIT( x, b ) ((x) &= ~(1 << (b))) +#define TOGGLE_BIT( x, b ) ((TEST_BIT(x,b)) ?(CLEAR_BIT(x,b)):(SET_BIT(x,b))) +#endif + +#ifndef TEST_AND +#define TEST_AND( a, b ) ((a&b)==b) +#endif + + +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +/*********** flush the stdout and stderr output streams *************/ +#ifndef flushout +#define flushout fflush(stdout) +#define flusherr fflush(stderr) +#endif + +/********** Debugging functions *************************************/ +#ifndef error_return +#define error_return( c ); {fprintf(stderr,c);return;} +#endif + +/************************* floating-point random ********************/ +#ifndef randf +#define randf() ((float) rand() / (float)RAND_MAX ) +#endif + +#ifndef SIGN +#define SIGN(x) ((x)>=0 ? 1 : -1) +#endif + +/****************** conversion between degrees and radians **********/ +#ifndef DEG2RAD +#define DEG2RAD(x) ((x)/180.0*M_PI) +#define RAD2DEG(x) ((x)/M_PI*180.0) +#endif + +/***************** clamp a value to some fixed interval *************/ +#ifndef CLAMP +#define CLAMP(x,lo,hi) {if ((x) < (lo)) {(x)=(lo);} else if((x) > (hi)) {(x)=(hi);}} +#endif + +/************ check if a value lies within a closed interval *********/ +#ifndef IN_BOUNDS +#define IN_BOUNDS( x, lo, hi ) ( (x) >= (lo) AND (x) <= (hi) ) +#endif + +/************ check if a 2D point lies within a 2D box ***************/ +#ifndef PT_IN_BOX +#define PT_IN_BOX( x, y, lo_x, hi_x, lo_y, hi_y ) \ +( IN_BOUNDS(x,lo_x,hi_x) AND IN_BOUNDS(y,lo_y,hi_y) ) +#endif + +/****** check if value lies on proper side of another value *****/ +/*** if side is positive => proper side is positive, else negative **/ +#ifndef CHECK_PROPER_SIDE +#define CHECK_PROPER_SIDE(x,val,side) ((side) > 0 ? (x) > (val) : (x) < (val)) +#endif + + +/***** Small value when we want to do a comparison to 'close to zero' *****/ +#ifndef FUDGE +#define FUDGE .00001 +#endif + + +/******************* swap two values, using a temp variable *********/ +#ifndef SWAP2 +#define SWAP2(a,b,t) {t=a;a=b;b=t;} +#endif + +#define VEC3_TO_ARRAY(v,a) a[0]=v[0], a[1]=v[1], a[2]=v[2] + +/**** Return the ASCII control code given the non-control ASCII character */ +#define CTRL(c) ( (c>=('a'-1)) ? (c-'a'+1) : (c-'A'+1) ) + + +#endif /* GLUI_INTERNAL_H */ diff --git a/Extras/glui/glui_internal_control.h b/Extras/glui/glui_internal_control.h new file mode 100644 index 000000000..e6f973556 --- /dev/null +++ b/Extras/glui/glui_internal_control.h @@ -0,0 +1,45 @@ +/* + Header file for use by GLUI controls. + Everything you need is right here. + + +*/ +#ifndef __GLUI_INTERNAL_CONTROL_H +#define __GLUI_INTERNAL_CONTROL_H + +/* This is the main GLUI external header */ +#include "GL/glui.h" + +/* Here's some utility routines */ +#include "glui_internal.h" + + +/** + A GLUI_Control-drawing sentinal object. + On creation, saves the current draw buffer and window. + On destruction, restores draw buffer and window. + This is way nicer than calling save/restore manually. +*/ +class GLUI_DrawingSentinal { + int orig_buf, orig_win; + GLUI_Control *c; +public: + /** The constructor sets up the drawing system */ + GLUI_DrawingSentinal(GLUI_Control *c_); + /** The destructor cleans up drawing back how it was */ + ~GLUI_DrawingSentinal(); + + // Do-nothing routine to avoid compiler warning about unused variable + inline void avoid_warning(void) {} +}; +/** Just drop a GLUI_DRAWINGSENTINAL_IDIOM at the start of your draw methods, +and they'll return if we can't be drawn, and +automatically save and restore all needed state. +*/ +#define GLUI_DRAWINGSENTINAL_IDIOM if (NOT can_draw()) return; GLUI_DrawingSentinal drawSentinal(this); drawSentinal.avoid_warning(); + + +/** Return the time, in seconds. */ +inline double GLUI_Time(void) {return 0.001*glutGet(GLUT_ELAPSED_TIME);} + +#endif diff --git a/Extras/glui/glui_list.cpp b/Extras/glui/glui_list.cpp new file mode 100644 index 000000000..a5b093935 --- /dev/null +++ b/Extras/glui/glui_list.cpp @@ -0,0 +1,540 @@ +/**************************************************************************** + + 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 = dynamic_cast(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(); +} diff --git a/Extras/glui/glui_listbox.cpp b/Extras/glui/glui_listbox.cpp new file mode 100644 index 000000000..3eda31079 --- /dev/null +++ b/Extras/glui/glui_listbox.cpp @@ -0,0 +1,448 @@ +/**************************************************************************** + + 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 + !dynamic_cast(GLUI_Master.curr_left_button_glut_menu) ) + 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 */ + } +} diff --git a/Extras/glui/glui_mouse_iaction.cpp b/Extras/glui/glui_mouse_iaction.cpp new file mode 100644 index 000000000..bc9f0610d --- /dev/null +++ b/Extras/glui/glui_mouse_iaction.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_mouse_iaction - GLUI Mouse Interaction 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_Mouse_Interaction::mouse_down_handler() ******/ + +int GLUI_Mouse_Interaction::mouse_down_handler( int local_x, int local_y ) +{ + /* int win_h = glutGet( GLUT_WINDOW_HEIGHT ); */ + + /* iaction_mouse_down_handler( local_x, local_y ); */ + iaction_mouse_down_handler( local_x-x_abs, local_y-y_abs ); + /*local_x-x_abs, ((glui->h-local_y)-y_abs) ); */ + redraw(); + + return false; +} + + +/**************************** GLUI_Mouse_Interaction::mouse_up_handler() */ + +int GLUI_Mouse_Interaction::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + iaction_mouse_up_handler( local_x-x_abs, local_y-y_abs, inside ); + return false; +} + + +/****************************** GLUI_Mouse_Interaction::mouse_held_down_handler() ******/ + +int GLUI_Mouse_Interaction::mouse_held_down_handler( int local_x, int local_y, + bool inside) +{ + iaction_mouse_held_down_handler( local_x-x_abs, local_y-y_abs , inside ); + + redraw(); + + /** Tell the main graphics window to update iteself **/ + if( glui ) + glui->post_update_main_gfx(); + + execute_callback(); + + return false; +} + + + +/****************************** GLUI_Mouse_Interaction::draw() **********/ + +void GLUI_Mouse_Interaction::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int text_width = string_width( this->name ); + int x_left = this->w/2 - text_width/2; + + if ( NOT draw_active_area_only ) { + draw_name( x_left, h-4 ); + draw_active_box( x_left-4, x_left+string_width( name )+4, + h, h-14 ); + } + + draw_active_area(); +} + + +/************************************ GLUI_Mouse_Interaction::update_size() **********/ + +void GLUI_Mouse_Interaction::update_size( void ) +{ + if ( NOT glui ) + return; + + int text_width = string_width( this->name ); + + if ( w < text_width+6 ) + w = text_width+6; + + if ( h - 18 > w ) + w = h - 18; + + iaction_init(); +} + + +/****************************** GLUI_Mouse_Interaction::special_handler() **********/ + +int GLUI_Mouse_Interaction::special_handler( int key,int modifiers ) +{ + int center_x, center_y; + int drag_x, drag_y; + + center_x = w/2; + center_y = (h-18)/2; + drag_x = 0; + drag_y = 0; + + if ( key == GLUT_KEY_LEFT ) + drag_x = -6; + else if ( key == GLUT_KEY_RIGHT ) + drag_x = 6; + else if ( key == GLUT_KEY_UP ) + drag_y = -6; + else if ( key == GLUT_KEY_DOWN ) + drag_y = 6; + + if ( drag_x != 0 OR drag_y != 0 ) { + mouse_down_handler( center_x, center_y ); + mouse_held_down_handler( center_x + drag_x, center_y + drag_y,true ); + mouse_up_handler( center_x + drag_x, center_y + drag_y, true ); + } + + return false; +} + + +/****************************** GLUI_Mouse_Interaction::draw_active_area() **********/ + +void GLUI_Mouse_Interaction::draw_active_area( void ) +{ + int win_h = glutGet( GLUT_WINDOW_HEIGHT ), win_w = glutGet(GLUT_WINDOW_WIDTH); + + int text_height = 18; /* what a kludge */ + + int viewport_size = h-text_height; /*MIN(w,h); */ + + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + glLoadIdentity(); + glTranslatef( (float) win_w/2.0, (float) win_h/2.0, 0.0 ); + glRotatef( 180.0, 0.0, 1.0, 0.0 ); + glRotatef( 180.0, 0.0, 0.0, 1.0 ); + glTranslatef( (float) -win_w/2.0, (float) -win_h/2.0, 0.0 ); + + glTranslatef( (float) this->x_abs + .5, (float) this->y_abs + .5, 0.0 ); + + glTranslatef( (float)this->w/2.0, (float)viewport_size/2.0 + 2.0 , 0.0 ); + + /*** Draw the interaction control's orthographic elements ***/ + iaction_draw_active_area_ortho(); + + /*** Setup and draw the interaction control's perspective elements ***/ + + /*** Set the viewport to just the square of the drawing area ***/ + /* glViewport( this->x_abs , glui->main_panel->h - this->y_abs - this->h,*/ + /*glViewport( this->x_abs+1+(this->w/2-viewport_size/2), + this->h-this->y_abs-viewport_size-1, + viewport_size, viewport_size );*/ + + viewport_size -= 4; + int offset = 0; + if ( ((this->w-viewport_size) % 2) == 1 ) + offset = 1; + + glViewport( this->x_abs + (this->w-viewport_size)/2 + offset, + win_h - this->y_abs - this->h + text_height, + viewport_size, viewport_size ); + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + double xy=1.00,zc=50.0; /* X-Y size, and Z origin */ + glFrustum( -1.0*xy, 1.0*xy, -xy, xy, zc*0.7, zc*1.3 ); + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + glLoadIdentity(); + glTranslatef( 0.0, 0.0, -zc ); + glScalef(xy,xy,1.0); // xy); + + /* glutSolidTeapot( 1.0 ); */ + iaction_draw_active_area_persp(); + + glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); + + glui->set_viewport(); + glui->set_ortho_projection(); + + glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); +} + diff --git a/Extras/glui/glui_node.cpp b/Extras/glui/glui_node.cpp new file mode 100644 index 000000000..4cfd71df7 --- /dev/null +++ b/Extras/glui/glui_node.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_node.cpp - linked-list tree structure + + + -------------------------------------------------- + + 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 "GL/glui.h" +#include "glui_internal.h" + +/********************************************* GLUI_Node::GLUI_Node() *******/ + +GLUI_Node::GLUI_Node() +: + parent_node(NULL), + child_head(NULL), + child_tail(NULL), + next_sibling(NULL), + prev_sibling(NULL) +{ +} + +/********************************************* GLUI_Node::first() *******/ +/* Returns first sibling in 'this' node's sibling list */ + +GLUI_Node *GLUI_Node::first_sibling( void ) +{ + if ( parent_node == NULL ) + return this; /* root node has no siblings */ + else + return parent_node->child_head; +} + + +/******************************************** GLUI_Node::next() ********/ +/* Returns next sibling in 'this' node's sibling list */ + +GLUI_Node *GLUI_Node::next( void ) +{ + return next_sibling; +} + + +/******************************************** GLUI_Node::prev() ********/ +/* Returns prev sibling in 'this' node's sibling list */ + +GLUI_Node *GLUI_Node::prev( void ) +{ + return prev_sibling; +} + + +/********************************************* GLUI_Node::last() *******/ +/* Returns last sibling in 'this' node's sibling list */ + +GLUI_Node *GLUI_Node::last_sibling( void ) +{ + if ( parent_node == NULL ) + return this; /* root node has no siblings */ + else + return parent_node->child_tail; +} + + +/*************************** GLUI_Node::link_this_to_parent_last() *******/ +/* Links as last child of parent */ + +void GLUI_Node::link_this_to_parent_last( GLUI_Node *new_parent ) +{ + if ( new_parent->child_tail == NULL ) { /* parent has no children */ + new_parent->child_head = this; + new_parent->child_tail = this; + this->parent_node = new_parent; + } + else { /* parent has children */ + new_parent->child_tail->next_sibling = this; + this->prev_sibling = new_parent->child_tail; + new_parent->child_tail = this; + this->parent_node = new_parent; + } +} + + +/*************************** GLUI_Node::link_this_to_parent_first() *******/ +/* Links as first child of parent */ + +void GLUI_Node::link_this_to_parent_first( GLUI_Node *new_parent ) +{ + if ( new_parent->child_head == NULL ) { /* parent has no children */ + new_parent->child_head = this; + new_parent->child_tail = this; + this->parent_node = new_parent; + } + else { /* parent has children */ + new_parent->child_head->prev_sibling = this; + this->next_sibling = new_parent->child_head; + new_parent->child_head = this; + this->parent_node = new_parent; + } +} + +/**************************** GLUI_Node::link_this_to_sibling_next() *****/ + +void GLUI_Node::link_this_to_sibling_next( GLUI_Node *sibling ) +{ + if ( sibling->next_sibling == NULL ) { /* node has no next sibling */ + sibling->next_sibling = this; + this->prev_sibling = sibling; + + /* This was the parent's last child, so update that as well */ + if ( sibling->parent_node != NULL ) { + sibling->parent_node->child_tail = this; + } + } + else { /* node already has a next sibling */ + sibling->next_sibling->prev_sibling = this; + this->next_sibling = sibling->next_sibling; + sibling->next_sibling = this; + this->prev_sibling = sibling; + } + + this->parent_node = sibling->parent_node; +} + + +/**************************** GLUI_Node::link_this_to_sibling_prev() *****/ + +void GLUI_Node::link_this_to_sibling_prev( GLUI_Node *sibling ) +{ + if ( sibling->prev_sibling == NULL ) { /* node has no prev sibling */ + sibling->prev_sibling = this; + this->next_sibling = sibling; + + /* This was the parent's first child, so update that as well */ + if ( sibling->parent_node != NULL ) { + sibling->parent_node->child_head = this; + } + } + else { /* node already has a prev sibling */ + sibling->prev_sibling->next_sibling = this; + this->prev_sibling = sibling->prev_sibling; + sibling->prev_sibling = this; + this->next_sibling = sibling; + } + + this->parent_node = sibling->parent_node; +} + +/**************************************** GLUI_Node::unlink() **************/ + +void GLUI_Node::unlink( void ) +{ + /* Unlink from prev sibling */ + if ( this->prev_sibling != NULL ) { + this->prev_sibling->next_sibling = this->next_sibling; + } + else { /* No prev sibling: this was parent's first child */ + this->parent_node->child_head = this->next_sibling; + } + + /* Unlink from next sibling */ + if ( this->next_sibling != NULL ) { + this->next_sibling->prev_sibling = this->prev_sibling; + } + else { /* No next sibling: this was parent's last child */ + this->parent_node->child_tail = this->prev_sibling; + } + + this->parent_node = NULL; + this->next_sibling = NULL; + this->prev_sibling = NULL; + this->child_head = NULL; + this->child_tail = NULL; +} + +/**************************************** GLUI_Node::dump() **************/ + +void GLUI_Node::dump( FILE *out, const char *name ) +{ + fprintf( out, "GLUI_node: %s\n", name ); + fprintf( out, " parent: %p child_head: %p child_tail: %p\n", + (void *) parent_node, + (void *) child_head, + (void *) child_tail ); + fprintf( out, " next: %p prev: %p\n", + (void *) next_sibling, + (void *) prev_sibling ); +} diff --git a/Extras/glui/glui_panel.cpp b/Extras/glui/glui_panel.cpp new file mode 100644 index 000000000..687b77971 --- /dev/null +++ b/Extras/glui/glui_panel.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_panel.cpp - GLUI_Panel 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_Panel::GLUI_Panel( GLUI_Node *parent, const char *name, int type ) +{ + common_init(); + set_name( name ); + user_id = -1; + int_val = type; + + parent->add_control( this ); +} + +/****************************** GLUI_Panel::draw() **********/ + +void GLUI_Panel::draw( int x, int y ) +{ + int top; + GLUI_DRAWINGSENTINAL_IDIOM + + if ( int_val == GLUI_PANEL_RAISED ) { + top = 0; + glLineWidth( 1.0 ); + glColor3f( 1.0, 1.0, 1.0 ); + glBegin( GL_LINE_LOOP ); + glVertex2i( 0, top ); glVertex2i( w, top ); + glVertex2i( 0, top ); glVertex2i( 0, h ); + glEnd(); + + glColor3f( .5, .5, .5 ); + glBegin( GL_LINE_LOOP ); + glVertex2i( w, top ); + glVertex2i( w, h ); + glVertex2i( 0, h ); + glVertex2i( w, h ); + glEnd(); + + /** ORIGINAL RAISED PANEL METHOD - A LITTLE TOO HIGH ** + glLineWidth(1.0); + glBegin( GL_LINES ); + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i( 1, 1 ); glVertex2i( w-2, 1 ); + glVertex2i( 1, 1 ); glVertex2i( 1, h-2 ); + + glColor3f( .5, .5, .5 ); + glVertex2i( w-1, 1 ); glVertex2i( w-1, h-1 ); + glVertex2i( 1, h-1 ); glVertex2i( w-1, h-1 ); + + glColor3f( 0.0, 0.0, 0.0 ); + glVertex2i( 0, h ); glVertex2i( w, h ); + glVertex2i( w, 0 ); glVertex2i( w, h ); + glEnd(); + + -- Touch up the lines a bit (needed in some opengl implementations + glBegin( GL_POINTS ); + glColor3f( .5, .5, .5 ); + glVertex2i( w-1, h-1 ); + glColor3f( 0.0, 0.0, 0.0 ); + glVertex2i( w, h ); + glEnd(); + **/ + } + else if ( int_val == GLUI_PANEL_EMBOSSED ) { + if ( parent_node == NULL || name == "" ) { + top = 0; + } + else { + top = GLUI_PANEL_EMBOSS_TOP; + } + + glLineWidth( 1.0 ); + glColor3f( 1.0, 1.0, 1.0 ); + glBegin( GL_LINE_LOOP ); + glVertex2i( 0, top ); glVertex2i( w, top ); + glVertex2i( w, h ); glVertex2i( 0, h ); + + glVertex2i( 1, top+1 ); glVertex2i( w-1, top+1 ); + glVertex2i( w-1, h-1 ); glVertex2i( 1, h-1 ); + glEnd(); + + glColor3f( .5, .5, .5 ); + glBegin( GL_LINE_LOOP ); + glVertex2i( 0, top ); + glVertex2i( w-1, top ); + glVertex2i( w-1, h-1 ); + glVertex2i( 0, h-1 ); + glEnd(); + + /**** Only display text in embossed panel ****/ + if ( parent_node != NULL && name != "" ) { /* Only draw non-null strings */ + int left = 7, height=GLUI_PANEL_NAME_DROP+1; + int str_width; + + str_width = string_width(name); + + if ( glui ) + glColor3ub(glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( left-3, 0 ); glVertex2i( left+str_width+3, 0 ); + glVertex2i( left+str_width+3, height ); glVertex2i( left-3, height ); + glEnd(); + + draw_name( left, GLUI_PANEL_NAME_DROP ); + } + } + + glLineWidth( 1.0 ); +} + +/****************************** GLUI_Panel::set_name() **********/ + +void GLUI_Panel::set_name( const char *new_name ) +{ + name = new_name ? new_name : ""; + + update_size(); + + if ( glui ) + glui->refresh(); +} + + +/****************************** GLUI_Panel::set_type() **********/ + +void GLUI_Panel::set_type( int new_type ) +{ + if ( new_type != int_val ) { + int_val = new_type; + update_size(); + redraw(); + } +} + + +/************************************** GLUI_Panel::update_size() **********/ + +void GLUI_Panel::update_size( void ) +{ + int text_size; + + if ( NOT glui ) + return; + + text_size = string_width(name); + + if ( w < text_size + 16 ) + w = text_size + 16 ; + + if ( name != "" AND int_val == GLUI_PANEL_EMBOSSED ) { + this->y_off_top = GLUI_YOFF + 8; + } + else { + this->y_off_top = GLUI_YOFF; + } +} diff --git a/Extras/glui/glui_radio.cpp b/Extras/glui/glui_radio.cpp new file mode 100644 index 000000000..157d18e84 --- /dev/null +++ b/Extras/glui/glui_radio.cpp @@ -0,0 +1,362 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_radio.cpp - GLUI_RadioGroup and GLUI_RadioButton control classes + + + -------------------------------------------------- + + 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" +#include + +/****************************** GLUI_RadioGroup::GLUI_RadioGroup() **********/ + +GLUI_RadioGroup::GLUI_RadioGroup(GLUI_Node *parent, + int *value_ptr, + int id, GLUI_CB cb) +{ + common_init(); + GLUI_String buf; + + set_ptr_val( value_ptr ); + if ( value_ptr ) { + int_val = *value_ptr; /** Can't call set_int_val(), b/c that + function will try to call the + callback, etc */ + /** Actually, maybe not **/ + last_live_int = *value_ptr; + } + + user_id = id; + glui_format_str( buf, "RadioGroup: %p", this ); + set_name( buf.c_str() ); + callback = cb; + + parent->add_control( this ); + + init_live(); +} + + +/****************************** GLUI_RadioGroup::draw() **********/ + +void GLUI_RadioGroup::draw( int x, int y ) +{ + if ( NOT can_draw() ) + return; + + draw_group(false); +} + + +/********************* GLUI_RadioGroup::draw_group(int translate) **********/ + +void GLUI_RadioGroup::draw_group( int translate ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + GLUI_RadioButton *button; + this->int_val = int_val; + + glMatrixMode(GL_MODELVIEW ); + + button = (GLUI_RadioButton*) first_child(); + while( button != NULL ) { + glPushMatrix(); + if (translate) { + button->translate_to_origin(); + } + else { + glTranslatef(button->x_abs-x_abs, + button->y_abs-y_abs,0.0); + } + + if ( button->int_val ) + button->draw_checked(); + else + button->draw_unchecked(); + + glPopMatrix(); + + button = (GLUI_RadioButton*) button->next(); + } +} + + +/****************************** GLUI_RadioGroup::set_name() **********/ + +void GLUI_RadioGroup::set_name( const char *text ) +{ + name = text; + + if ( glui ) + glui->refresh(); +} + + +/********************************* GLUI_RadioGroup::set_selected() **********/ + +void GLUI_RadioGroup::set_selected( int int_val ) +{ + GLUI_RadioButton *button; + + this->int_val = int_val; + + button = (GLUI_RadioButton*) first_child(); + while( button != NULL ) { + if ( int_val == -1 ) { /*** All buttons in group are deselected ***/ + button->set_int_val(0); + } + else if ( int_val == button->user_id ) { /*** This is selected button ***/ + button->set_int_val(1); + } + else { /*** This is NOT selected button ***/ + button->set_int_val(0); + + } + button = (GLUI_RadioButton*) button->next(); + } + redraw(); +} + + +/************************ GLUI_RadioButton::GLUI_RadioButton() **********/ + +GLUI_RadioButton::GLUI_RadioButton( GLUI_RadioGroup *grp, const char *name ) +{ + common_init(); + + set_int_val( 0 ); + + /** A radio button's user id is always its ordinal number (zero-indexed) + within the group */ + user_id = grp->num_buttons; + set_name( name ); + group = grp; + + group->num_buttons++; /* Increments radiogroup's button count */ + group->add_control( this ); + + /*** Now update button states ***/ + group->set_int_val( group->int_val ); /* This tells the group to + reset itself to its + current value, thereby + updating all its buttons */ +} + + +/************************ GLUI_RadioButton::mouse_down_handler() **********/ + +int GLUI_RadioButton::mouse_down_handler( int local_x, int local_y ) +{ + if ( NOT group ) + return false; + + orig_value = group->int_val; + + currently_inside = true; + + group->set_selected( this->user_id ); + redraw(); + + return false; +} + +/********************** GLUI_RadioButton::mouse_held_down_handler() ******/ + +int GLUI_RadioButton::mouse_held_down_handler( int local_x, int local_y, + bool inside) +{ + if (inside != currently_inside) { + if (inside) group->set_selected( this->user_id ); + else group->set_selected( orig_value ); + currently_inside = inside; + redraw(); + } + + return false; +} + + +/*************************** GLUI_RadioButton::mouse_up_handler() **********/ + +int GLUI_RadioButton::mouse_up_handler( int local_x, int local_y, + bool inside ) +{ + if ( NOT group ) + return false; + + if ( NOT inside ) { + group->set_selected( orig_value ); + redraw(); + } + else { + /** Now we update the radio button group. We tell the group + handler to set the currently-selected item to this button, which + is reference by its user_id/ordinal number within group **/ + + group->set_selected( this->user_id ); + redraw(); + + /*** Now update the linked variable, and call the callback, + but ONLY if the value of the radio group actually changed ***/ + if ( group->int_val != orig_value ) { + group->output_live(true); /** Output live and update gfx ***/ + + group->execute_callback(); + } + } + + return false; +} + +/****************************** GLUI_RadioButton::draw() **********/ + +void GLUI_RadioButton::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + if ( NOT group OR NOT can_draw() ) + return; + + /*** See if we're the currently-selected button. If so, draw ***/ + if ( group->int_val == this->user_id ) { + if ( enabled ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_ON, 0, 0 ); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_ON_DIS, 0, 0 ); + } + else { + if ( enabled ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_OFF, 0, 0 ); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_OFF_DIS, 0, 0 ); + } + + draw_active_area(); + + draw_name( text_x_offset, 10 ); +} + + +/************************************ GLUI_RadioButton::draw_checked() ******/ + +void GLUI_RadioButton::draw_checked( void ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + if ( enabled ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_ON, 0, 0 ); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_ON_DIS, 0, 0 ); + draw_active_area(); +} + + +/*********************************** GLUI_RadioButton::draw_unchecked() ******/ + +void GLUI_RadioButton::draw_unchecked( void ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + if ( enabled ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_OFF, 0, 0 ); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_OFF_DIS, 0, 0 ); + draw_active_area(); +} + + +/**************************************** GLUI_RadioButton::draw_O() ********/ + +void GLUI_RadioButton::draw_O( void ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int i, j; + + glBegin( GL_POINTS ); + for(i=3; i<=GLUI_RADIOBUTTON_SIZE-3; i++ ) + for(j=3; j<=GLUI_RADIOBUTTON_SIZE-3; j++ ) + glVertex2i(i,j); + glEnd(); +} + + +/******************************** GLUI_RadioButton::update_size() **********/ + +void GLUI_RadioButton::update_size( void ) +{ + int text_size; + + if ( NOT glui ) + return; + + text_size = _glutBitmapWidthString( glui->font, name.c_str() ); + + /* if ( w < text_x_offset + text_size + 6 ) */ + w = text_x_offset + text_size + 6 ; +} + + +/************************* GLUI_RadioButton::draw_active_area() **************/ + +void GLUI_RadioButton::draw_active_area( void ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int text_width, left, right; + + text_width = _glutBitmapWidthString( glui->font, name.c_str() ); + left = text_x_offset-3; + right = left + 7 + text_width; + + if ( active ) { + glEnable( GL_LINE_STIPPLE ); + glLineStipple( 1, 0x5555 ); + glColor3f( 0., 0., 0. ); + } else { + glColor3ub( glui->bkgd_color.r, glui->bkgd_color.g, glui->bkgd_color.b ); + } + + glBegin( GL_LINE_LOOP ); + glVertex2i(left,0); glVertex2i( right,0); + glVertex2i(right,h+1); glVertex2i( left,h+1); + glEnd(); + + glDisable( GL_LINE_STIPPLE ); +} + + +/********************************* GLUI_RadioGroup::set_int_val() **********/ + +void GLUI_RadioGroup::set_int_val( int new_val ) +{ + if ( new_val == int_val ) + return; + + set_selected( new_val ); + redraw(); + + output_live(true); + +} diff --git a/Extras/glui/glui_rollout.cpp b/Extras/glui/glui_rollout.cpp new file mode 100644 index 000000000..f0aa7fc4e --- /dev/null +++ b/Extras/glui/glui_rollout.cpp @@ -0,0 +1,275 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_panel.cpp - GLUI_Panel 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" + +enum {rollout_height_pixels=GLUI_DEFAULT_CONTROL_HEIGHT + 7}; + +/****************************** GLUI_Rollout::GLUI_Rollout() **********/ + +GLUI_Rollout::GLUI_Rollout( GLUI_Node *parent, const char *name, + int open, int type ) +{ + common_init(); + set_name( name ); + user_id = -1; + int_val = type; + + if ( NOT open ) { + is_open = false; + h = rollout_height_pixels; + } + + parent->add_control( this ); +} + +/****************************** GLUI_Rollout::open() **********/ + +void GLUI_Rollout::open( void ) +{ + if ( NOT glui ) + return; + + if ( is_open ) + return; + is_open = true; + + GLUI_DRAWINGSENTINAL_IDIOM + + /* Copy hidden children into our private list "collapsed_node" */ + child_head = collapsed_node.child_head; + child_tail = collapsed_node.child_tail; + collapsed_node.child_head = NULL; + collapsed_node.child_tail = NULL; + + if ( child_head != NULL ) { + ((GLUI_Control*) child_head)->unhide_internal( true ); + } + + glui->refresh(); +} + + +/****************************** GLUI_Rollout::close() **********/ + +void GLUI_Rollout::close( void ) +{ + if ( NOT glui ) + return; + + if ( NOT is_open ) + return; + is_open = false; + + GLUI_DRAWINGSENTINAL_IDIOM + + if ( child_head != NULL ) { + ((GLUI_Control*) child_head)->hide_internal( true ); + } + + /* Move all children into a private list of hidden children */ + collapsed_node.child_head = first_child(); + collapsed_node.child_tail = last_child(); + child_head = NULL; + child_tail = NULL; + + this->h = rollout_height_pixels; + + glui->refresh(); +} + + +/**************************** GLUI_Rollout::mouse_down_handler() **********/ + + +int GLUI_Rollout::mouse_down_handler( int local_x, int local_y ) +{ + if ( local_y - y_abs > rollout_height_pixels ) { + initially_inside = currently_inside = false; + return false; + } + + currently_inside = true; + initially_inside = true; + redraw(); + + return false; +} + + +/**************************** GLUI_Rollout::mouse_held_down_handler() ****/ + +int GLUI_Rollout::mouse_held_down_handler( + int local_x, int local_y, + bool new_inside ) +{ + if ( NOT initially_inside ) + return false; + + if ( local_y - y_abs> rollout_height_pixels ) + new_inside = false; + + if (new_inside != currently_inside) { + currently_inside = new_inside; + redraw(); + } + + return false; +} + + +/**************************** GLUI_Rollout::mouse_down_handler() **********/ + +int GLUI_Rollout::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + if ( currently_inside ) { + if ( is_open ) + close(); + else + open(); + } + + currently_inside = false; + initially_inside = false; + redraw(); + + return false; +} + + +/********************************* GLUI_Rollout::draw() ***********/ + +void GLUI_Rollout::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + int left, right, top, bottom; + + left = 5; + right = w-left; + top = 3; + bottom = 3+16; + + if ( is_open ) + draw_emboss_box( 0, w, top+3, h ); + else + draw_emboss_box( 0, w, top+3, h-7 ); + + glui->draw_raised_box( left, top, w-left*2, 16 ); + + if ( glui ) + glColor3ub(glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( left+1, top+1 ); glVertex2i( right-1, top+1 ); + glVertex2i( right-1, bottom-1 ); glVertex2i( left+1, bottom-1 ); + glEnd(); + + draw_name( left+8, top+11 ); + + if ( active ) + /*draw_active_box( left+4, left+string_width( name.c_str() )+12, */ + draw_active_box( left+4, right-17, + top+2, bottom-2 ); + + + /** Draw '+' or '-' **/ + + glBegin( GL_LINES ); + if ( is_open ) { + if ( enabled ) glColor3f( 0.0, 0.0, 0.0 ); + else glColor3f( 0.5, 0.5, 0.5 ); + glVertex2i(right-14,(top+bottom)/2); glVertex2i(right-5,(top+bottom)/2); + + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i(right-14,1+(top+bottom)/2);glVertex2i(right-5,1+(top+bottom)/2); + } + else + { + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i(right-9,top+3); glVertex2i(right-9,bottom-4); + glVertex2i(right-14,(top+bottom)/2); glVertex2i(right-5,(top+bottom)/2); + + if ( enabled ) glColor3f( 0.0, 0.0, 0.0 ); + else glColor3f( 0.5, 0.5, 0.5 ); + glVertex2i(right-14,-1+(top+bottom)/2); + glVertex2i(right-5,-1+(top+bottom)/2); + glVertex2i(right-10,top+3); + glVertex2i(right-10,bottom-4); + } + glEnd(); + + glLineWidth( 1.0 ); + + if (currently_inside) {draw_pressed(); /* heavy black outline when pressed */ } +} + + +/***************************** GLUI_Rollout::update_size() **********/ + +void GLUI_Rollout::update_size( void ) +{ + int text_size; + + if ( NOT glui ) + return; + + text_size = string_width(name); + + if ( w < text_size + 36 ) + w = text_size + 36; +} + + +/**************************** GLUI_Rollout::draw_pressed() ***********/ + +void GLUI_Rollout::draw_pressed( void ) +{ + int left, right, top, bottom; + + left = 5; + right = w-left; + top = 3; + bottom = 3+16; + + + glColor3f( 0.0, 0.0, 0.0 ); + + glBegin( GL_LINE_LOOP ); + glVertex2i( left, top ); glVertex2i( right, top ); + glVertex2i( right, bottom ); glVertex2i( left,bottom ); + glEnd(); + + glBegin( GL_LINE_LOOP ); + glVertex2i( left+1, top+1 ); glVertex2i( right-1, top+1 ); + glVertex2i( right-1, bottom-1 ); glVertex2i( left+1,bottom-1 ); + glEnd(); +} diff --git a/Extras/glui/glui_rotation.cpp b/Extras/glui/glui_rotation.cpp new file mode 100644 index 000000000..156543763 --- /dev/null +++ b/Extras/glui/glui_rotation.cpp @@ -0,0 +1,473 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_rotation - GLUI_Rotation 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 "GL/glui.h" +#include "arcball.h" +#include "algebra3.h" + +/*************************** GLUI_Rotation::iaction_mouse_down_handler() ***/ + +int GLUI_Rotation::iaction_mouse_down_handler( int local_x, int local_y ) +{ + copy_float_array_to_ball(); + + init_ball(); + + local_y = (int) floor(2.0 * ball->center[1] - local_y); + + ball->mouse_down( local_x, local_y ); + + /* printf( "%d %d - %f %f\n", local_x, local_y, ball->center[0], ball->center[1] ); */ + + copy_ball_to_float_array(); + + spinning = false; + + return false; +} + + +/*********************** GLUI_Rotation::iaction_mouse_up_handler() **********/ + +int GLUI_Rotation::iaction_mouse_up_handler( int local_x, int local_y, + bool inside ) +{ + copy_float_array_to_ball(); + + ball->mouse_up(); + + return false; +} + + +/******************* GLUI_Rotation::iaction_mouse_held_down_handler() ******/ + +int GLUI_Rotation::iaction_mouse_held_down_handler( int local_x, int local_y, + bool inside) +{ + if ( NOT glui ) + return 0; + + copy_float_array_to_ball(); + + local_y = (int) floor(2.0 * ball->center[1] - local_y); + + /* printf( "%d %d\n", local_x, local_y ); */ + + ball->mouse_motion( local_x, local_y, 0, + (glui->curr_modifiers & GLUT_ACTIVE_ALT) != 0, + (glui->curr_modifiers & GLUT_ACTIVE_CTRL) != 0 ); + + copy_ball_to_float_array(); + + if ( can_spin ) + spinning = true; + + return false; +} + + +/******************** GLUI_Rotation::iaction_draw_active_area_persp() **************/ + +void GLUI_Rotation::iaction_draw_active_area_persp( void ) +{ + /********** arcball *******/ + copy_float_array_to_ball(); + + setup_texture(); + setup_lights(); + + glEnable(GL_CULL_FACE ); + + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + + mat4 tmp_rot = *ball->rot_ptr; + glMultMatrixf( (float*) &tmp_rot[0][0] ); + + /*** Draw the checkered box ***/ + /*glDisable( GL_TEXTURE_2D ); */ + draw_ball(1.35); // 1.96 ); + + glPopMatrix(); + + glBindTexture(GL_TEXTURE_2D,0); /* unhook our checkerboard texture */ + glDisable( GL_TEXTURE_2D ); + glDisable( GL_LIGHTING ); + glDisable( GL_CULL_FACE ); +} + + +/******************** GLUI_Rotation::iaction_draw_active_area_ortho() **********/ + +void GLUI_Rotation::iaction_draw_active_area_ortho( void ) +{ + float radius; + radius = (float)(h-22)/2.0; /*MIN((float)w/2.0, (float)h/2.0); */ + + /********* Draw emboss circles around arcball control *********/ + int k; + glLineWidth( 1.0 ); + glBegin( GL_LINE_LOOP); + for( k=0; k<60; k++ ) { + float phi = 2*M_PI*(float)k/60.0; + vec2 p( cos(phi) * (2.0 + radius), sin(phi) * (2.0 + radius)); + if ( p[1] < -p[0] ) glColor3ub( 128,128,128 ); + else glColor3ub( 255,255,255 ); + glVertex2fv((float*)&p[0]); + } + glEnd(); + + glBegin( GL_LINE_LOOP); + for( k=0; k<60; k++ ) { + float phi = 2*M_PI*(float)k/60.0; + vec2 p( cos(phi) * (1.0 + radius), sin(phi) * (1.0 + radius)); + if ( enabled ) { + if ( p[1] < -p[0] ) glColor3ub( 0,0,0); + else glColor3ub( 192,192,192); + } + else + { + if ( p[1] < -p[0] ) glColor3ub( 180,180,180); + else glColor3ub( 192,192,192); + } + glVertex2fv((float*)&p[0]); + } + glEnd(); +} + + +/******************************** GLUI_Rotation::iaction_dump() **********/ + +void GLUI_Rotation::iaction_dump( FILE *output ) +{ +} + + +/******************** GLUI_Rotation::iaction_special_handler() **********/ + +int GLUI_Rotation::iaction_special_handler( int key,int modifiers ) +{ + + return false; +} + +/********************************** GLUI_Rotation::init_ball() **********/ + +void GLUI_Rotation::init_ball( void ) +{ + /*printf( "%f %f %f", float( MIN(w/2,h/2)), (float) w/2, (float) h/2 ); */ + + ball->set_params( vec2( (float)(w/2), (float)((h-18)/2)), + (float) 2.0*(h-18) ); + /*ball->set_damping( .05 ); */ + /*float( MIN(w/2,h/2))*2.0 ); */ + /* ball->reset_mouse(); */ +} + + +/****************************** GLUI_Rotation::setup_texture() *********/ + +void GLUI_Rotation::setup_texture( void ) +{ + static GLuint tex=0u; + GLenum t=GL_TEXTURE_2D; + glEnable(t); + glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + glColor3f( 1.0, 1.0, 1.0 ); + if (tex!=0u) { + /* (OSL 2006/06) Just use glBindTexture to avoid having to re-upload the whole checkerboard every frame. */ + glBindTexture(t,tex); + return; + } /* Else need to make a new checkerboard texture */ + glGenTextures(1,&tex); + glBindTexture(t,tex); + glEnable(t); + + unsigned int i, j; + int dark, light; /*** Dark and light colors for ball checkerboard ***/ + +/* Note: you can change the number of checkers across there sphere in draw_ball */ +#define CHECKBOARD_SIZE 64 /* pixels across whole texture */ +#define CHECKBOARD_REPEAT 32u /* pixels across one black/white sector */ + unsigned char texture_image[CHECKBOARD_SIZE] [CHECKBOARD_SIZE] [3]; + unsigned char c; + for( i=0; iinit(); /** reset quaternion, etc. **/ + ball->set_params( vec2( (float)(w/2), (float)((h-18)/2)), + (float) 2.0*(h-18) ); + + set_spin( this->damping ); + + copy_ball_to_float_array(); + + translate_and_draw_front(); + + output_live(true); /*** Output live and draw main grx window ***/ +} + + +/****************************** GLUI_Rotation::needs_idle() *********/ + +bool GLUI_Rotation::needs_idle( void ) const +{ + return can_spin; +} + + +/****************************** GLUI_Rotation::idle() ***************/ + +void GLUI_Rotation::idle( void ) +{ + spinning = ball->is_spinning?true:false; + + if ( can_spin AND spinning ) { + copy_float_array_to_ball(); + ball->idle(); + + *ball->rot_ptr = *ball->rot_ptr * ball->rot_increment; + + mat4 tmp_rot; + tmp_rot = *ball->rot_ptr; + + copy_ball_to_float_array(); + + draw_active_area_only = true; + translate_and_draw_front(); + draw_active_area_only = false; + + output_live(true); /** output live and update gfx **/ + } + else { + } +} + + +/********************** GLUI_Rotation::copy_float_array_to_ball() *********/ + +void GLUI_Rotation::copy_float_array_to_ball( void ) +{ + int i; + float *fp_src, *fp_dst; + + fp_src = &float_array_val[0]; + fp_dst = &((*ball->rot_ptr)[0][0]); + + for( i=0; i<16; i++ ) { + *fp_dst = *fp_src; + + fp_src++; + fp_dst++; + } +} + + +/********************** GLUI_Rotation::copy_ball_to_float_array() *********/ + +void GLUI_Rotation::copy_ball_to_float_array( void ) +{ + mat4 tmp_rot; + tmp_rot = *ball->rot_ptr; + + set_float_array_val( (float*) &tmp_rot[0][0] ); +} + + +/************************ GLUI_Rotation::set_spin() **********************/ + +void GLUI_Rotation::set_spin( float damp_factor ) +{ + if ( damp_factor == 0.0 ) + can_spin = false; + else + can_spin = true; + + ball->set_damping( 1.0 - damp_factor ); + + this->damping = damp_factor; +} + + +/************** GLUI_Rotation::GLUI_Rotation() ********************/ + +GLUI_Rotation::GLUI_Rotation( GLUI_Node *parent, + const char *name, float *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(); + + /*** Init the live 4x4 matrix. This is different than the standard + live variable behavior, since the original value of the 4x4 matrix + is ignored and reset to Identity ***/ +/* +NO! WVB + if ( value_ptr != NULL ) { + int i, j, index; + for( i=0; i<4; i++ ) { + for( j=0; j<4; j++ ) { + index = i*4+j; + if ( i==j ) + value_ptr[index] = 1.0; + else + value_ptr[index] = 0.0; + } + } + } +*/ + /*init_ball(); */ + + +} + + +/************** GLUI_Rotation::common_init() ********************/ + +void GLUI_Rotation::common_init( void ) +{ + glui_format_str( name, "Rotation: %p", this ); +// type = GLUI_CONTROL_ROTATION; + w = GLUI_ROTATION_WIDTH; + h = GLUI_ROTATION_HEIGHT; + can_activate = true; + live_type = GLUI_LIVE_FLOAT_ARRAY; + float_array_size = 16; + quadObj = NULL; + alignment = GLUI_ALIGN_CENTER; + can_spin = false; + spinning = false; + damping = 0.0; + ball = new Arcball; + + reset(); +} diff --git a/Extras/glui/glui_scrollbar.cpp b/Extras/glui/glui_scrollbar.cpp new file mode 100644 index 000000000..9540d4079 --- /dev/null +++ b/Extras/glui/glui_scrollbar.cpp @@ -0,0 +1,832 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_scrollbar.cpp - GLUI_Scrollbar class + + -------------------------------------------------- + + Copyright (c) 2004 John Kew, 1998 Paul Rademacher + + 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 + +/*static int __debug=0; */ + +#define GLUI_SCROLL_GROWTH_STEPS 800 +#define GLUI_SCROLL_MIN_GROWTH_STEPS 100 +#define GLUI_SCROLL_CALLBACK_INTERVAL 1 /* Execute the user's callback every this many clicks */ + +enum { + GLUI_SCROLL_ARROW_UP, + GLUI_SCROLL_ARROW_DOWN, + GLUI_SCROLL_ARROW_LEFT, + GLUI_SCROLL_ARROW_RIGHT +}; + + +/****************************** GLUI_Scrollbar::GLUI_Scrollbar() **********/ +// Constructor, no live var +GLUI_Scrollbar::GLUI_Scrollbar( GLUI_Node *parent, + const char *name, + int horz_vert, + int data_type, + int id, GLUI_CB callback + /*,GLUI_Control *object + ,GLUI_InterObject_CB obj_cb*/ + ) +{ + common_construct(parent, name, horz_vert, data_type, NULL, id, callback/*, object, obj_cb*/); +} + +/****************************** GLUI_Scrollbar::GLUI_Scrollbar() **********/ +// Constructor, int live var +GLUI_Scrollbar::GLUI_Scrollbar( GLUI_Node *parent, const char *name, + int horz_vert, + int *live_var, + int id, GLUI_CB callback + /*,GLUI_Control *object + ,GLUI_InterObject_CB obj_cb*/ + ) +{ + common_construct(parent, name, horz_vert, GLUI_SCROLL_INT, live_var, id, callback/*, object, obj_cb*/); +} + +/****************************** GLUI_Scrollbar::GLUI_Scrollbar() **********/ +// Constructor, float live var +GLUI_Scrollbar::GLUI_Scrollbar( GLUI_Node *parent, const char *name, + int horz_vert, + float *live_var, + int id, GLUI_CB callback + /*,GLUI_Control *object + ,GLUI_InterObject_CB obj_cb*/ + ) +{ + common_construct(parent, name, horz_vert, GLUI_SCROLL_FLOAT, live_var, id, callback/*, object, obj_cb*/); +} + +/****************************** GLUI_Scrollbar::common_init() **********/ +void GLUI_Scrollbar::common_init(void) +{ + horizontal = true; + h = GLUI_SCROLL_ARROW_HEIGHT; + w = GLUI_TEXTBOX_WIDTH; + alignment = GLUI_ALIGN_CENTER; + x_off = 0; + y_off_top = 0; + y_off_bot = 0; + can_activate = true; + state = GLUI_SCROLL_STATE_NONE; + growth_exp = GLUI_SCROLL_DEFAULT_GROWTH_EXP; + callback_count = 0; + first_callback = true; + user_speed = 1.0; + float_min = 0.0; + float_max = 0.0; + int_min = 0; + int_max = 0; + associated_object = NULL; + last_update_time=0; + velocity_limit=50.0; /* Change value by at most 50 per second */ + box_length = 0; + box_start_position = 0; + box_end_position = 0; + track_length = 0; +} + +/****************************** GLUI_Scrollbar::common_construct() **********/ +void GLUI_Scrollbar::common_construct( + GLUI_Node *parent, + const char *name, + int horz_vert, + int data_type, + void *data, + int id, GLUI_CB callback + /*,GLUI_Control *object, + GLUI_InterObject_CB obj_cb*/ + ) +{ + common_init(); + + // make sure limits are wide enough to hold live value + if (data_type==GLUI_SCROLL_FLOAT) { + float lo = 0.0f, hi=1.0f; + if (data) { + float d = *(float*)(data); + lo = MIN(lo, d); + hi = MAX(hi, d); + } + this->set_float_limits(lo,hi); + this->set_float_val(lo); + this->live_type = GLUI_LIVE_FLOAT; + } else { + int lo = 0, hi=100; + if (data) { + int d = *(int*)(data); + lo = MIN(lo, d); + hi = MAX(hi, d); + } + this->set_int_limits(lo,hi); + this->set_int_val(0); + this->live_type = GLUI_LIVE_INT; + } + this->data_type = data_type; + this->set_ptr_val( data ); + this->set_name(name); + this->user_id = id; + this->callback = callback; + //this->associated_object = object; + //this->object_cb = obj_cb; + this->horizontal=(horz_vert==GLUI_SCROLL_HORIZONTAL); + if (this->horizontal) { + this->h = GLUI_SCROLL_ARROW_HEIGHT; + this->w = GLUI_TEXTBOX_WIDTH; + } else { + this->h = GLUI_TEXTBOX_HEIGHT; + this->w = GLUI_SCROLL_ARROW_WIDTH; + } + parent->add_control( this ); + this->init_live(); +} + +/****************************** GLUI_Scrollbar::mouse_down_handler() **********/ + +int GLUI_Scrollbar::mouse_down_handler( int local_x, int local_y ) +{ + last_update_time=GLUI_Time()-1.0; + this->state = find_arrow( local_x, local_y ); + GLUI_Master.glui_setIdleFuncIfNecessary(); + + /* printf( "spinner: mouse down : %d/%d arrow:%d\n", local_x, local_y, + find_arrow( local_x, local_y )); + */ + + if ( state != GLUI_SCROLL_STATE_UP AND state != GLUI_SCROLL_STATE_DOWN) + return true; + + reset_growth(); + + /*** ints and floats behave a bit differently. When you click on + an int spinner, you expect the value to immediately go up by 1, whereas + for a float it'll go up only by a fractional amount. Therefore, we + go ahead and increment by one for int spinners ***/ +#if 1 + if ( data_type == GLUI_SCROLL_INT ) { + // Allow for possibility of reversed limits + int lo = MIN(int_min,int_max); + int hi = MAX(int_min,int_max); + int increase = int_min < int_max ? 1 : -1; + int new_val = int_val; + if ( state == GLUI_SCROLL_STATE_UP ) { + new_val += increase; + } else if ( state == GLUI_SCROLL_STATE_DOWN ) { + new_val -= increase; + } + if (new_val >= lo && new_val <= hi && new_val!=int_val) { + set_int_val(new_val); + do_callbacks(); + } + } +#endif + do_click(); + redraw(); + + return false; +} + + +/******************************** GLUI_Scrollbar::mouse_up_handler() **********/ + +int GLUI_Scrollbar::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + state = GLUI_SCROLL_STATE_NONE; + GLUI_Master.glui_setIdleFuncIfNecessary(); + + /* printf("spinner: mouse up : %d/%d inside: %d\n",local_x,local_y,inside); */ + + /*glutSetCursor( GLUT_CURSOR_INHERIT ); */ + glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); + + redraw(); + + /* do_callbacks(); --- stub */ + /* if ( callback ) */ + /* callback( this->user_id ); */ + + return false; +} + + +/***************************** GLUI_Scrollbar::mouse_held_down_handler() ******/ + +int GLUI_Scrollbar::mouse_held_down_handler( int local_x, int local_y, + bool new_inside) +{ + int new_state; + if ( state == GLUI_SCROLL_STATE_NONE ) + return false; + + /* printf("spinner: mouse held: %d/%d inside: %d\n",local_x,local_y, + new_inside); + */ + + if ( state == GLUI_SCROLL_STATE_SCROLL) { /* dragging? */ + do_drag( local_x-x_abs, local_y-y_abs ); + } + else { /* not dragging */ + new_state = find_arrow( local_x, local_y ); + + if ( new_state == state ) { + /** Still in same arrow **/ + do_click(); + } + } + redraw(); + + return false; +} + + +/****************************** GLUI_Scrollbar::key_handler() **********/ + +int GLUI_Scrollbar::key_handler( unsigned char key,int modifiers ) +{ + return true; +} + + +/****************************** GLUI_Scrollbar::draw() **********/ + +void GLUI_Scrollbar::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + if ( horizontal ) { + draw_scroll_arrow(GLUI_SCROLL_ARROW_LEFT, 0, 0); + draw_scroll_arrow(GLUI_SCROLL_ARROW_RIGHT, w-GLUI_SCROLL_ARROW_WIDTH, 0); + } else { + draw_scroll_arrow(GLUI_SCROLL_ARROW_UP, 0, 0); + draw_scroll_arrow(GLUI_SCROLL_ARROW_DOWN, 0, h-GLUI_SCROLL_ARROW_HEIGHT); + } + draw_scroll(); +} + + +/****************************** GLUI_Scrollbar::draw_scroll_arrow() **********/ + +void GLUI_Scrollbar::draw_scroll_arrow(int arrowtype, int x, int y) +{ + float offset=0; + float L=3.5f,HC=7.f,R=10.5f; + float T=4.5f,VC=8.f,B=11.5; + const float verts[][6]={ + { L,10.5f, R, 10.5f, HC, 6.5f }, // up arrow + { L,6.5f, R, 6.5f, HC,10.5f }, // down arrow + { R-2,T, R-2, B, L+1, VC }, // left arrow + { L+2,T, L+2, B, R-1, VC } // right arrow + }; + + const float *tri = NULL; + + switch (arrowtype) + { + case GLUI_SCROLL_ARROW_UP: + tri = verts[0]; + if (state & GLUI_SCROLL_STATE_UP) offset = 1; + break; + + case GLUI_SCROLL_ARROW_DOWN: + tri = verts[1]; + if (state & GLUI_SCROLL_STATE_DOWN) offset = 1; + break; + + case GLUI_SCROLL_ARROW_LEFT: + tri = verts[2]; + if (state & GLUI_SCROLL_STATE_DOWN) offset = 1; + break; + + case GLUI_SCROLL_ARROW_RIGHT: + tri = verts[3]; + if (state & GLUI_SCROLL_STATE_UP) offset = 1; + break; + + default: + return; /* tri is NULL */ + } + + glColor3ubv(&glui->bkgd_color.r); + glRecti(x,y,x+GLUI_SCROLL_ARROW_WIDTH,y+GLUI_SCROLL_ARROW_HEIGHT); + if (!offset) { + glui->draw_raised_box(x,y+1,GLUI_SCROLL_ARROW_WIDTH-1,GLUI_SCROLL_ARROW_HEIGHT-1); + } else { + glColor3ub(128,128,128); + glBegin(GL_LINE_LOOP); + int x2=x+GLUI_SCROLL_ARROW_WIDTH, y2=y+GLUI_SCROLL_ARROW_HEIGHT; + glVertex2i(x ,y); + glVertex2i(x2,y); + glVertex2i(x2,y2); + glVertex2i(x ,y2); + glEnd(); + } + + GLubyte black[]={0,0,0}; + GLubyte white[]={255,255,255}; + GLubyte gray[]={128,128,128}; + GLubyte *color=black; + if (!enabled) { + offset = 1; + color = white; + } + glTranslatef(x+offset,y+offset,0); + glColor3ubv(color); + glBegin(GL_TRIANGLES); + glVertex2fv(tri); glVertex2fv(tri+2), glVertex2fv(tri+4); + glEnd(); + glTranslatef(-(x+offset),-(y+offset),0); + + if (!enabled) { // once more! + glTranslatef(x,y,0); + glColor3ubv(gray); + glBegin(GL_TRIANGLES); + glVertex2fv(tri); glVertex2fv(tri+2), glVertex2fv(tri+4); + glEnd(); + glTranslatef(-x,-y,0); + } +} + + +void GLUI_Scrollbar::draw_scroll() { + update_scroll_parameters(); + + // Draw track using a checkerboard background + const unsigned char scroll_bg[] = { + 0xD4, 0xD0, 0xC8, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xD4, 0xD0, 0xC8 + }; + glColor3f( 1.0, 1.0, 1.0 ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glEnable( GL_TEXTURE_2D); + glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, + scroll_bg); + + float y0 = horizontal? 0 : GLUI_SCROLL_ARROW_HEIGHT; + float y1 = horizontal? h : h-GLUI_SCROLL_ARROW_HEIGHT; + float x0 = horizontal? GLUI_SCROLL_ARROW_WIDTH : 0; + float x1 = horizontal? w-GLUI_SCROLL_ARROW_WIDTH : w; + x0-=0.5; y0+=0.5; + x1-=0.5; y1+=0.5; + float dy = y1-y0; + float dx = x1-x0; + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(x0,y0); + glTexCoord2f(dx*0.5f,0); glVertex2f(x1,y0); + glTexCoord2f(dx*0.5f,dy*0.5f); glVertex2f(x1,y1); + glTexCoord2f(0, dy*0.5f); glVertex2f(x0,y1); + glEnd(); + glDisable(GL_TEXTURE_2D); + + // Draw scroll box + int box = box_start_position; + if (horizontal) { + box += GLUI_SCROLL_ARROW_WIDTH; + draw_scroll_box(box,1,box_length,h); + } else { + box += GLUI_SCROLL_ARROW_HEIGHT+1; + draw_scroll_box(0,box,w,box_length); + } +} + +/****************************** GLUI_Scrollbar::draw_scroll_box() **********/ + +void GLUI_Scrollbar::draw_scroll_box(int x, int y, int w, int h) +{ + if (!enabled) return; + glColor3ubv(&glui->bkgd_color.r); + glRecti(x,y,x+w,y+h); + glui->draw_raised_box(x,y, w-1, h-1); + + if (active) { + glEnable( GL_LINE_STIPPLE ); + glLineStipple( 1, 0x5555 ); + glColor3f( 0., 0., 0. ); + glBegin(GL_LINE_LOOP); + int x1 = x+2, y1 = y+2, x2 = x+w-4, y2 = y+h-4; + glVertex2i(x1,y1); + glVertex2i(x2,y1); + glVertex2i(x2,y2); + glVertex2i(x1,y2); + glEnd(); + glDisable( GL_LINE_STIPPLE ); + } +} + + + +/**************************** update_scroll_parameters ***********/ + +void GLUI_Scrollbar::update_scroll_parameters() { + track_length = horizontal? + this->w-GLUI_SCROLL_ARROW_WIDTH*2 : + this->h-GLUI_SCROLL_ARROW_HEIGHT*2; + if (data_type==GLUI_SCROLL_INT) + { + if (int_max==int_min) + box_length=track_length; + else { + const int MIN_TAB = GLUI_SCROLL_BOX_STD_HEIGHT; + //box_length = int(track_length/float(visible_range)); + //if (box_length < MIN_TAB) + box_length = MIN_TAB; + } + float pixels_per_unit = (track_length-box_length)/float(int_max-int_min); + if (horizontal) + box_start_position = int((int_val-int_min)*pixels_per_unit); + else + box_start_position = int((int_max-int_val)*pixels_per_unit); + box_end_position = box_start_position+box_length; + } + else if (data_type==GLUI_SCROLL_FLOAT) + { + if (float_max==float_min) + box_length=track_length; + else { + box_length = GLUI_SCROLL_BOX_STD_HEIGHT; + } + float pixels_per_unit = (track_length-box_length)/float(float_max-float_min); + if (horizontal) + box_start_position = int((float_val-float_min)*pixels_per_unit); + else + box_start_position = int((float_max-float_val)*pixels_per_unit); + box_end_position = box_start_position+box_length; + } +} + + +/********************************* GLUI_Scrollbar::special_handler() **********/ + +int GLUI_Scrollbar::special_handler( int key,int modifiers ) +{ + if ( !horizontal && key == GLUT_KEY_UP ) { + mouse_down_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1, + y_abs + 1 ); + mouse_up_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1, + y_abs + 1, true ); + } + else if ( !horizontal && key == GLUT_KEY_DOWN ) { + mouse_down_handler(x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1, + y_abs+1+GLUI_SCROLL_ARROW_HEIGHT); + mouse_up_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1, + y_abs+1 +GLUI_SCROLL_ARROW_HEIGHT, + true ); + } + if ( horizontal && key == GLUT_KEY_LEFT ) { + mouse_down_handler( x_abs + 1,y_abs + 1 ); + mouse_up_handler( x_abs + 1, y_abs + 1, true ); + } + else if ( horizontal && key == GLUT_KEY_RIGHT ) { + mouse_down_handler(x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1, + y_abs+1); + mouse_up_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1, + y_abs+1, + true ); + } + else if ( key == GLUT_KEY_HOME ) { /** Set value to limit top - + or increment by 10 **/ + } + else if ( key == GLUT_KEY_END ) { + } + + return true; +} + + +/************************************ GLUI_Scrollbar::update_size() **********/ + +void GLUI_Scrollbar::update_size( void ) +{ + if (horizontal) { + h = GLUI_SCROLL_ARROW_HEIGHT; + if (associated_object) { + this->w = ((GLUI_Control *)associated_object)->w; + } + } + else { + w = GLUI_SCROLL_ARROW_WIDTH; + if (associated_object) { + this->h = ((GLUI_Control *)associated_object)->h; + } + } +} + + +/************************************ GLUI_Scrollbar::find_arrow() ************/ + +int GLUI_Scrollbar::find_arrow( int local_x, int local_y ) +{ + + local_x = local_x-x_abs; + local_y = local_y-y_abs; + + if (horizontal) + { + if ( local_y >= h-GLUI_SCROLL_ARROW_HEIGHT-3 && local_y <= h) + { + update_scroll_parameters(); + if ( local_x >= 0 AND local_x <= (GLUI_SCROLL_ARROW_WIDTH+box_start_position) ) + { + return GLUI_SCROLL_STATE_DOWN; + } + if ( local_x >= (GLUI_SCROLL_ARROW_WIDTH+box_end_position) + AND local_x <= (w+GLUI_SCROLL_ARROW_WIDTH) ) + { + return GLUI_SCROLL_STATE_UP; + } + return GLUI_SCROLL_STATE_SCROLL; + } + } + else + { + if ( local_x >= w-GLUI_SCROLL_ARROW_WIDTH-3 && local_x <= w) + { + update_scroll_parameters(); + if ( local_y >= 0 AND local_y <= (GLUI_SCROLL_ARROW_HEIGHT+box_start_position) ) + { + return GLUI_SCROLL_STATE_UP; + } + if ( local_y >= (GLUI_SCROLL_ARROW_HEIGHT+box_end_position) + AND local_y <= (h+GLUI_SCROLL_ARROW_HEIGHT) ) + { + return GLUI_SCROLL_STATE_DOWN; + } + return GLUI_SCROLL_STATE_SCROLL; + } + } + + return GLUI_SCROLL_STATE_NONE; +} + +/***************************************** GLUI_Scrollbar::do_click() **********/ + +void GLUI_Scrollbar::do_click( void ) +{ + int direction = 0; + + if ( state == GLUI_SCROLL_STATE_UP ) + direction = +1; + else if ( state == GLUI_SCROLL_STATE_DOWN ) + direction = -1; + + if (data_type==GLUI_SCROLL_INT&&int_min>int_max) direction*=-1; + if (data_type==GLUI_SCROLL_FLOAT&&float_min>float_max) direction*=-1; + + increase_growth(); + + float modifier_factor = 1.0; + float incr = growth * modifier_factor * user_speed ; + + double frame_time=GLUI_Time()-last_update_time; + double frame_limit=velocity_limit*frame_time; + if (incr>frame_limit) incr=frame_limit; /* don't scroll faster than limit */ + last_update_time=GLUI_Time(); + + float new_val = float_val; + + new_val += direction * incr; + if (1 || data_type==GLUI_SCROLL_FLOAT) set_float_val(new_val); + if (0 && data_type==GLUI_SCROLL_INT) set_int_val((int)new_val); + //printf("do_click: incr %f val=%f float_val=%f\n",incr,new_val,float_val); + + /*** Now update live variable and do callback. We don't want + to do the callback on each iteration of this function, just on every + i^th iteration, where i is given by GLUI_SCROLL_CALLBACK_INTERVAL ****/ + callback_count++; + if ( (callback_count % GLUI_SCROLL_CALLBACK_INTERVAL ) == 0 ) + do_callbacks(); + +} + + +/***************************************** GLUI_Scrollbar::do_drag() **********/ + +void GLUI_Scrollbar::do_drag( int x, int y ) +{ + int direction = 0; + float incr, modifier_factor; + /* int delta_x; */ + int new_int_val = int_val; + float new_float_val = float_val; + + int free_len = track_length-box_length; + if (free_len == 0) return; + + modifier_factor = 1.0; + if ( state == GLUI_SCROLL_STATE_SCROLL) { + update_scroll_parameters(); + + int hbox = box_length/2; + if (horizontal) { + int track_v = x-GLUI_SCROLL_ARROW_WIDTH; + new_int_val = int_min + (track_v-hbox)*(int_max-int_min)/free_len; + new_float_val = float_min + (track_v-hbox)*(float_max-float_min)/float(free_len); + } else { + int track_v = y-GLUI_SCROLL_ARROW_HEIGHT; + new_int_val = int_max - (track_v-hbox)*(int_max-int_min)/free_len; + new_float_val = float_max - (track_v-hbox)*(float_max-float_min)/float(free_len); + } + } + else { + if ( state == GLUI_SCROLL_STATE_UP ) + direction = +1; + else if ( state == GLUI_SCROLL_STATE_DOWN ) + direction = -1; + incr = growth * direction * modifier_factor * user_speed; + new_int_val += direction; + new_float_val += direction * (float_max-float_min)/free_len; + } + last_y = y; + last_x = x; + + /*** Now update live variable and do callback. We don't want + to do the callback on each iteration of this function, just on every + i^th iteration, where i is given by GLUI_SCROLL_CALLBACK_INTERVAL ****/ + if(data_type==GLUI_SCROLL_INT) + set_int_val(new_int_val); + else if (data_type==GLUI_SCROLL_FLOAT) + set_float_val(new_float_val); + + callback_count++; + if ( (callback_count % GLUI_SCROLL_CALLBACK_INTERVAL ) == 0 ) + do_callbacks(); +} + + +/***************************************** GLUI_Scrollbar::needs_idle() ******/ + +bool GLUI_Scrollbar::needs_idle( void ) const +{ + if (state == GLUI_SCROLL_STATE_UP OR state == GLUI_SCROLL_STATE_DOWN ) { + return true; + } + else { + return false; + } +} + +/***************************************** GLUI_Scrollbar::idle() **********/ + +void GLUI_Scrollbar::idle( void ) +{ + if ( NOT needs_idle() ) + return; + else + do_click(); +} + + +/************************************ GLUI_Scrollbar::do_callbacks() **********/ + +void GLUI_Scrollbar::do_callbacks( void ) +{ + + /* *******************************************/ + + if ( NOT first_callback ) { + if ( data_type == GLUI_SCROLL_INT AND int_val == last_int_val ) { + return; + } + if ( data_type == GLUI_SPINNER_FLOAT AND float_val == last_float_val ) { + return; + } + } + + if (associated_object == NULL) { + this->execute_callback(); + } + else { // Use internal Callbacks + if (object_cb) { + //object_cb(associated_object, int_val); + object_cb(this); + } + } + last_int_val = int_val; + last_float_val = float_val; + first_callback = false; +} + + +/********************************** GLUI_Scrollbar::set_float_val() ************/ + +void GLUI_Scrollbar::set_float_val( float new_val ) +{ + // Allow for the possibility that the limits are reversed + float hi = MAX(float_min,float_max); + float lo = MIN(float_min,float_max); + if (new_val > hi) + new_val = hi; + if (new_val < lo) + new_val = lo; + last_float_val = float_val; + float_val = new_val; + int_val = (int)new_val; + + redraw(); + + /*** Now update the live variable ***/ + output_live(true); +} + + +/********************************** GLUI_Scrollbar::set_int_val() ************/ + +void GLUI_Scrollbar::set_int_val( int new_val ) +{ + // Allow for the possibility that the limits are reversed + int hi = MAX(int_min,int_max); + int lo = MIN(int_min,int_max); + if (new_val > hi) + new_val = hi; + if (new_val < lo) + new_val = lo; + last_int_val = int_val; + float_val = int_val = new_val; + + redraw(); + + /*** Now update the live variable ***/ + output_live(true); +} + +/*********************************** GLUI_Scrollbar::set_float_limits() *********/ + +void GLUI_Scrollbar::set_float_limits( float low, float high, int limit_type ) +{ + if (limit_type != GLUI_LIMIT_CLAMP) { + // error! + } + float_min = low; + float_max = high; + // Allow for possiblitly of reversed limits + float lo = MIN(low,high); + float hi = MAX(low,high); + if (float_valhi) set_float_val(hi); +} + + +/*********************************** GLUI_Scrollbar::set_int_limits() *********/ + +void GLUI_Scrollbar::set_int_limits( int low, int high, int limit_type ) +{ + if (limit_type != GLUI_LIMIT_CLAMP) { + // error! + } + int_min = low; + int_max = high; + // Allow for possiblitly of reversed limits + int lo = MIN(low,high); + int hi = MAX(low,high); + if (int_valhi) set_int_val(hi); + float_min = low; + float_max = high; +} + + +/*********************************** GLUI_Scrollbar::reset_growth() *************/ + +void GLUI_Scrollbar::reset_growth( void ) +{ + growth = fabs(float_max - float_min) / float(GLUI_SCROLL_GROWTH_STEPS); + if (data_type == GLUI_SCROLL_INT && growth<1) growth=1; +} + + +/******************************* GLUI_Scrollbar::increase_growth() *************/ + +void GLUI_Scrollbar::increase_growth( void ) +{ + float range=0; + if (data_type==GLUI_SCROLL_FLOAT) + range = fabs(float_max-float_min); + else + range = fabs(float(int_max-int_min)); + if ( growth < (range / float(GLUI_SCROLL_MIN_GROWTH_STEPS)) ) + growth *= growth_exp; + return; +} + + + diff --git a/Extras/glui/glui_separator.cpp b/Extras/glui/glui_separator.cpp new file mode 100644 index 000000000..b10cf361f --- /dev/null +++ b/Extras/glui/glui_separator.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_separator.cpp - GLUI_Separator 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_Separator::GLUI_Separator() **********/ + +GLUI_Separator::GLUI_Separator( GLUI_Node *parent ) +{ + common_init(); + parent->add_control( this ); +} + +/****************************** GLUI_Separator::draw() **********/ + +void GLUI_Separator::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + int width, indent; + int cont_x, cont_y, cont_w, cont_h, cont_x_off, cont_y_off; + + if ( parent() != NULL ) { + get_this_column_dims(&cont_x, &cont_y, &cont_w, &cont_h, + &cont_x_off, &cont_y_off); + + width = cont_w - cont_x_off*2; + } + else { + width = this->w; + } + + indent = (int) floor(width * .05); + + glLineWidth( 1.0 ); + glBegin( GL_LINES ); + glColor3f( .5, .5, .5 ); + glVertex2i( indent, GLUI_SEPARATOR_HEIGHT/2-1 ); + glVertex2i( width-indent, GLUI_SEPARATOR_HEIGHT/2-1 ); + + glColor3f( 1., 1., 1. ); + glVertex2i( indent, GLUI_SEPARATOR_HEIGHT/2 ); + glVertex2i( width-indent, GLUI_SEPARATOR_HEIGHT/2 ); + glEnd(); +} + + diff --git a/Extras/glui/glui_spinner.cpp b/Extras/glui/glui_spinner.cpp new file mode 100644 index 000000000..85e7e3e00 --- /dev/null +++ b/Extras/glui/glui_spinner.cpp @@ -0,0 +1,647 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_spinner.cpp - GLUI_Spinner class + + + notes: + spinner does not explicitly keep track of the current value - this is all + handled by the underlying edittext control + -> thus, spinner->sync_live() has no meaning, nor spinner->output_live + -> BUT, edittext will alter this spinner's float_val and int_val, + so that spinner->get/set will work + + +FIXME: there's a heck of a lot of duplication between this and glui_scrollbar.cpp. + (OSL, 2006/06) + + + -------------------------------------------------- + + 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" +#include +#include + +/*static int __debug=0; */ + +#define GLUI_SPINNER_GROWTH_STEPS 800 +#define GLUI_SPINNER_MIN_GROWTH_STEPS 100 +#define GLUI_SPINNER_CALLBACK_INTERVAL 1 + + +/****************************** spinner_edittext_callback() ******************/ +/* This function is not used anymore. It has been replaced by directly */ +/* Including an optional pointer to a spinner from an edittext box */ + +void spinner_edittext_callback( int id ) +{ + GLUI_Spinner *spinner; + + putchar( '.' ); flushout; + + spinner = (GLUI_Spinner*) id; + + if ( NOT spinner ) + return; + + spinner->do_callbacks(); +} + + +/****************************** GLUI_Spinner::GLUI_Spinner() ****************/ + +GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name, + int data_type, int id, GLUI_CB callback ) +{ + common_construct(parent, name, data_type, NULL, id, callback); +} + +/****************************** GLUI_Spinner::GLUI_Spinner() ****************/ + +GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name, + int *live_var, int id, GLUI_CB callback ) +{ + common_construct(parent, name, GLUI_SPINNER_INT, live_var, id, callback); +} + +/****************************** GLUI_Spinner::GLUI_Spinner() ****************/ + +GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name, + float *live_var, int id, GLUI_CB callback ) +{ + common_construct(parent, name, GLUI_SPINNER_FLOAT, live_var, id, callback); +} + +/****************************** GLUI_Spinner::GLUI_Spinner() ****************/ + +GLUI_Spinner::GLUI_Spinner( GLUI_Node *parent, const char *name, + int data_t, void *live_var, + int id, GLUI_CB callback ) +{ + common_construct(parent, name, data_t, live_var, id, callback); +} + +/****************************** GLUI_Spinner::common_construct() ************/ + +void GLUI_Spinner::common_construct( GLUI_Node* parent, const char *name, + int data_t, void *data, + int id, GLUI_CB cb ) +{ + common_init(); + + if ( NOT strcmp( name, "Spinner Test" )) + id=id; + + int text_type; + if ( data_t == GLUI_SPINNER_INT ) { + text_type = GLUI_EDITTEXT_INT; + } + else if ( data_t == GLUI_SPINNER_FLOAT ) { + text_type = GLUI_EDITTEXT_FLOAT; + } + else { + assert(0); /* Did not pass in a valid data type */ + } + + user_id = id; + data_type = data_t; + callback = cb; + set_name( name ); + //glui = parent->get_glui(); + + parent->add_control( this ); + + GLUI_EditText *txt = + new GLUI_EditText( this, name, text_type, data, id, cb); + + edittext = txt; /* Link the edittext to the spinner */ + /* control->ptr_val = data; */ + + edittext->spinner = this; /* Link the spinner to the edittext */ + +} + +/****************************** GLUI_Spinner::mouse_down_handler() **********/ + +int GLUI_Spinner::mouse_down_handler( int local_x, int local_y ) +{ + this->state = find_arrow( local_x, local_y ); + GLUI_Master.glui_setIdleFuncIfNecessary(); + + /* printf( "spinner: mouse down : %d/%d arrow:%d\n", local_x, local_y, + find_arrow( local_x, local_y )); + */ + + if ( state != GLUI_SPINNER_STATE_UP AND state != GLUI_SPINNER_STATE_DOWN ) + return true; + + reset_growth(); + redraw(); + + /*** ints and floats behave a bit differently. When you click on + an int spinner, you expect the value to immediately go up by 1, whereas + for a float it'll go up only by a fractional amount. Therefore, we + go ahead and increment by one for int spinners ***/ + if ( data_type == GLUI_SPINNER_INT ) { + if ( state == GLUI_SPINNER_STATE_UP ) + edittext->set_float_val( edittext->float_val + 1.0 ); + else if ( state == GLUI_SPINNER_STATE_DOWN ) + edittext->set_float_val( edittext->float_val - .9 ); + } + + do_click(); + + return false; +} + + +/******************************** GLUI_Spinner::mouse_up_handler() **********/ + +int GLUI_Spinner::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + state = GLUI_SPINNER_STATE_NONE; + GLUI_Master.glui_setIdleFuncIfNecessary(); + + /* printf("spinner: mouse up : %d/%d inside: %d\n",local_x,local_y,inside); */ + + /*glutSetCursor( GLUT_CURSOR_INHERIT ); */ + glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); + redraw(); + + /* do_callbacks(); --- stub */ + /* if ( callback ) */ + /* callback( this->user_id ); */ + + return false; +} + + +/***************************** GLUI_Spinner::mouse_held_down_handler() ******/ + +int GLUI_Spinner::mouse_held_down_handler( int local_x, int local_y, + bool new_inside) +{ + int new_state; + + if ( state == GLUI_SPINNER_STATE_NONE ) + return false; + + /* printf("spinner: mouse held: %d/%d inside: %d\n",local_x,local_y, + new_inside); + */ + + if ( state == GLUI_SPINNER_STATE_BOTH ) { /* dragging? */ + do_drag( local_x, local_y ); + } + else { /* not dragging */ + new_state = find_arrow( local_x, local_y ); + + if ( new_state == state ) { + /** Still in same arrow **/ + do_click(); + } + else { + if ( new_inside OR 1) { + /** The state changed, but we're still inside - that + means we moved off the arrow: begin dragging **/ + state = GLUI_SPINNER_STATE_BOTH; + } + else { + /*** Here check y of mouse position to determine whether to + drag ***/ + + /* ... */ + } + } + + /*** We switched to up/down dragging ***/ + if ( state == GLUI_SPINNER_STATE_BOTH ) { + glutSetCursor( GLUT_CURSOR_UP_DOWN ); + last_x = local_x; + last_y = local_y; + + /** If the spinner has limits, we reset the growth value, since + reset_growth() will compute a new growth value for dragging + vs. clicking. If the spinner has no limits, then we just let the + growth remain at whatever the user has incremented it up to **/ + if ( edittext->has_limits != GLUI_LIMIT_NONE ) + reset_growth(); + } + + redraw(); + } + + return false; +} + + +/****************************** GLUI_Spinner::key_handler() **********/ + +int GLUI_Spinner::key_handler( unsigned char key,int modifiers ) +{ + + + return true; +} + + +/****************************** GLUI_Spinner::draw() **********/ + +void GLUI_Spinner::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + if ( enabled ) { + /*** Draw the up arrow either pressed or unrpessed ***/ + if ( state == GLUI_SPINNER_STATE_UP OR state == GLUI_SPINNER_STATE_BOTH ) + glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_ON, + w-GLUI_SPINNER_ARROW_WIDTH-1, + GLUI_SPINNER_ARROW_Y); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_OFF, + w-GLUI_SPINNER_ARROW_WIDTH-1, + GLUI_SPINNER_ARROW_Y); + + /*** Draw the down arrow either pressed or unrpessed ***/ + if (state == GLUI_SPINNER_STATE_DOWN OR state == GLUI_SPINNER_STATE_BOTH) + glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_ON, + w-GLUI_SPINNER_ARROW_WIDTH-1, + GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y); + else + glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_OFF, + w-GLUI_SPINNER_ARROW_WIDTH-1, + GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y); + } + else { /**** The spinner is disabled ****/ + glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_DIS, + w-GLUI_SPINNER_ARROW_WIDTH-1, + GLUI_SPINNER_ARROW_Y); + glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_DIS, + w-GLUI_SPINNER_ARROW_WIDTH-1, + GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y); + } + + if ( active ) { + glColor3ub( 0, 0, 0 ); + glEnable( GL_LINE_STIPPLE ); + glLineStipple( 1, 0x5555 ); + } + else { + glColor3ub( glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b ); + } + + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( w-GLUI_SPINNER_ARROW_WIDTH-2, 0 ); + glVertex2i( w, 0 ); + glVertex2i( w, h ); + glVertex2i( w-GLUI_SPINNER_ARROW_WIDTH-2, h ); + glEnd(); + glDisable( GL_LINE_STIPPLE ); + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); +} + + +/********************************* GLUI_Spinner::special_handler() **********/ + +int GLUI_Spinner::special_handler( int key,int modifiers ) +{ + if ( key == GLUT_KEY_UP ) { /** Simulate a click in the up arrow **/ + mouse_down_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1, + y_abs + GLUI_SPINNER_ARROW_Y+1 ); + mouse_up_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1, + y_abs + GLUI_SPINNER_ARROW_Y+1, true ); + } + else if ( key == GLUT_KEY_DOWN ) { /** Simulate a click in the up arrow **/ + mouse_down_handler(x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1, + y_abs+GLUI_SPINNER_ARROW_Y+1+GLUI_SPINNER_ARROW_HEIGHT); + mouse_up_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1, + y_abs+GLUI_SPINNER_ARROW_Y+1 +GLUI_SPINNER_ARROW_HEIGHT, + true ); + } + else if ( key == GLUT_KEY_HOME ) { /** Set value to limit top - + or increment by 10 **/ + } + else if ( key == GLUT_KEY_END ) { + } + + return true; +} + + +/******************************* GLUI_Spinner::set_float_val() ************/ + +void GLUI_Spinner::set_float_val( float new_val ) +{ + if ( NOT edittext ) + return; + + edittext->set_float_val( new_val ); +} + + +/********************************** GLUI_Spinner::set_int_val() ************/ + +void GLUI_Spinner::set_int_val( int new_val ) +{ + if ( NOT edittext ) + return; + + edittext->set_int_val( new_val ); +} + + +/************************************ GLUI_Spinner::update_size() **********/ + +void GLUI_Spinner::update_size( void ) +{ + if (!edittext) return; + /*edittext->w = this->w - GLUI_SPINNER_ARROW_WIDTH-3; */ + this->w = edittext->w + GLUI_SPINNER_ARROW_WIDTH + 3; +} + + +/************************************ GLUI_Spinner::find_arrow() ************/ + +int GLUI_Spinner::find_arrow( int local_x, int local_y ) +{ + local_x -= x_abs; + local_y -= y_abs; + + if ( local_x >= (w - GLUI_SPINNER_ARROW_WIDTH) AND + local_x <= w ) { + + if ( local_y >= GLUI_SPINNER_ARROW_Y AND + local_y <= (GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT) ) + return GLUI_SPINNER_STATE_UP; + + if ( local_y >= GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT AND + local_y <= (GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT*2) ) + return GLUI_SPINNER_STATE_DOWN; + + } + + return GLUI_SPINNER_STATE_NONE; +} + + +/***************************************** GLUI_Spinner::do_click() **********/ + +void GLUI_Spinner::do_click( void ) +{ + int direction = 0; + float incr; + float modifier_factor; + + if ( state == GLUI_SPINNER_STATE_UP ) + direction = +1; + else if ( state == GLUI_SPINNER_STATE_DOWN ) + direction = -1; + + increase_growth(); + + modifier_factor = 1.0; + if ( glui ) { + if ( glui->curr_modifiers & GLUT_ACTIVE_SHIFT ) + modifier_factor = 100.0f; + else if ( glui->curr_modifiers & GLUT_ACTIVE_CTRL ) + modifier_factor = .01f; + } + + if ( this->data_type == GLUI_SPINNER_FLOAT OR 1) { + incr = growth * direction * modifier_factor * user_speed; + edittext->set_float_val( edittext->float_val + incr ); + /** Remember, edittext mirrors the float and int values ***/ + } + + /*** Now update live variable and do callback. We don't want + to do the callback on each iteration of this function, just on every + i^th iteration, where i is given by GLUI_SPINNER_CALLBACK_INTERVAL ****/ + callback_count++; + if ( (callback_count % GLUI_SPINNER_CALLBACK_INTERVAL ) == 0 ) + do_callbacks(); +} + + +/***************************************** GLUI_Spinner::do_drag() **********/ + +void GLUI_Spinner::do_drag( int x, int y ) +{ + int delta_y; + float incr, modifier_factor; + /* int delta_x; */ + + modifier_factor = 1.0f; + if ( glui ) { + if ( glui->curr_modifiers & GLUT_ACTIVE_SHIFT ) + modifier_factor = 100.0f; + else if ( glui->curr_modifiers & GLUT_ACTIVE_CTRL ) + modifier_factor = .01f; + } + + /* delta_x = x - last_x; */ + delta_y = -(y - last_y); + + if ( this->data_type == GLUI_SPINNER_FLOAT OR 1 ) { + incr = growth * delta_y * modifier_factor * user_speed; + edittext->set_float_val( edittext->float_val + incr ); + /** Remember, edittext mirrors the float and int values ***/ + } + + last_x = x; + last_y = y; + + /*** Now update live variable and do callback. We don't want + to do the callback on each iteration of this function, just on every + i^th iteration, where i is given by GLUI_SPINNER_CALLBACK_INTERVAL ****/ + + callback_count++; + if ( (callback_count % GLUI_SPINNER_CALLBACK_INTERVAL ) == 0 ) + do_callbacks(); +} + + +/***************************************** GLUI_Spinner::needs_idle() ******/ + +bool GLUI_Spinner::needs_idle( void ) const +{ + if (state == GLUI_SPINNER_STATE_UP OR state == GLUI_SPINNER_STATE_DOWN ) { + return true; + } + else { + return false; + } +} + +/***************************************** GLUI_Spinner::idle() **********/ + +void GLUI_Spinner::idle( void ) +{ + if ( NOT needs_idle() ) + return; + else + do_click(); +} + + +/************************************ GLUI_Spinner::do_callbacks() **********/ + +void GLUI_Spinner::do_callbacks( void ) +{ + /*** This is not necessary, b/c edittext automatically updates us ***/ + if ( NOT edittext ) + return; + this->float_val = edittext->float_val; + this->int_val = edittext->int_val; + /* *******************************************/ + + if ( NOT first_callback ) { + if ( data_type == GLUI_SPINNER_INT AND int_val == last_int_val ) { + return; + } + + if ( data_type == GLUI_SPINNER_FLOAT AND float_val == last_float_val ) { + return; + } + } + + this->execute_callback(); + + last_int_val = int_val; + last_float_val = float_val; + first_callback = false; +} + + +/********************************* GLUI_Spinner::set_float_limits() *********/ + +void GLUI_Spinner::set_float_limits( float low, float high, int limit_type ) +{ + if ( NOT edittext ) + return; + + edittext->set_float_limits( low, high, limit_type ); +} + + +/*********************************** GLUI_Spinner::set_int_limits() *********/ + +void GLUI_Spinner::set_int_limits( int low, int high, int limit_type ) +{ + if ( NOT edittext ) + return; + + edittext->set_int_limits( low, high, limit_type ); +} + + +/*********************************** GLUI_Spinner:reset_growth() *************/ + +void GLUI_Spinner::reset_growth( void ) +{ + float lo, hi; + + if ( edittext->has_limits == GLUI_LIMIT_NONE ) { + if ( data_type == GLUI_SPINNER_FLOAT ) + growth = sqrt(ABS(edittext->float_val)) * .05f; + else if ( data_type == GLUI_SPINNER_INT ) + growth = .4f; + } + else { + if ( data_type == GLUI_SPINNER_FLOAT ) { + lo = edittext->float_low; + hi = edittext->float_high; + growth = (hi-lo) / GLUI_SPINNER_GROWTH_STEPS; + } + else if ( data_type == GLUI_SPINNER_INT ) { + lo = (float) edittext->int_low; + hi = (float) edittext->int_high; + + growth = (hi-lo) / GLUI_SPINNER_GROWTH_STEPS; + } + } + + if ( growth == 0.0f ) + growth = .001f; +} + + +/******************************* GLUI_Spinner:increase_growth() *************/ + +void GLUI_Spinner::increase_growth( void ) +{ + float hi = 0.0,lo = 0.0; + + if ( data_type == GLUI_SPINNER_FLOAT ) { + lo = edittext->float_low; + hi = edittext->float_high; + } + else if ( data_type == GLUI_SPINNER_INT ) { + lo = (float) edittext->int_low; + hi = (float) edittext->int_high; + } + + if ( growth < (hi-lo) / GLUI_SPINNER_MIN_GROWTH_STEPS ) + growth *= growth_exp; + + /* printf( "growth: %f\n", growth ); */ +} + + +/*************************************** GLUI_Spinner:get_text() *************/ + +const char *GLUI_Spinner::get_text( void ) +{ + if (edittext) + return edittext->text.c_str(); + else + return ""; +} + + +/********************************** GLUI_Spinner:get_float_val() *************/ + +float GLUI_Spinner::get_float_val( void ) +{ + if (edittext) + return edittext->float_val; + else + return 0.0f; +} + + +/********************************** GLUI_Spinner:get_int_val() *************/ + +int GLUI_Spinner::get_int_val( void ) +{ + if (edittext) + return edittext->int_val; + else + return 0; +} + + diff --git a/Extras/glui/glui_statictext.cpp b/Extras/glui/glui_statictext.cpp new file mode 100644 index 000000000..b0db4b943 --- /dev/null +++ b/Extras/glui/glui_statictext.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_statictext.cpp - GLUI_StaticText Control + + + -------------------------------------------------- + + 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_StaticText::GLUI_StaticText() **********/ +GLUI_StaticText::GLUI_StaticText( GLUI_Node *parent, const char *name ) +{ + common_init(); + set_name( name ); + parent->add_control( this ); +} + +/****************************** GLUI_StaticText::draw() **********/ + +void GLUI_StaticText::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + + draw_text(); +} + + +/****************************** GLUI_StaticText::set_text() **********/ + +void GLUI_StaticText::set_text( const char *text ) +{ + set_name( text ); + redraw(); +} + + +/************************************ GLUI_StaticText::update_size() **********/ + +void GLUI_StaticText::update_size( void ) +{ + int text_size; + + if ( NOT glui ) + return; + + text_size = string_width( name ); + + if ( w < text_size ) + w = text_size; +} + + +/****************************** GLUI_StaticText::draw_text() **********/ + +void GLUI_StaticText::draw_text( void ) +{ + if ( NOT can_draw() ) + return; + + erase_text(); + draw_name( 0, 9 ); +} + + +/****************************** GLUI_StaticText::erase_text() **********/ + +void GLUI_StaticText::erase_text( void ) +{ + if ( NOT can_draw() ) + return; + + set_to_bkgd_color(); + glDisable( GL_CULL_FACE ); + glBegin( GL_TRIANGLES ); + glVertex2i( 0,0 ); glVertex2i( w, 0 ); glVertex2i( w, h ); + glVertex2i( 0, 0 ); glVertex2i( w, h ); glVertex2i( 0, h ); + glEnd(); +} + + + diff --git a/Extras/glui/glui_string.cpp b/Extras/glui/glui_string.cpp new file mode 100644 index 000000000..06a08bc3e --- /dev/null +++ b/Extras/glui/glui_string.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui.cpp + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher (this file, Bill Baxter 2005) + + 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 + + This program is -not- in the public domain. + +*****************************************************************************/ + +#include "GL/glui.h" +#include + +#ifdef _MSC_VER +#define vsnprintf _vsnprintf +#endif + +GLUI_String& glui_format_str(GLUI_String& str, const char* fmt, ...) +{ + const size_t ISIZE = 128; + char stackbuf[ISIZE]; + size_t bufsz = ISIZE; + char *buf = stackbuf; + str = ""; + va_list arg; + while (1) { + va_start(arg, fmt); + int ret = vsnprintf(buf,299,fmt,arg); + va_end(arg); + if (ret>=0) { + break; + } + // else make a bigger buf, try again + bufsz <<= 1; + if (buf==stackbuf) buf = (char*)malloc(sizeof(char)*bufsz); + else buf = (char*)realloc(buf, sizeof(char)*bufsz); + } + if (buf!=stackbuf) free(buf); + str=buf; + return str; +} diff --git a/Extras/glui/glui_textbox.cpp b/Extras/glui/glui_textbox.cpp new file mode 100644 index 000000000..56fc0158b --- /dev/null +++ b/Extras/glui/glui_textbox.cpp @@ -0,0 +1,1108 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_textbox.cpp - GLUI_TextBox control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher, 2004 John Kew + + 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" +#include + + +static const int LINE_HEIGHT = 15; + +/****************************** GLUI_TextBox::GLUI_TextBox() **********/ + +GLUI_TextBox::GLUI_TextBox(GLUI_Node *parent, GLUI_String &live_var, + bool scroll, int id, GLUI_CB callback ) +{ + common_construct(parent, &live_var, scroll, id, callback); +} + +/****************************** GLUI_TextBox::GLUI_TextBox() **********/ + +GLUI_TextBox::GLUI_TextBox( GLUI_Node *parent, bool scroll, int id, + GLUI_CB callback ) +{ + common_construct(parent, NULL, scroll, id, callback); +} + +/****************************** GLUI_TextBox::common_construct() **********/ +void GLUI_TextBox::common_construct( + GLUI_Node *parent, GLUI_String *data, + bool scroll, int id, GLUI_CB callback) +{ + common_init(); + + GLUI_Node *tb_panel = parent; + + if (scroll) { + GLUI_Panel *p = new GLUI_Panel(parent,"",GLUI_PANEL_NONE); + p->x_off = 1; + tb_panel = p; + } + this->ptr_val = data; + if (data) { + this->live_type = GLUI_LIVE_STRING; + } else { + this->live_type = GLUI_LIVE_NONE; + } + this->user_id = id; + this->callback = callback; + this->name = "textbox"; + tb_panel->add_control( this ); + if (scroll) { + new GLUI_Column(tb_panel, false); + scrollbar = + new GLUI_Scrollbar(tb_panel, + "scrollbar", + GLUI_SCROLL_VERTICAL, + GLUI_SCROLL_INT); + scrollbar->set_object_callback(GLUI_TextBox::scrollbar_callback, this); + scrollbar->set_alignment(GLUI_ALIGN_LEFT); + // scrollbar->can_activate = false; //kills ability to mouse drag too + } + init_live(); +} + +/****************************** GLUI_TextBox::mouse_down_handler() **********/ + +int GLUI_TextBox::mouse_down_handler( int local_x, int local_y ) +{ + int tmp_insertion_pt; + + if ( debug ) dump( stdout, "-> MOUSE DOWN" ); + + tmp_insertion_pt = find_insertion_pt( local_x, local_y ); + if ( tmp_insertion_pt == -1 ) { + if ( glui ) + glui->deactivate_current_control( ); + return false; + } + + insertion_pt = tmp_insertion_pt; + + sel_start = sel_end = insertion_pt; + + keygoal_x = insert_x; + + if ( can_draw()) + update_and_draw_text(); + + if ( debug ) dump( stdout, "<- MOUSE UP" ); + + return true; +} + + +/******************************** GLUI_TextBox::mouse_up_handler() **********/ + +int GLUI_TextBox::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + return false; +} + + +/***************************** GLUI_TextBox::mouse_held_down_handler() ******/ + +int GLUI_TextBox::mouse_held_down_handler( int local_x, int local_y, + bool new_inside) +{ + int tmp_pt; + + if ( NOT new_inside ) return false; + + if ( debug ) dump( stdout, "-> HELD DOWN" ); + + tmp_pt = find_insertion_pt( local_x, local_y ); + keygoal_x = insert_x; + + if ( tmp_pt == -1 AND sel_end != 0 ) { /* moved mouse past left edge */ + special_handler( GLUT_KEY_LEFT, GLUT_ACTIVE_SHIFT ); + } + else if ( tmp_pt == substring_end+1 AND sel_end != (int) text.length()) { + /* moved mouse past right edge */ + special_handler( GLUT_KEY_RIGHT, GLUT_ACTIVE_SHIFT ); + } + else if ( tmp_pt != -1 AND tmp_pt != sel_end ) { + sel_end = insertion_pt = tmp_pt; + + update_and_draw_text(); + } + + if ( debug ) + dump( stdout, "<- HELD DOWN" ); + + return false; +} + + +/****************************** GLUI_TextBox::key_handler() **********/ +int GLUI_TextBox::key_handler( unsigned char key,int modifiers ) +{ + int regular_key; + /* int has_selection; */ + + if ( NOT glui ) + return false; + + if ( debug ) + dump( stdout, "-> KEY HANDLER" ); + + regular_key = false; + bool ctrl_down = (modifiers & GLUT_ACTIVE_CTRL)!=0; + /* has_selection = (sel_start != sel_end); */ + + if ( key == CTRL('[')) { /* ESCAPE */ + glui->deactivate_current_control(); + return true; + } + else if ( (key == 127 AND !ctrl_down) OR /* FORWARD DELETE */ + ( key == CTRL('d') AND modifiers == GLUT_ACTIVE_CTRL) ) + { + if ( sel_start == sel_end ) { /* no selection */ + if ( insertion_pt < (int)text.length() ) { + text.erase(insertion_pt,1); + } + } + else { /* There is a selection */ + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + } + else if ( ((key == 127) AND ctrl_down) OR // Delete word forward + ((key == 'd') AND (modifiers == GLUT_ACTIVE_ALT)) ) + { + if ( sel_start == sel_end ) { /* no selection */ + sel_start = insertion_pt; + sel_end = find_word_break( insertion_pt, +1 ); + } + + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + else if ( key == CTRL('h') ) { /* BACKSPACE */ + if ( sel_start == sel_end ) { /* no selection */ + if ( insertion_pt > 0 ) { + insertion_pt--; + text.erase(insertion_pt,1); + } + } + else { /* There is a selection */ + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + } + else if ( modifiers == GLUT_ACTIVE_CTRL ) /* CTRL ONLY */ + { + /* Ctrl-key bindings */ + if ( key == CTRL('a') ) { + return special_handler( GLUT_KEY_HOME, 0 ); + } + else if ( key == CTRL('e') ) { + return special_handler( GLUT_KEY_END, 0 ); + } + else if ( key == CTRL('b') ) { + return special_handler( GLUT_KEY_LEFT, 0 ); + } + else if ( key == CTRL('f') ) { + return special_handler( GLUT_KEY_RIGHT, 0 ); + } + else if ( key == CTRL('p') ) { + return special_handler( GLUT_KEY_UP, 0 ); + } + else if ( key == CTRL('n') ) { + return special_handler( GLUT_KEY_DOWN, 0 ); + } + else if ( key == CTRL('u') ) { /* ERASE LINE */ + insertion_pt = 0; + text.erase(0,text.length()); + sel_start = sel_end = 0; + } + else if ( key == CTRL('k') ) { /* KILL TO END OF LINE */ + sel_start = sel_end = insertion_pt; + text.erase(insertion_pt,GLUI_String::npos); + } + } + else if ( modifiers == GLUT_ACTIVE_ALT ) /* ALT ONLY */ + { + if ( key == 'b' ) { // Backward word + return special_handler ( GLUT_KEY_LEFT, GLUT_ACTIVE_CTRL ); + } + if ( key == 'f' ) { // Forward word + return special_handler ( GLUT_KEY_RIGHT, GLUT_ACTIVE_CTRL ); + } + } + else if ( (modifiers & GLUT_ACTIVE_CTRL) OR + (modifiers & GLUT_ACTIVE_ALT) ) + { + /** ignore other keys with modifiers */ + return true; + } + else { /* Regular key */ + if ( key == 13 ) /* RETURNS are written as newlines*/ + key = '\n'; + + regular_key = true; + + /** This is just to get rid of warnings - the flag regular_key is + set if the key was not a backspace, return, whatever. But I + believe if we're here, we know it was a regular key anyway */ + if ( regular_key ) { + } + + /**** If there's a current selection, erase it ******/ + if ( sel_start != sel_end ) { + clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end )); + insertion_pt = MIN(sel_start,sel_end); + sel_start = sel_end = insertion_pt; + } + + /******** We insert the character into the string ***/ + + text.insert(insertion_pt,1,key); + + /******** Move the insertion point and substring_end one over ******/ + insertion_pt++; + substring_end++; + + sel_start = sel_end = insertion_pt; + } + + /******** Now redraw text ***********/ + /* Hack to prevent text box from being cleared first **/ + /** int substring_change = update_substring_bounds(); + draw_text_only = + (NOT substring_change AND NOT has_selection AND regular_key ); + */ + + draw_text_only = false; /** Well, hack is not yet working **/ + update_and_draw_text(); + draw_text_only = false; + + + if ( debug ) + dump( stdout, "<- KEY HANDLER" ); + + return true; +} + +/****************************** GLUI_TextBox::enable() **********/ + +void GLUI_TextBox::enable( void ) +{ + GLUI_Control::enable(); + scrollbar->enable(); +} + +/****************************** GLUI_TextBox::disable() **********/ + +void GLUI_TextBox::disable( void ) +{ + GLUI_Control::disable(); + scrollbar->disable(); +} + +/****************************** GLUI_TextBox::activate() **********/ + +void GLUI_TextBox::activate( int how ) +{ + if ( debug ) + dump( stdout, "-> ACTIVATE" ); + active = true; + + if ( how == GLUI_ACTIVATE_MOUSE ) + return; /* Don't select everything if activated with mouse */ + + orig_text = text; + + sel_start = 0; + sel_end = text.length(); + insertion_pt = 0; + if ( debug ) + dump( stdout, "<- ACTIVATE" ); +} + + +/****************************** GLUI_TextBox::deactivate() **********/ + +void GLUI_TextBox::deactivate( void ) +{ + active = false; + + if ( NOT glui ) + return; + + if ( debug ) + dump( stdout, "-> DISACTIVATE" ); + + sel_start = sel_end = insertion_pt = -1; + + /***** Retrieve the current value from the text *****/ + /***** The live variable will be updated by set_text() ****/ + set_text(text.c_str()); /* This will force callbacks and gfx refresh */ + + update_substring_bounds(); + + /******** redraw text without insertion point ***********/ + redraw(); + + /***** Now do callbacks if value changed ******/ + if ( orig_text != text ) { + this->execute_callback(); + + + } + + + if ( debug ) + dump( stdout, "<- DISACTIVATE" ); +} + +/****************************** GLUI_TextBox::draw() **********/ + +void GLUI_TextBox::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int line = 0; + int text_length; + int box_width; + int i; + + /* 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(); + } + + /* Begin Drawing Lines of Text */ + substring_start = 0; + substring_end = 0; + text_length = text.length()-1; + + /* Figure out how wide the box is */ + box_width = get_box_width(); + + /* Get the first line substring */ + while (substring_width(substring_start, substring_end+1 ) < box_width && + substring_end < text_length && text[substring_end+1] != '\n') + substring_end++; + + /* Figure out which lines are visible*/ + + visible_lines = (int)(h-20)/LINE_HEIGHT; + if (start_line < (curr_line-visible_lines)) { + for (i = 0; ((curr_line-i)*LINE_HEIGHT+20) > h; i++); + start_line = i; + } else if ( start_line > curr_line) { + start_line = curr_line; + } + line = 0; + do { + if (line && substring_end < text_length) { + substring_start = substring_end+1; + while (substring_width(substring_start, substring_end+1 ) < box_width && + substring_end < text_length && text[substring_end+1] != '\n') + substring_end++; + } + if (text[substring_end+1] == '\n') { /* Skip newline */ + substring_end++; + } + if (line < start_line || (line > curr_line && curr_line > (start_line + visible_lines))) { + line++; + continue; + } + if ((line - start_line) <= visible_lines) + draw_text(0,(line - start_line)*LINE_HEIGHT); /* tabs and other nasties are handled by substring_width */ + line++; + } while (substring_end < text_length); + + num_lines = line; + + draw_insertion_pt(); + if (scrollbar) { + scrollbar->set_int_limits(MAX(0,num_lines/*-1*/-visible_lines),0); + glPushMatrix(); + glTranslatef(scrollbar->x_abs-x_abs, scrollbar->y_abs-y_abs,0.0); + scrollbar->draw_scroll(); + glPopMatrix(); + } +} + + + +/************************** GLUI_TextBox::update_substring_bounds() *********/ + +int GLUI_TextBox::update_substring_bounds( void ) +{ + int box_width; + int text_len = text.length(); + int old_start, old_end; + + old_start = substring_start; + old_end = substring_end; + + /*** Calculate the width of the usable area of the edit box ***/ + box_width = get_box_width(); + + CLAMP( substring_end, 0, MAX(text_len-1,0) ); + CLAMP( substring_start, 0, MAX(text_len-1,0) ); + + if ( debug ) dump( stdout, "-> UPDATE SS" ); + + if ( insertion_pt >= 0 AND + insertion_pt < substring_start ) { /* cursor moved left */ + substring_start = insertion_pt; + + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_end--; + } + else if ( insertion_pt > substring_end ) { /* cursor moved right */ + substring_end = insertion_pt-1; + + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_start++; + } + else { /* cursor is within old substring bounds */ + if ( last_insertion_pt > insertion_pt ) { /* cursor moved left */ + } + else { + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_end--; + + while(substring_width( substring_start, substring_end+1 ) <= box_width + AND substring_end < text_len-1 ) + substring_end++; + } + } + + while ( substring_width( substring_start, substring_end ) > box_width ) + substring_end--; + + last_insertion_pt = insertion_pt; + + /*** No selection if not enabled ***/ + if ( NOT enabled ) { + sel_start = sel_end = 0; + } + + if ( debug ) dump( stdout, "<- UPDATE SS" ); + + if ( substring_start == old_start AND substring_end == old_end ) + return false; /*** bounds did not change ***/ + else + return true; /*** bounds did change ***/ + +} + + +/********************************* GLUI_TextBox::update_x_offsets() *********/ + +void GLUI_TextBox::update_x_offsets( void ) +{ +} + + +/********************************* GLUI_TextBox::draw_text() ****************/ + +void GLUI_TextBox::draw_text( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int text_x, i, sel_lo, sel_hi, x_pos; + + if ( debug ) dump( stdout, "-> DRAW_TEXT" ); + + /** Find where to draw the text **/ + + text_x = 2 + GLUI_TEXTBOX_BOXINNERMARGINX; + + /** Find lower and upper selection bounds **/ + sel_lo = MIN(sel_start, sel_end ); + sel_hi = MAX(sel_start, sel_end ); + + int sel_x_start, sel_x_end, delta; + + /** Draw selection area dark **/ + if ( sel_start != sel_end ) { + sel_x_start = text_x; + sel_x_end = text_x; + delta = 0; + for( i=substring_start; sel_x_end < (w - text_x) && i<=substring_end; i++ ) { + delta = 0; + if (text[i] == '\t') // Character is a tab, go to next tab stop + while (((delta + sel_x_end) < (w - text_x)) && + (delta == 0 || delta % tab_width)) + delta++; + else + delta = char_width( text[i] ); + + if ( i < sel_lo ) { + sel_x_start += delta; + sel_x_end += delta; + } + else if ( i < sel_hi ) { + sel_x_end += delta; + } + } + + glColor3f( 0.0f, 0.0f, .6f ); + glRecti(sel_x_start, y+5, sel_x_end, y+20); + } + + + if ( sel_start == sel_end ) { // No current selection + x_pos = text_x; + if ( enabled ) + glColor3b( 0, 0, 0 ); + else + glColor3b( 32, 32, 32 ); + + glRasterPos2i( text_x, y+LINE_HEIGHT); + for( i=substring_start; i<=substring_end; i++ ) { + if (this->text[i] == '\t') { // Character is a tab, go to next tab stop + x_pos = ((x_pos-text_x)/tab_width)*tab_width+tab_width+text_x; + glRasterPos2i( x_pos, y+LINE_HEIGHT); // Reposition pen after tab + } else { + glutBitmapCharacter( get_font(), this->text[i] ); + x_pos += char_width( this->text[i] ); + } + } + } + else { // There is a selection + x_pos = text_x; + for( i=substring_start; i<=substring_end; i++ ) { + if ( IN_BOUNDS( i, sel_lo, sel_hi-1)) { // This character is selected + glColor3f( 1., 1., 1. ); + glRasterPos2i( x_pos, y+LINE_HEIGHT); + if (this->text[i] == '\t') { // Character is a tab, go to next tab stop + x_pos = ((x_pos-text_x)/tab_width)*tab_width+tab_width+text_x; + } + else + glutBitmapCharacter( get_font(), this->text[i] ); + } + else { + glColor3f( 0., 0., 0. ); + glRasterPos2i( x_pos, y+LINE_HEIGHT); + if (this->text[i] == '\t') { // Character is a tab, go to next tab stop + x_pos = ((x_pos-text_x)/tab_width)*tab_width+tab_width+text_x; + glRasterPos2i( x_pos, y+LINE_HEIGHT); // Reposition pen after tab + } else + glutBitmapCharacter( get_font(), this->text[i] ); + } + + x_pos += char_width( text[i] ); + } + } + + if ( debug ) dump( stdout, "<- DRAW_TEXT" ); +} + + +/******************************** GLUI_TextBox::find_insertion_pt() *********/ +/* This function returns the character number *before which* the insertion */ +/* point goes */ + +int GLUI_TextBox::find_insertion_pt( int x, int y ) +{ + /*** See if we clicked outside box ***/ + if ( x < this->x_abs || y < this->y_abs) + return -1; + + /*** See if we clicked in an empty box ***/ + if ( text.empty() ) + return 0; + + /* update insert variables */ + insert_x = x; + insert_y = y; + + int text_length = text.length()-1; + int box_width = get_box_width(); + + int sol = 0; + int eol = 0; + int line = 0; + + int y_off = y - (y_abs + 2 + GLUI_TEXTBOX_BOXINNERMARGINX); + int x_off = x - (x_abs + 2 + GLUI_TEXTBOX_BOXINNERMARGINX); + + /* Find the line clicked, + The possibility of long lines getting wrapped complicates this. */ + while ((line-start_line+1)*LINE_HEIGHT < y_off && eol < text_length) + { + while (eol < text_length && text[eol] != '\n' && + substring_width(sol, eol+1) <= box_width) + { + eol++; + } + if (text[eol]=='\n' && eol=x_off) { + // did we go far enough? (see if click was >1/2 width of last char) + int decision_pt = prev_w+(total_w-prev_w)/2; + if (x_off>decision_pt) eol++; + } + return eol; + +#if 0 + while (eol < text_length && text[eol] != '\n' && + substring_width(sol, eol+1) < box_width ) + { + eol++; + } + + + /* We move from right to left, looking to see if the mouse was clicked + to the right of the ith character */ +#if 0 + int curr_x = this->x_abs + + substring_width( sol, eol ) + + 2 /* The edittext box has a 2-pixel margin */ + + GLUI_TEXTBOX_BOXINNERMARGINX; /** plus this many pixels blank space + between the text and the box **/ +#endif + + /** find mouse click in text **/ + + if (x_off > substring_width(sol, eol)) + return eol; + + for(i = sol; i <= eol+1; i++) { + if (x_off <= substring_width(sol, i)) + return i+1; + } + return 0; +#endif +} + + +int GLUI_TextBox::get_box_width() +{ + return MAX( this->w + - 4 /* 2 * the two-line box border */ + - 2 * GLUI_TEXTBOX_BOXINNERMARGINX, 0 ); + +} + +/******************************** GLUI_TextBox::draw_insertion_pt() *********/ + +void GLUI_TextBox::draw_insertion_pt( void ) +{ + int curr_x, box_width, text_length, eol, sol, line; + + if ( NOT can_draw() ) + return; + + /*** Don't draw insertion pt if control is disabled ***/ + if ( NOT enabled ) + return; + + if ( sel_start != sel_end OR insertion_pt < 0 ) { + return; /* Don't draw insertion point if there is a current selection */ + } + + if ( debug ) dump( stdout, "-> DRAW_INS_PT" ); + + /* printf( "insertion pt: %d\n", insertion_pt ); */ + + box_width = get_box_width(); + + // This function is unable to distinguish whether an insertion + // point on a line break should be drawn on the line before or the line after. + // This depends on the sequence of operations used to get there, and this + // function just doesn't have that information. If curr_line were kept up + // to date elsewhere that could be used here to disambiguate, but arrow keys + // and such do not update it. + + sol = 0; + eol = 0; + text_length = text.length()-1; + + //while (eol < text_length && text[eol] != '\n' + // && substring_width(sol, eol + 1) < box_width ) + // eol++; + line = 0; + while (eol < insertion_pt && eol <= text_length) + { + if (text[eol] == '\n' || substring_width(sol, eol + 1) >= box_width) + { + eol++; + if (text[eol]=='\n'||eol!=insertion_pt + ||(eol==insertion_pt && eol>0 && text[eol-1]=='\n')) { + sol = eol; + line++; + } + } + else { + eol++; + } + } + + //glColor3f(1,0,0); + //glRecti(0, curr_line*LINE_HEIGHT, 3, (curr_line+1)*LINE_HEIGHT); + + curr_line = line; + + if (scrollbar) + scrollbar->set_int_val(start_line); + if (curr_line < start_line || curr_line > (start_line + visible_lines)) /* Insertion pt out of draw area */ + return; + + curr_x = this->x_abs + + 2 /* The edittext box has a 2-pixel margin */ + + GLUI_TEXTBOX_BOXINNERMARGINX; /** plus this many pixels blank space + between the text and the box **/ + + curr_x += substring_width(sol,insertion_pt-1); + if (insertion_pt == text.length() && text[text.length()-1] == '\n' + || curr_x-this->x_abs > (w - 2 - GLUI_TEXTBOX_BOXINNERMARGINX)) { // Insert on the next line + curr_x = this->x_abs + GLUI_TEXTBOX_BOXINNERMARGINX; + line++; + } + /* update insertion coordinates */ + insert_x = curr_x+5; /* I hate magic numbers too, these offset the imagined insertion point */ + insert_y = (curr_line-start_line+2)*LINE_HEIGHT; + + + glColor3f( 0.0, 0.0, 0.0 ); + glBegin( GL_LINE_LOOP ); + + curr_x -= x_abs; + glVertex2i( curr_x+1, (curr_line-start_line)*LINE_HEIGHT + 4 ); + glVertex2i( curr_x, (curr_line-start_line)*LINE_HEIGHT + 4 ); + glVertex2i( curr_x+1, (curr_line-start_line)*LINE_HEIGHT + 16 ); + glVertex2i( curr_x, (curr_line-start_line)*LINE_HEIGHT + 16 ); + glEnd(); + + + if ( debug ) dump( stdout, "-> DRAW_INS_PT" ); +} + + + + +/******************************** GLUI_TextBox::substring_width() *********/ +int GLUI_TextBox::substring_width( int start, int end, int initial_width ) +{ + // This function only works properly if start is really the start of a line. + // Otherwise tabs will be messed up. + int i, width = initial_width; + + for( i=start; i<=end; i++ ) + if (text[i] == '\t') { // Character is a tab, jump to next tab stop + width += tab_width-(width%tab_width); + //while (width == 0 || width % tab_width) + // width++; + } + else + width += char_width( text[i] ); + + return width; +} + + +/***************************** GLUI_TextBox::update_and_draw_text() ********/ + +void GLUI_TextBox::update_and_draw_text( void ) +{ + //update_substring_bounds(); + /* printf( "ss: %d/%d\n", substring_start, substring_end ); */ + + redraw(); +} + + +/********************************* GLUI_TextBox::special_handler() **********/ + +int GLUI_TextBox::special_handler( int key,int modifiers ) +{ + int tmp_insertion_pt; + if ( NOT glui ) + return false; + + if ( debug ) + printf( "SPECIAL:%d - mod:%d subs:%d/%d ins:%d sel:%d/%d\n", + key, modifiers, substring_start, substring_end,insertion_pt, + sel_start, sel_end ); + + if ( key == GLUT_KEY_DOWN ) { + if (insert_x == -1 || insert_y == -1) + return false; + tmp_insertion_pt = find_insertion_pt( keygoal_x, insert_y+LINE_HEIGHT); + if (tmp_insertion_pt < 0) + return false; + insertion_pt = tmp_insertion_pt; + sel_end = insertion_pt; + if (!(modifiers & GLUT_ACTIVE_SHIFT)) { + sel_start = sel_end; + } + if ( can_draw()) + update_and_draw_text(); + } else if ( key == GLUT_KEY_UP ) { + if (insert_x == -1 || insert_y == -1) + return false; + tmp_insertion_pt = find_insertion_pt( keygoal_x, insert_y-LINE_HEIGHT); + if (tmp_insertion_pt < 0) + return false; + insertion_pt = tmp_insertion_pt; + sel_end = insertion_pt; + if (!(modifiers & GLUT_ACTIVE_SHIFT)) { + sel_start = sel_end; + } + if ( can_draw()) + update_and_draw_text(); + } else if ( key == GLUT_KEY_LEFT ) { + if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) { + insertion_pt = find_word_break( insertion_pt, -1 ); + } + else { + insertion_pt--; + } + // update keygoal_x! + } + else if ( key == GLUT_KEY_RIGHT ) { + if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) { + insertion_pt = find_word_break( insertion_pt, +1 ); + } + else { + insertion_pt++; + } + // update keygoal_x! + } + else if ( key == GLUT_KEY_HOME ) { + insertion_pt = 0; + // update keygoal_x! + } + else if ( key == GLUT_KEY_END ) { + insertion_pt = text.length(); + // update keygoal_x! + } + + /*** Update selection if shift key is down ***/ + if ( (modifiers & GLUT_ACTIVE_SHIFT ) != 0 ) + sel_end = insertion_pt; + else + sel_start = sel_end = insertion_pt; + + + CLAMP( insertion_pt, 0, (int)text.length()); /* Make sure insertion_pt + is in bounds */ + CLAMP( sel_start, 0, (int)text.length()); /* Make sure insertion_pt + is in bounds */ + CLAMP( sel_end, 0, (int)text.length()); /* Make sure insertion_pt + is in bounds */ + + /******** Now redraw text ***********/ + if ( can_draw()) + update_and_draw_text(); + + return true; +} + + +/****************************** GLUI_TextBox::find_word_break() **********/ +/* It looks either left or right (depending on value of 'direction' */ +/* for the beginning of the next 'word', where word are characters */ +/* separated by one of the following tokens: " :-.," */ +/* If there is no next word in the specified direction, this returns */ +/* the beginning of 'text', or the very end. */ + +int GLUI_TextBox::find_word_break( int start, int direction ) +{ + int i, j; + char breaks[] = " \n\t:-.,"; + int num_break_chars = (int)strlen(breaks), text_len = text.length(); + int new_pt; + + /** If we're moving left, we have to start two back, in case we're either + already at the beginning of a word, or on a separating token. + Otherwise, this function would just return the word we're already at **/ + if ( direction == -1 ) { + start -= 2; + } + + /***** Iterate over text in the specified direction *****/ + for ( i=start; i >= 0 AND i < text_len; i += direction ) { + + /** For each character in text, iterate over list of separating tokens **/ + for( j=0; j 0 ) /* Return the end of string */ + return text_len; + else /* Return the beginning of the text */ + return 0; +} + + +/********************************** GLUI_TextBox::clear_substring() ********/ + +void GLUI_TextBox::clear_substring( int start, int end ) +{ + text.erase(start,end-start); +} + + + +/************************************ GLUI_TextBox::update_size() **********/ + +void GLUI_TextBox::update_size( void ) +{ + if ( NOT glui ) + return; + + if ( w < GLUI_TEXTBOX_MIN_TEXT_WIDTH ) + w = GLUI_TEXTBOX_MIN_TEXT_WIDTH; +} + + +/****************************** GLUI_TextBox::set_text() **********/ + +void GLUI_TextBox::set_text( const char *new_text ) +{ + text = new_text; + + substring_start = 0; + substring_end = text.length() - 1; + insertion_pt = -1; + sel_start = 0; + sel_end = 0; + visible_lines = 0; + start_line = 0; + curr_line = 0; + num_lines = 0; + + if ( can_draw() ) + update_and_draw_text(); + + /*** Now update the live variable ***/ + output_live(true); +} + + +/*************************************** GLUI_TextBox::dump() **************/ + +void GLUI_TextBox::dump( FILE *out, char *name ) +{ + fprintf( out, + "%s (edittext@%p): line:%d ins_pt:%d subs:%d/%d sel:%d/%d len:%d\n", + name, this, curr_line, + insertion_pt, substring_start, substring_end, sel_start, sel_end, + text.length()); +} + + +/**************************************** GLUI_TextBox::mouse_over() ********/ + +int GLUI_TextBox::mouse_over( int state, int x, int y ) +{ + if ( state && enabled) { + /* curr_cursor = GLUT_CURSOR_TEXT; */ + glutSetCursor( GLUT_CURSOR_TEXT ); + } + else { + /* printf( "OUT\n" ); */ + glutSetCursor( GLUT_CURSOR_LEFT_ARROW ); + } + + return true; +} + +void GLUI_TextBox::scrollbar_callback(GLUI_Control *my_scrollbar) { + GLUI_Scrollbar *sb = dynamic_cast(my_scrollbar); + if (!sb) return; + GLUI_TextBox* me = (GLUI_TextBox*) sb->associated_object; + if (me->scrollbar == NULL) + return; + int new_start_line = sb->get_int_val(); // ?? + me->start_line = new_start_line; + if (new_start_line < (me->curr_line - me->visible_lines)) + me->curr_line = new_start_line + me->visible_lines; + if (new_start_line > me->curr_line) + me->curr_line = new_start_line; + if ( me->can_draw() ) + me->update_and_draw_text(); +} diff --git a/Extras/glui/glui_translation.cpp b/Extras/glui/glui_translation.cpp new file mode 100644 index 000000000..e11c743a7 --- /dev/null +++ b/Extras/glui/glui_translation.cpp @@ -0,0 +1,559 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_translation - GLUI_Translation 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 "GL/glui.h" +#include "glui_internal.h" +#include "algebra3.h" + +/********************** GLUI_Translation::GLUI_Translation() ***/ + +GLUI_Translation::GLUI_Translation( + GLUI_Node *parent, const char *name, + int trans_t, float *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(); + + trans_type = trans_t; + + if ( trans_type == GLUI_TRANSLATION_XY ) { + float_array_size = 2; + } + else if ( trans_type == GLUI_TRANSLATION_X ) { + float_array_size = 1; + } + else if ( trans_type == GLUI_TRANSLATION_Y ) { + float_array_size = 1; + } + else if ( trans_type == GLUI_TRANSLATION_Z ) { + float_array_size = 1; + } + init_live(); +} + +/********************** GLUI_Translation::iaction_mouse_down_handler() ***/ +/* These are really in local coords (5/10/99) */ + +int GLUI_Translation::iaction_mouse_down_handler( int local_x, + int local_y ) +{ + int center_x, center_y; + + down_x = local_x; + down_y = local_y; + + if ( trans_type == GLUI_TRANSLATION_XY ) { + orig_x = float_array_val[0]; + orig_y = float_array_val[1]; + + /** Check if the Alt key is down, which means lock to an axis **/ + + center_x = w/2; + center_y = (h-18)/2; + + if ( glui->curr_modifiers & GLUT_ACTIVE_ALT ) { + if ( ABS(local_y-center_y) > ABS(local_x-center_x) ) { + locked = GLUI_TRANSLATION_LOCK_Y; + glutSetCursor( GLUT_CURSOR_UP_DOWN ); + } + else { + locked = GLUI_TRANSLATION_LOCK_X; + glutSetCursor( GLUT_CURSOR_LEFT_RIGHT ); + } + } + else { + locked = GLUI_TRANSLATION_LOCK_NONE; + glutSetCursor( GLUT_CURSOR_SPRAY ); + } + } + else if ( trans_type == GLUI_TRANSLATION_X ) { + glutSetCursor( GLUT_CURSOR_LEFT_RIGHT ); + orig_x = float_array_val[0]; + } + else if ( trans_type == GLUI_TRANSLATION_Y ) { + glutSetCursor( GLUT_CURSOR_UP_DOWN ); + orig_y = float_array_val[0]; + } + else if ( trans_type == GLUI_TRANSLATION_Z ) { + glutSetCursor( GLUT_CURSOR_UP_DOWN ); + orig_z = float_array_val[0]; + } + + trans_mouse_code = 1; + redraw(); + + return false; +} + + +/*********************** GLUI_Translation::iaction_mouse_up_handler() **********/ + +int GLUI_Translation::iaction_mouse_up_handler( int local_x, int local_y, + bool inside ) +{ + trans_mouse_code = GLUI_TRANSLATION_MOUSE_NONE; + locked = GLUI_TRANSLATION_LOCK_NONE; + + redraw(); + + return false; +} + + +/******************* GLUI_Translation::iaction_mouse_held_down_handler() ******/ + +int GLUI_Translation::iaction_mouse_held_down_handler( int local_x, int local_y, + bool inside) +{ + float x_off, y_off; + float off_array[2]; + + x_off = scale_factor * (float)(local_x - down_x); + y_off = -scale_factor * (float)(local_y - down_y); + + if ( glui->curr_modifiers & GLUT_ACTIVE_SHIFT ) { + x_off *= 100.0f; + y_off *= 100.0f; + } + else if ( glui->curr_modifiers & GLUT_ACTIVE_CTRL ) { + x_off *= .01f; + y_off *= .01f; + } + + + if ( trans_type == GLUI_TRANSLATION_XY ) { + + if ( locked == GLUI_TRANSLATION_LOCK_X ) + y_off = 0.0; + else if ( locked == GLUI_TRANSLATION_LOCK_Y ) + x_off = 0.0; + + off_array[0] = x_off + orig_x; + off_array[1] = y_off + orig_y; + } + else if ( trans_type == GLUI_TRANSLATION_X ) { + off_array[0] = x_off + orig_x; + } + else if ( trans_type == GLUI_TRANSLATION_Y ) { + off_array[0] = y_off + orig_y; + } + else if ( trans_type == GLUI_TRANSLATION_Z ) { + off_array[0] = y_off + orig_z; + } + + set_float_array_val( (float*) &off_array[0] ); + + return false; +} + + +/******************** GLUI_Translation::iaction_draw_active_area_persp() **************/ + +void GLUI_Translation::iaction_draw_active_area_persp( void ) +{ +} + + +/******************** GLUI_Translation::iaction_draw_active_area_ortho() **********/ + +void GLUI_Translation::iaction_draw_active_area_ortho( void ) +{ + /********* Draw emboss circles around arcball control *********/ + float radius; + radius = (float)(h-22)/2.0; /* MIN((float)w/2.0, (float)h/2.0); */ + glLineWidth( 1.0 ); + + draw_emboss_box( (int) -radius-2, (int)radius+2, + (int)-radius-2, (int)radius+2 ); + + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + glTranslatef( .5, .5, .5 ); + /* glScalef( radius-1.0, radius-1.0, radius-1.0 ); */ + if ( trans_type == GLUI_TRANSLATION_Z ) + draw_2d_z_arrows((int)radius-1); + else if ( trans_type == GLUI_TRANSLATION_XY ) + draw_2d_xy_arrows((int)radius-1); + else if ( trans_type == GLUI_TRANSLATION_X ) + draw_2d_x_arrows((int)radius-1); + else if ( trans_type == GLUI_TRANSLATION_Y ) + draw_2d_y_arrows((int)radius-1); + + glPopMatrix(); +} + + +/******************************** GLUI_Translation::iaction_dump() **********/ + +void GLUI_Translation::iaction_dump( FILE *output ) +{ +} + + +/******************** GLUI_Translation::iaction_special_handler() **********/ + +int GLUI_Translation::iaction_special_handler( int key,int modifiers ) +{ + + return false; +} + + + +/*************************** GLUI_Translation::draw_2d_z_arrows() **************/ + +void GLUI_Translation::draw_2d_z_arrows( int radius ) +{ + if ( trans_mouse_code != GLUI_TRANSLATION_MOUSE_NONE ) { + draw_2d_arrow(radius, true, 2); + draw_2d_arrow(radius, true, 0); + } + else { + draw_2d_arrow(radius, false, 2); + draw_2d_arrow(radius, false, 0); + } +} + + +/*************************** GLUI_Translation::draw_2d_x_arrows() **************/ + +void GLUI_Translation::draw_2d_x_arrows( int radius ) +{ + if ( trans_mouse_code != GLUI_TRANSLATION_MOUSE_NONE ) { + draw_2d_arrow(radius, true, 1); + draw_2d_arrow(radius, true, 3); + } + else { + draw_2d_arrow(radius, false, 1); + draw_2d_arrow(radius, false, 3); + } +} + + +/*************************** GLUI_Translation::draw_2d_y_arrows() **************/ + +void GLUI_Translation::draw_2d_y_arrows( int radius ) +{ + if ( trans_mouse_code != GLUI_TRANSLATION_MOUSE_NONE ) { + draw_2d_arrow(radius, true, 0); + draw_2d_arrow(radius, true, 2); + } + else { + draw_2d_arrow(radius, false, 0); + draw_2d_arrow(radius, false, 2); + } +} + + +/************************** GLUI_Translation::draw_2d_xy_arrows() **************/ + +void GLUI_Translation::draw_2d_xy_arrows( int radius) +{ + if ( trans_mouse_code != GLUI_TRANSLATION_MOUSE_NONE ) { + if ( locked == GLUI_TRANSLATION_LOCK_X ) { + draw_2d_arrow(radius, false, 0); + draw_2d_arrow(radius, false, 2); + draw_2d_arrow(radius, true, 1); + draw_2d_arrow(radius, true, 3); + } + else if ( locked == GLUI_TRANSLATION_LOCK_Y ) { + draw_2d_arrow(radius, false, 1); + draw_2d_arrow(radius, false, 3); + draw_2d_arrow(radius, true, 0); + draw_2d_arrow(radius, true, 2); + } + else { + draw_2d_arrow(radius, true, 0); + draw_2d_arrow(radius, true, 1); + draw_2d_arrow(radius, true, 2); + draw_2d_arrow(radius, true, 3); + } + } + else { + draw_2d_arrow(radius, false, 0); + draw_2d_arrow(radius, false, 1); + draw_2d_arrow(radius, false, 2); + draw_2d_arrow(radius, false, 3); + } + + return; +} + + +/*************************** GLUI_Translation::draw_2d_arrow() **************/ +/* ori: 0=up, 1=left, 2=down, 3=right */ +/* */ +/* */ +/* 0, y2 */ +/* / \ */ +/* / \ */ +/* / \ */ +/* / \ */ +/* / \ */ +/* / \ */ +/* / \ */ +/* / \ */ +/* -x2,y1 -x1b,y1 x1b,y1 x2,y1 */ +/* | | */ +/* | | */ +/* | | */ +/* | | */ +/* | | */ +/* -x1a,y0 x1a,y0 */ +/* */ + + +void GLUI_Translation::draw_2d_arrow( int radius, int filled, int orientation ) +{ + float x1 = .2, x2 = .4, y1 = .54, y2 = .94, y0; + float x1a, x1b; +/* + vec3 col1( 0.0, 0.0, 0.0 ), col2( .45, .45, .45 ), + col3( .7, .7, .7 ), col4( 1.0, 1.0, 1.0 ); + vec3 c1, c2, c3, c4, c5, c6; +*/ + vec3 white(1.0,1.0,1.0), black(0.0,0.0,0.0), gray(.45,.45,.45), + bkgd(.7,.7,.7); + int c_off=0; /* color index offset */ + + if ( glui ) + bkgd.set(glui->bkgd_color_f[0], + glui->bkgd_color_f[1], + glui->bkgd_color_f[2]); + + /* bkgd[0] = 255.0; bkgd[1] = 0; */ + + /** The following 8 colors define the shading of an octagon, in + clockwise order, starting from the upstroke on the left **/ + /** This is for an outside and inside octagons **/ + vec3 colors_out[]={white, white, white, gray, black, black, black, gray}; + vec3 colors_in[] ={bkgd,white,bkgd,gray,gray,gray,gray,gray}; + +#define SET_COL_OUT(i) glColor3fv((float*) &colors_out[(i)%8][0]); +#define SET_COL_IN(i) glColor3fv((float*) &colors_in[(i)%8][0]); + + x1 = (float)radius * .2; + x2 = x1 * 2; + y1 = (float)radius * .54; + y2 = y1 + x2; + x1a = x1; + x1b = x1; + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + +#define DRAW_SEG( xa,ya,xb,yb ) glVertex2f(xa,ya); glVertex2f(xb,yb); + + glScalef( -1.0, 1.0, 1.0 ); + + if ( orientation == 2 ) { + c_off = 4; + } + else if ( orientation == 0 ) { + c_off = 0; + glRotatef( 180.0, 0.0, 0.0, 1.0 ); + } + else if ( orientation == 1 ) { + c_off = 2; + glRotatef( 90.0, 0.0, 0.0, 1.0 ); + } + else if ( orientation == 3 ) { + c_off = 6; + glRotatef( -90.0, 0.0, 0.0, 1.0 ); + } + + if ( trans_type == GLUI_TRANSLATION_Z ) + y0 = 0.0; + else if ( trans_type == GLUI_TRANSLATION_XY ) + y0 = x1; + else + y0 = 0.0; + + + if ( trans_type == GLUI_TRANSLATION_Z ) { + if ( orientation == 0 ) { + y1 += 2.0; + y2 += 0.0; + + x1b -= 2.0; + x2 -= 2.0; + x1a += 2.0; + } + else if ( orientation == 2 ) { + y1 -= 6.0; + x1a += 2.0; + x1b += 4.0; + x2 += 6.0; + } + } + + /*** Fill in inside of arrow ***/ + if ( NOT filled ) { /*** Means button is up - control is not clicked ***/ + /*glColor3f( .8, .8, .8 ); */ + set_to_bkgd_color(); + glColor3f( bkgd[0]+.07, bkgd[1]+.07, bkgd[2]+.07 ); + } + else { /*** Button is down on control ***/ + glColor3f( .6, .6, .6 ); + c_off += 4; /* Indents the shadows - goes from a raised look to embossed */ + } + + /*** Check if control is enabled or not ***/ + if ( NOT enabled ) { + set_to_bkgd_color(); + /*c_off += 4; -- Indents the shadows - goes from a raised look to embossed */ + colors_out[0] = colors_out[1] = colors_out[2] = colors_out[7] = gray; + colors_out[3] = colors_out[4] = colors_out[5] = colors_out[6] = white; + colors_in[0] = colors_in[1] = colors_in[2] = colors_in[7] = white; + colors_in[3] = colors_in[4] = colors_in[5] = colors_in[6] = gray; + + } + + glBegin( GL_POLYGON ); + glVertex2f( 0.0, 0.0 ); glVertex2f( -x1a, 0.0 ); + glVertex2f( -x1a, 0.0 ); glVertex2f( -x1b, y1 ); + glVertex2f( x1b, y1); glVertex2f( x1a, 0.0 ); + glVertex2f( x1a, 0.0 ); glVertex2f( 0.0, 0.0 ); + glEnd(); + glBegin( GL_TRIANGLES ); + glVertex2f( -x2, y1 ); glVertex2f( 0.0, y2 ); glVertex2f( x2, y1 ); + glEnd(); + + glLineWidth( 1.0 ); + /*** Draw arrow outline ***/ + glBegin( GL_LINES ); + + SET_COL_IN(1+c_off); DRAW_SEG( 0.0, y2-1.0, -x2, y1-1.0 ); + SET_COL_IN(6+c_off); DRAW_SEG( -x2+2.0, y1+1.0, -x1b+1.0, y1+1.0 ); + SET_COL_IN(0+c_off); DRAW_SEG( -x1b+1.0, y1+1.0, -x1a+1.0, y0 ); + SET_COL_IN(3+c_off); DRAW_SEG( 0.0, y2-1.0, x2, y1-1.0 ); + SET_COL_IN(6+c_off); DRAW_SEG( x2-1.0, y1+1.0, x1b-1.0, y1+1.0 ); + SET_COL_IN(4+c_off); DRAW_SEG( x1b-1.0, y1+1.0, x1a-1.0, y0 ); + + SET_COL_OUT(0+c_off); DRAW_SEG( -x1a, y0, -x1b, y1 ); + SET_COL_OUT(6+c_off); DRAW_SEG( -x1b, y1, -x2, y1 ); + SET_COL_OUT(1+c_off); DRAW_SEG( -x2, y1, 0.0, y2 ); + SET_COL_OUT(3+c_off); DRAW_SEG( 0.0, y2, x2, y1 ); + SET_COL_OUT(6+c_off); DRAW_SEG( x2, y1, x1b, y1 ); + SET_COL_OUT(4+c_off); DRAW_SEG( x1b, y1, x1a, y0 ); + + glEnd(); + +#undef DRAW_SEG + + glPopMatrix(); +} + + +/*************************** GLUI_Translation::get_mouse_code() *************/ + +int GLUI_Translation::get_mouse_code( int x, int y ) +{ + if ( x == 0 AND y < 0 ) + return GLUI_TRANSLATION_MOUSE_DOWN; + else if ( x == 0 AND y > 0 ) + return GLUI_TRANSLATION_MOUSE_UP; + else if ( x > 0 AND y == 0 ) + return GLUI_TRANSLATION_MOUSE_LEFT; + else if ( x < 0 AND y == 0 ) + return GLUI_TRANSLATION_MOUSE_RIGHT; + else if ( x < 0 AND y < 0 ) + return GLUI_TRANSLATION_MOUSE_DOWN_LEFT; + else if ( x < 0 AND y > 0 ) + return GLUI_TRANSLATION_MOUSE_DOWN_RIGHT; + else if ( x > 0 AND y < 0 ) + return GLUI_TRANSLATION_MOUSE_UP_LEFT; + else if ( x > 0 AND y > 0 ) + return GLUI_TRANSLATION_MOUSE_UP_RIGHT; + + + return GLUI_TRANSLATION_MOUSE_NONE; +} + + +/*********************************** GLUI_Translation::set_x() ******/ + +void GLUI_Translation::set_x( float val ) +{ + set_one_val( val, 0 ); +} + + +/*********************************** GLUI_Translation::set_y() ******/ + +void GLUI_Translation::set_y( float val ) +{ + if ( trans_type == GLUI_TRANSLATION_XY ) + set_one_val( val, 1 ); + else + set_one_val( val, 0 ); +} + + +/*********************************** GLUI_Translation::set_z() ******/ + +void GLUI_Translation::set_z( float val ) +{ + set_one_val( val, 0 ); +} + + +/******************************* GLUI_Translation::set_one_val() ****/ + +void GLUI_Translation::set_one_val( float val, int index ) +{ + float *fp; + + float_array_val[index] = val; /* set value in array */ + + /*** The code below is like output_live, except it only operates on + a single member of the float array (given by 'index') instead of + outputting the entire array ****/ + + if ( ptr_val == NULL OR NOT live_inited ) + return; + + fp = (float*) ptr_val; + fp[index] = float_array_val[index]; + last_live_float_array[index] = float_array_val[index]; + + /** Update the main gfx window? **/ + if ( this->glui != NULL ) { + this->glui->post_update_main_gfx(); + } +} diff --git a/Extras/glui/glui_tree.cpp b/Extras/glui/glui_tree.cpp new file mode 100644 index 000000000..1ed456d52 --- /dev/null +++ b/Extras/glui/glui_tree.cpp @@ -0,0 +1,278 @@ +/**************************************************************************** + + GLUI User Interface Toolkit + --------------------------- + + glui_panel.cpp - GLUI_Panel control class + + + -------------------------------------------------- + + Copyright (c) 1998 Paul Rademacher + + 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" + + +/****************************** GLUI_Tree::GLUI_Tree() **********/ +GLUI_Tree::GLUI_Tree(GLUI_Node *parent, const char *name, + int open, int inset) +{ + common_init(); + GLUI_StaticText *inset_label; + GLUI_Column *col; + + this->set_name( name ); + this->user_id = -1; + + if ( NOT open ) { + this->is_open = false; + this->h = GLUI_DEFAULT_CONTROL_HEIGHT + 7; + } + + parent->add_control( this ); + inset_label = new GLUI_StaticText(this,""); + inset_label->set_w(inset); + col = new GLUI_Column(this,true); + this->set_column(col); + this->set_alignment(GLUI_ALIGN_LEFT); +} + + +/****************************** GLUI_Tree::open() **********/ + +void GLUI_Tree::open( void ) +{ + if ( is_open ) + return; + is_open = true; + + GLUI_DRAWINGSENTINAL_IDIOM + + child_head = collapsed_node.child_head; + child_tail = collapsed_node.child_tail; + + collapsed_node.child_head = NULL; + collapsed_node.child_tail = NULL; + + if ( child_head != NULL ) { + ((GLUI_Control*) child_head)->unhide_internal( true ); + } + + glui->refresh(); +} + + +/****************************** GLUI_Tree::close() **********/ + +void GLUI_Tree::close( void ) +{ + if ( NOT glui ) + return; + + if ( NOT is_open ) + return; + is_open = false; + + GLUI_DRAWINGSENTINAL_IDIOM + + if ( child_head != NULL ) { + ((GLUI_Control*) child_head)->hide_internal( true ); + } + + collapsed_node.child_head = first_child(); + collapsed_node.child_tail = last_child(); + + child_head = NULL; + child_tail = NULL; + + this->h = GLUI_DEFAULT_CONTROL_HEIGHT + 7; + + glui->refresh(); +} + + +/**************************** GLUI_Tree::mouse_down_handler() **********/ + + +int GLUI_Tree::mouse_down_handler( int local_x, int local_y ) +{ + if ( local_y - y_abs > 18 ) { + initially_inside = currently_inside = false; + return false; + } + + currently_inside = true; + initially_inside = true; + redraw(); + + return false; +} + +/**************************** GLUI_Tree::mouse_held_down_handler() ****/ + +int GLUI_Tree::mouse_held_down_handler( + int local_x, int local_y, + bool new_inside ) +{ + if ( NOT initially_inside ) + return false; + + if ( local_y - y_abs> 18 ) + new_inside = false; + + if (currently_inside != new_inside) + redraw(); + + return false; +} + + +/**************************** GLUI_Tree::mouse_down_handler() **********/ + +int GLUI_Tree::mouse_up_handler( int local_x, int local_y, bool inside ) +{ + if ( currently_inside ) { + if ( is_open ) + close(); + else + open(); + } + + currently_inside = false; + initially_inside = false; + redraw(); + + return false; +} + + +/********************************* GLUI_Tree::draw() ***********/ + +void GLUI_Tree::draw( int x, int y ) +{ + GLUI_DRAWINGSENTINAL_IDIOM + int left, right, top, bottom, delta_x; + + left = 5; + right = w-left; + top = 3; + bottom = 3+16; + delta_x = 0; + + glui->draw_raised_box( left, top, 16, 16 ); + + if ( glui ) + glColor3ub(glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b); + glDisable( GL_CULL_FACE ); + glBegin( GL_QUADS ); + glVertex2i( left+17, top+1 ); glVertex2i( right-1, top+1 ); + glVertex2i( right-1, bottom-1 ); glVertex2i( left+17, bottom-1 ); + glEnd(); + + if (format & GLUI_TREEPANEL_DISPLAY_HIERARCHY) { + delta_x = string_width( level_name ) + char_width(' '); + glColor3f( lred, lgreen, lblue); /* The hierarchy is drawn in bold */ + glRasterPos2i(left + 25, top + 11); + draw_string(level_name); + glRasterPos2i(left + 24, top + 11); + draw_string(level_name); + } + + draw_name( delta_x+left+24, top+11 ); + + if ( active ) + draw_active_box( left+22, delta_x+left+string_width( name )+32, + top, bottom-2 ); + + + /** Draw '+' or '-' **/ + + glBegin( GL_LINES ); + if ( is_open ) { + if ( enabled ) + if (is_current) + glColor3f( 0, 0, 1 ); + else + glColor3f( 0.0, 0.0, 0.0 ); + else + glColor3f( 0.5, 0.5, 0.5 ); + glVertex2i(left+4,(top+bottom)/2); glVertex2i(left+13,(top+bottom)/2); + + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i(left+4,1+(top+bottom)/2);glVertex2i(left+13,1+(top+bottom)/2); + } + else + { + glColor3f( 1.0, 1.0, 1.0 ); + glVertex2i(left+9,top+3); glVertex2i(left+9,bottom-4); + glVertex2i(left+4,(top+bottom)/2); glVertex2i(left+13,(top+bottom)/2); + + if ( enabled ) + if (is_current) + glColor3f( 0, 0, 1 ); + else + glColor3f( 0.0, 0.0, 0.0 ); + else + glColor3f( 0.5, 0.5, 0.5 ); + glVertex2i(left+4,-1+(top+bottom)/2); + glVertex2i(left+13,-1+(top+bottom)/2); + glVertex2i(left+8,top+3); + glVertex2i(left+8,bottom-4); + } + glEnd(); + + glLineWidth( 1.0 ); + + if (currently_inside) draw_pressed(); +} + + +/***************************** GLUI_Tree::update_size() **********/ + +void GLUI_Tree::update_size( void ) +{ + int text_size = 0, delta_x = 0; + + if ( NOT glui ) + return; + + text_size = string_width(name); + + if (format & GLUI_TREEPANEL_DISPLAY_HIERARCHY) { + delta_x = string_width( level_name ); + } + + if ( w < text_size + 36 + delta_x) + w = text_size + 36 + delta_x; +} + + +/**************************** GLUI_Tree::draw_pressed() ***********/ + +void GLUI_Tree::draw_pressed( void ) +{ + int left, right, top, bottom; + + left = 5; + right = w-left; + top = 3; + bottom = 3+16; + + glColor3f( 0.0, 0.0, 0.0 ); + + glBegin( GL_LINE_LOOP ); + glVertex2i( left, top ); glVertex2i( right, top ); + glVertex2i( right, bottom ); glVertex2i( left,bottom ); + glEnd(); + + glBegin( GL_LINE_LOOP ); + glVertex2i( left+1, top+1 ); glVertex2i( right-1, top+1 ); + glVertex2i( right-1, bottom-1 ); glVertex2i( left+1,bottom-1 ); + glEnd(); +} diff --git a/Extras/glui/glui_treepanel.cpp b/Extras/glui/glui_treepanel.cpp new file mode 100644 index 000000000..6be2c5ee1 --- /dev/null +++ b/Extras/glui/glui_treepanel.cpp @@ -0,0 +1,387 @@ +#include "GL/glui.h" + + +/****************************** GLUI_TreePanel::GLUI_TreePanel() *********/ + +GLUI_TreePanel::GLUI_TreePanel(GLUI_Node *parent, const char *name, + bool open, int inset) +{ + common_init(); + + set_name( name ); + user_id = -1; + + if ( !open ) { + is_open = false; + h = GLUI_DEFAULT_CONTROL_HEIGHT + 7; + } + + parent->add_control( this ); +} + +/****************************** GLUI_TreePanel::set_color() *********/ + +void GLUI_TreePanel::set_color(float r, float g, float b) +{ + red = r; + green = g; + blue = b; + redraw(); +} + +/************************ GLUI_TreePanel::set_level_color() *********/ + +void GLUI_TreePanel::set_level_color(float r, float g, float b) +{ + lred = r; + lgreen = g; + lblue = b; + redraw(); +} + +/****************************** GLUI_TreePanel::ab() *********/ + +/* Adds branch to curr_root */ +GLUI_Tree *GLUI_TreePanel::ab(const char *name, GLUI_Tree *root) +{ + GLUI_Tree *temp; + + + if (root != NULL) { + resetToRoot(root); + } + + temp = new GLUI_Tree(curr_root, name); + initNode(temp); + formatNode(temp); + + curr_root = temp; + curr_branch = NULL; /* Currently at leaf */ + + if (dynamic_cast(temp)) + ((GLUI_Tree *)temp)->set_current(true); + //refresh(); + // glui->deactivate_current_control(); + //glui->activate_control( temp, GLUI_ACTIVATE_TAB ); + return temp; + +} + +/****************************** GLUI_TreePanel::fb() *********/ + +/* Goes up one level, resets curr_root and curr_branch to parents*/ +void GLUI_TreePanel::fb(GLUI_Tree *branch) +{ + if (((GLUI_Panel *)branch) == ((GLUI_Panel *)this)) + return; + + if (((GLUI_Panel *)curr_branch) == ((GLUI_Panel *)this)) { + resetToRoot(); + return; + } + if (((GLUI_Panel *)curr_root) == ((GLUI_Panel *)this)) { + resetToRoot(); + return; + } + + if (branch != NULL) { + + if ( dynamic_cast(branch) ) + ((GLUI_Tree *)branch)->set_current(false); + + curr_branch = (GLUI_Tree *)branch->next(); + curr_root = (GLUI_Panel *)branch->parent(); + + if (curr_branch == NULL && (curr_root->collapsed_node).first_child() != NULL) + curr_branch = (GLUI_Tree *)(curr_root->collapsed_node).first_child(); + + if ( dynamic_cast(curr_root) ) + ((GLUI_Tree *)curr_root)->set_current(true); + + } else { + if (curr_root != NULL) { /* up one parent */ + + if (dynamic_cast(curr_root)) + ((GLUI_Tree *)curr_root)->set_current(false); + + curr_branch = (GLUI_Tree *) curr_root->next(); + curr_root = (GLUI_Panel *) curr_root->parent(); + + if (curr_branch == NULL && (curr_root->collapsed_node).first_child() != NULL) + curr_branch = (GLUI_Tree *)(curr_root->collapsed_node).first_child(); + + if (dynamic_cast(curr_root)) + ((GLUI_Tree *)curr_root)->set_current(true); + + } + + } + //refresh(); +} + + +/****************************** GLUI_TreePanel::refresh() *********/ + +void GLUI_TreePanel::refresh() +{ + glui->deactivate_current_control(); + glui->activate_control( curr_root, GLUI_ACTIVATE_TAB ); + + redraw(); +} + +/****************************** GLUI_TreePanel::initNode() *********/ + +void GLUI_TreePanel::initNode(GLUI_Tree *temp) +{ + if (temp == NULL) + return; + int level = temp->get_level(); + int child_number = 1; + + GLUI_Tree *ptree = dynamic_cast(temp->parent()); + if (ptree) { + level = ptree->get_level() + 1; + GLUI_Tree *prevTree = dynamic_cast(temp->prev()); + if (prevTree) { + child_number = prevTree->get_child_number() + 1; + } + } else if (dynamic_cast(temp) && + dynamic_cast(temp->parent())) { + child_number = ++root_children; + } + temp->set_id(uniqueID()); // -1 if unset + temp->set_level(level); + temp->set_child_number(child_number); +} + +/****************************** GLUI_TreePanel::formatNode() *********/ + +void GLUI_TreePanel::formatNode(GLUI_Tree *temp) +{ + if (temp == NULL) + return; + int level = temp->get_level(); + int child_number = temp->get_child_number(); + GLUI_String level_name=""; + GLUI_String full_name=""; + + temp->level_name == ""; + + if (format & GLUI_TREEPANEL_DISPLAY_HIERARCHY) { + if (format & GLUI_TREEPANEL_HIERARCHY_LEVEL_ONLY) { + glui_format_str(level_name, "%d", level); + } + if (format & GLUI_TREEPANEL_HIERARCHY_NUMERICDOT) { + if ( dynamic_cast(temp->parent()) ) + glui_format_str(level_name, "%s.%d", + ((GLUI_Tree *)(temp->parent()))->level_name.c_str(), + child_number); + else + glui_format_str(level_name, "%d", child_number); + } + } + + temp->set_level_color(lred, lgreen, lblue); + temp->set_format(format); + temp->level_name = level_name; + + if (format & GLUI_TREEPANEL_ALTERNATE_COLOR) { + switch (level%8) { + case (7): temp->set_color(.5,.5,.5); break; + case (6): temp->set_color(.3,.5,.5); break; + case (5): temp->set_color(.5,.3,.5); break; + case (4): temp->set_color(.3,.3,.5); break; + case (3): temp->set_color(.5,.5,.3); break; + case (2): temp->set_color(.3,.5,.3); break; + case (1): temp->set_color(.5,.3,.3); break; + default: temp->set_color(.3,.3,.3); + } + } else { + temp->set_color(red,green,blue); + } + + if (format & GLUI_TREEPANEL_DISABLE_BAR) { + temp->disable_bar(); + } else { + if (format & GLUI_TREEPANEL_DISABLE_DEEPEST_BAR) { + temp->disable_bar(); + if ( dynamic_cast(curr_root) ) + ((GLUI_Tree *)curr_root)->enable_bar(); + } else + if (format & GLUI_TREEPANEL_CONNECT_CHILDREN_ONLY) { + temp->disable_bar(); + if (temp->prev() && dynamic_cast(temp->prev()) ) + { + ((GLUI_Tree *)temp->prev())->enable_bar(); + } + } + } +} + +/****************************** GLUI_TreePanel::update_all() *********/ + +void GLUI_TreePanel::update_all() +{ + printf("GLUI_TreePanel::update_all() doesn't work yet. - JVK\n"); + return; + GLUI_Panel *saved_root = curr_root; + GLUI_Tree *saved_branch = curr_branch; + root_children = 0; + resetToRoot(this); + if (curr_branch && dynamic_cast(curr_branch)) + formatNode((GLUI_Tree *)curr_branch); + next(); + while (curr_root && curr_branch != this->first_child()) { + if (curr_branch && dynamic_cast(curr_branch)) { + formatNode((GLUI_Tree *)curr_branch); + } + next(); + } + curr_root = saved_root; + curr_branch = saved_branch; +} + +/****************************** GLUI_TreePanel::expand_all() *********/ + +void GLUI_TreePanel::expand_all() +{ + GLUI_Panel *saved_root = curr_root; + GLUI_Tree *saved_branch = curr_branch; + + resetToRoot(this); + if (dynamic_cast(curr_root)) + ((GLUI_Tree*)curr_root)->open(); + next(); + while (curr_root != NULL && curr_branch != this->first_child()) { + if (dynamic_cast(curr_root)) + ((GLUI_Tree*)curr_root)->open(); + next(); + } + + curr_root = saved_root; + curr_branch = saved_branch; +} + +/****************************** GLUI_TreePanel::collapse_all() *********/ + +void GLUI_TreePanel::collapse_all() +{ + GLUI_Panel *saved_root = curr_root; + GLUI_Tree *saved_branch = curr_branch; + + resetToRoot(this); + next(); + while (curr_root != NULL && curr_branch != this->first_child()) { + if (dynamic_cast(curr_root) && + curr_branch == NULL) { /* we want to close everything leaf-first */ + ((GLUI_Tree*)curr_root)->close(); + /* Rather than simply next(), we need to manually move the + curr_root because this node has been moved to the + collapsed_node list */ + curr_branch = (GLUI_Tree *)curr_root->next(); + curr_root = (GLUI_Panel *)curr_root->parent(); + } else + next(); + } + + curr_root = saved_root; + curr_branch = saved_branch; + +} + +/****************************** GLUI_TreePanel::db() *********/ + +/* Deletes the curr_root */ +void GLUI_TreePanel::db(GLUI_Tree *root) +{ + GLUI_Tree *temp_branch; + GLUI_Panel *temp_root; + + if (((GLUI_Control *)root) == ((GLUI_Control *)this)) + return; + + if (root != NULL) { + curr_root = (GLUI_Tree *)root; + curr_branch = NULL; + } + + if (curr_root == NULL || ((GLUI_Panel *)curr_root) == ((GLUI_Panel *)this)) { + resetToRoot(); + return; + } + + + temp_branch = (GLUI_Tree *)curr_root->next(); /* Next branch, if any */ + temp_root = (GLUI_Panel *)curr_root->parent(); /* new root */ + curr_root->unlink(); + delete curr_root; + curr_branch = (GLUI_Tree *) temp_branch; + curr_root = (GLUI_Panel *) temp_root; + if (dynamic_cast(curr_root)) + ((GLUI_Tree *)curr_root)->open(); + + if ((format & GLUI_TREEPANEL_DISABLE_DEEPEST_BAR) == GLUI_TREEPANEL_DISABLE_DEEPEST_BAR) { + if (dynamic_cast(curr_root) && ((GLUI_Tree *)curr_root->next()) == NULL) + ((GLUI_Tree *)curr_root)->disable_bar(); + } + //refresh(); +} + +/****************************** GLUI_TreePanel::descendBranch() *********/ + +/* Finds the very last branch of curr_root, resets vars */ +void GLUI_TreePanel::descendBranch(GLUI_Panel *root) { + if (root) + resetToRoot(root); + else + resetToRoot(curr_root); + if (curr_branch != NULL && curr_branch != ((GLUI_Panel *)this)) { + if (dynamic_cast(curr_root)) + ((GLUI_Tree *)curr_root)->set_current(false); + descendBranch(curr_branch); + } +} + +/****************************** GLUI_TreePanel::next() *********/ + +void GLUI_TreePanel::next() +{ + if (curr_root == NULL) + resetToRoot(this); + + if (curr_branch == NULL && (curr_root->collapsed_node).first_child() != NULL) + curr_branch = (GLUI_Tree *)(curr_root->collapsed_node).first_child(); + + + if (curr_branch != NULL && curr_branch != ((GLUI_Panel *)this)) { /* Descend into branch */ + if (dynamic_cast(curr_root)) + ((GLUI_Tree *)curr_root)->set_current(false); + resetToRoot(curr_branch); + } else if (curr_branch == NULL) { + fb(NULL); /* Backup and move on */ + } +} + +/****************************** GLUI_TreePanel::resetToRoot() *********/ + +/* Resets curr_root and curr branch to TreePanel and lastChild */ +void GLUI_TreePanel::resetToRoot(GLUI_Panel *new_root) +{ + GLUI_Panel *root = this; + if (new_root != NULL) + root = new_root; + curr_root = root; + if (dynamic_cast(curr_root)) + ((GLUI_Tree *)curr_root)->set_current(true); + curr_branch = (GLUI_Tree *)root->first_child(); + + /* since Trees are collapsable, we need to check the collapsed nodes + in case the curr_root is collapsed */ + if (curr_branch == NULL && (root->collapsed_node).first_child() != NULL) { + curr_branch = (GLUI_Tree *)(root->collapsed_node).first_child(); + } + while (curr_branch && dynamic_cast(curr_branch)) { + curr_branch=(GLUI_Tree *)curr_branch->next(); + } +} diff --git a/Extras/glui/glui_window.cpp b/Extras/glui/glui_window.cpp new file mode 100644 index 000000000..c028e248e --- /dev/null +++ b/Extras/glui/glui_window.cpp @@ -0,0 +1,44 @@ +/* + + glui_window.cpp - GLUI_Button control class + + GLUI User Interface Toolkit (LGPL) + 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 "GL/glui.h" +#include "glui_internal.h" + +GLUI_Glut_Window::GLUI_Glut_Window() +: GLUI_Node(), + + glut_window_id(0), + glut_keyboard_CB(NULL), + glut_special_CB(NULL), + glut_reshape_CB(NULL), + glut_passive_motion_CB(NULL), + glut_mouse_CB(NULL), + glut_visibility_CB(NULL), + glut_motion_CB(NULL), + glut_display_CB(NULL), + glut_entry_CB(NULL) +{ +} diff --git a/Extras/glui/quaternion.cpp b/Extras/glui/quaternion.cpp new file mode 100644 index 000000000..3e80242af --- /dev/null +++ b/Extras/glui/quaternion.cpp @@ -0,0 +1,243 @@ +/*********************************************************************** + + quaternion.cpp - A quaternion class + + ------------------------------------------------------------------- + + GLUI User Interface Toolkit (LGPL) + 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 + +************************************************************************ + + Feb 1998, Paul Rademacher (rademach@cs.unc.edu) + Oct 2003, Nigel Stewart - GLUI Code Cleaning + +************************************************************************/ + +#include "quaternion.h" +#include +#include "glui_internal.h" + +/******************************************* constructors **************/ + +quat::quat() +{ + *this = quat_identity(); +} + +quat::quat(const float x, const float y, const float z, const float w) +{ + v.set( x, y, z ); + s = w; +} + +quat::quat(const vec3 &_v, const float _s) +{ + set( _v, _s ); +} + +quat::quat(const float _s, const vec3 &_v) +{ + set( _v, _s ); +} + +quat::quat(const float *d) +{ + v[0] = d[0]; + v[1] = d[1]; + v[2] = d[2]; + s = d[3]; +} + +quat::quat(const double *d) +{ + v[0] = (float) d[0]; + v[1] = (float) d[1]; + v[2] = (float) d[2]; + s = (float) d[3]; +} + +quat::quat(const quat &q) +{ + v = q.v; + s = q.s; +} + +void quat::set(const vec3 &_v, const float _s) +{ + v = _v; + s = _s; +} + +quat &quat::operator=(const quat &q) +{ + v = q.v; + s = q.s; + return *this; +} + +/******** quat friends ************/ + +quat operator + (const quat &a, const quat &b) +{ + return quat( a.s+b.s, a.v+b.v ); +} + +quat operator - (const quat &a, const quat &b) +{ + return quat( a.s-b.s, a.v-b.v ); +} + +quat operator - (const quat &a ) +{ + return quat( -a.s, -a.v ); +} + +quat operator * ( const quat &a, const quat &b) +{ + return quat( a.s*b.s - a.v*b.v, a.s*b.v + b.s*a.v + a.v^b.v ); +} + +quat operator * ( const quat &a, const float t) +{ + return quat( a.v * t, a.s * t ); +} + +quat operator * ( const float t, const quat &a ) +{ + return quat( a.v * t, a.s * t ); +} + +mat4 quat::to_mat4() const +{ + float xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz; + + float t = 2.0f / (v*v + s*s); + + xs = v[VX]*t; ys = v[VY]*t; zs = v[VZ]*t; + wx = s*xs; wy = s*ys; wz = s*zs; + xx = v[VX]*xs; xy = v[VX]*ys; xz = v[VX]*zs; + yy = v[VY]*ys; yz = v[VY]*zs; zz = v[VZ]*zs; + + mat4 matrix( + 1.0f-(yy+zz), xy+wz, xz-wy, 0.0f, + xy-wz, 1.0f-(xx+zz), yz+wx, 0.0f, + xz+wy, yz-wx, 1.0f-(xx+yy), 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f ); + + return matrix; +} + +/************************************************* quat_identity() *****/ +/* Returns quaternion identity element */ + +quat quat_identity() +{ + return quat( vec3( 0.0, 0.0, 0.0 ), 1.0 ); +} + +/************************************************ quat_slerp() ********/ +/* Quaternion spherical interpolation */ + +quat quat_slerp(const quat &from, const quat &to, float t) +{ + quat to1; + float omega, cosom, sinom, scale0, scale1; + + /* calculate cosine */ + cosom = from.v * to.v + from.s + to.s; + + /* Adjust signs (if necessary) */ + if ( cosom < 0.0 ) + { + cosom = -cosom; + to1 = -to; + } + else + { + to1 = to; + } + + /* Calculate coefficients */ + if ((1.0 - cosom) > FUDGE ) + { + /* standard case (slerp) */ + omega = (float) acos( cosom ); + sinom = (float) sin( omega ); + scale0 = (float) sin((1.0 - t) * omega) / sinom; + scale1 = (float) sin(t * omega) / sinom; + } + else + { + /* 'from' and 'to' are very close - just do linear interpolation */ + scale0 = 1.0f - t; + scale1 = t; + } + + return scale0 * from + scale1 * to1; +} + +/********************************************** set_angle() ************/ +/* set rot angle (degrees) */ + +void quat::set_angle(float f) +{ + vec3 axis = get_axis(); + + s = (float) cos( DEG2RAD( f ) / 2.0 ); + + v = axis * (float) sin(DEG2RAD(f) / 2.0); +} + +/********************************************** scale_angle() ************/ +/* scale rot angle (degrees) */ + +void quat::scale_angle(float f) +{ + set_angle( f * get_angle() ); +} + +/********************************************** get_angle() ************/ +/* get rot angle (degrees). Assumes s is between -1 and 1 */ + +float quat::get_angle() const +{ + return (float) RAD2DEG( 2.0 * acos( s ) ); +} + +/********************************************* get_axis() **************/ + +vec3 quat::get_axis() const +{ + float scale = (float) sin( acos( s ) ); + + if ( scale < FUDGE AND scale > -FUDGE ) + return vec3( 0.0, 0.0, 0.0 ); + else + return v / scale; +} + +/******************************************* quat::print() ************/ + +void quat::print(FILE *dest, const char *name) const +{ + fprintf( dest, "%s: v:<%3.2f %3.2f %3.2f> s:%3.2f\n", + name, v[0], v[1], v[2], s ); +} diff --git a/Extras/glui/quaternion.h b/Extras/glui/quaternion.h new file mode 100644 index 000000000..8bd458232 --- /dev/null +++ b/Extras/glui/quaternion.h @@ -0,0 +1,114 @@ +/**************************************************************************** + + quaternion.h - A quaternion class + + GLUI User Interface Toolkit (LGPL) + 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 + +*****************************************************************************/ + +#ifndef GLUI_QUATERNION_H +#define GLUI_QUATERNION_H + +#include "algebra3.h" +#include + +/* this line defines a new type: pointer to a function which returns a */ +/* float and takes as argument a float */ +typedef float (*V_FCT_PTR)(float); + +/**************************************************************** + * Quaternion * + ****************************************************************/ + +class quat +{ + /*protected: */ +public: + + vec3 v; /* vector component */ + float s; /* scalar component */ + + /*public: */ + + /* Constructors */ + + quat(); + quat(float x, float y, float z, float w); + quat(const vec3 &v, float s); + quat(float s, const vec3 &v); + quat(const float *d); /* copy from four-element float array */ + quat(const double *f); /* copy from four-element double array */ + quat(const quat &q); /* copy from other quat */ + + /* Assignment operators */ + + quat &operator = (const quat &v); /* assignment of a quat */ + quat &operator += (const quat &v); /* incrementation by a quat */ + quat &operator -= (const quat &v); /* decrementation by a quat */ + quat &operator *= (float d); /* multiplication by a constant */ + quat &operator /= (float d); /* division by a constant */ + + /* special functions */ + + float length() const; /* length of a quat */ + float length2() const; /* squared length of a quat */ + quat &normalize(); /* normalize a quat */ + quat &apply(V_FCT_PTR fct); /* apply a func. to each component */ + vec3 xform(const vec3 &v ); /* q*v*q-1 */ + mat4 to_mat4() const; + void set_angle(float f); /* set rot angle (degrees) */ + void scale_angle(float f); /* scale rot angle (degrees) */ + float get_angle() const; /* set rot angle (degrees) */ + vec3 get_axis() const; /* get axis */ + + void print( FILE *file, const char *name ) const; /* print to a file */ + + float &operator [] (int i); /* indexing */ + const float &operator [] (int i) const; /* indexing */ + + void set(float x, float y, float z); /* set quat */ + void set(const vec3 &v, float s); /* set quat */ + + /* friends */ + + friend quat operator - (const quat &v); /* -q1 */ + friend quat operator + (const quat &a, const quat &b); /* q1 + q2 */ + friend quat operator - (const quat &a, const quat &b); /* q1 - q2 */ + friend quat operator * (const quat &a, float d); /* q1 * 3.0 */ + friend quat operator * (float d, const quat &a); /* 3.0 * q1 */ + friend quat operator * (const quat &a, const quat &b); /* q1 * q2 */ + friend quat operator / (const quat &a, float d); /* q1 / 3.0 */ + friend int operator == (const quat &a, const quat &b); /* q1 == q2 ? */ + friend int operator != (const quat &a, const quat &b); /* q1 != q2 ? */ + friend void swap(quat &a, quat &b); /* swap q1 &q2 */ + /*friend quat min(const quat &a, const quat &b); -- min(q1, q2) */ + /*friend quat max(const quat &a, const quat &b); -- max(q1, q2) */ + friend quat prod(const quat &a, const quat &b); /* term by term mult*/ +}; + +/* Utility functions */ + +quat quat_identity(); /* Returns quaternion identity element */ +quat quat_slerp(const quat &from, const quat &to, float t); + +#endif diff --git a/Extras/glui/readme.txt b/Extras/glui/readme.txt new file mode 100644 index 000000000..43ba3ed52 --- /dev/null +++ b/Extras/glui/readme.txt @@ -0,0 +1,228 @@ +Welcome to the GLUI User Interface Library, v2.3! +March 22, 2005 +------------------------------------------------- + +This distribution contains the latest community-maintained fork of the +GLUI Library. It is based on the GLUI v2.1 beta version from Paul +Rademacher (http://www.cs.unc.edu/~rademach/glui/) plus the +compatibility changes made by Nigel Stewart in his "GLUI v2.2" +(http://www.nigels.com/glt/glui) In accordance with the LGPL under +which the library is released (according to Paul's web page at least), +these changes are available to everyone in the community. + +WARNING: This version (2.3) introduces some incompatible changes with +previous versions!! + +CHANGES: + +---------------------------------- +- GLUI_String is now a std::string + This is the main source of most incopatibilities, but I felt it was + a necessary change, because the previous usage of a fixed-sized + buffer was just too unsafe. I myself was bitten a few times passing + a char* buffer of insufficient size into GLUI as a live variable. + It is still possible to use a char buffer, but it is not recommended. + + If you used GLUI_String before as a live var type, the easiest way + to get your code compiling again is to change those to "char + buf[300]". The better way, though, is to update your code to treat + it as a std::string. + + For instance, if you used to pass mystr to functions that take + 'const char*', now use mystr.c_str() method, instead. + If you used strcpy(mystr, b) to set the value, now just do mystr=b. + If you used sprintf(mystr,...) to set the value, now do + glui_format_string(mystr,...). + If you used to clear the string with mystr[0]='\0', now just clear + it with mystr="". + +---------------------------------- +- Enhanced GLUI_EditText + Control keys can be used for navigation and control. The bindings + are bash-like: Ctrl-B for previous char, Ctrl-F for forward char, etc. + bindings. Also control keys that aren't bound to commands are + simply ignored, whereas before they would be inserted as invisible + characters. + +---------------------------------- +- Added GLUI_CommandLine class + This is a GLUI_EditText with a history mechanism. + +---------------------------------- +- New, more object oriented construction API. + Now instead of calling + + glui->add_button_to_panel( panel, "my button", myid, mycallback ); + + you should just call the button constructor: + + new GLUI_Button( panel, "my button", myid, mycallback ); + + And similarly to add it to a GLUI instead of a panel, rather than: + + glui->add_button( glui, "my button", myid, mycallback ); + + just call the constructor with the GLUI as the first argument: + + new GLUI_Button( glui, "my button", myid, mycallback ); + + The old scheme is now deprecated, but still works. The benefit of + this new scheme is that now the GLUI class doesn't have to know + about all the different types of GLUI_Controls that exist. + Previously GLUI had to both know about all the controls, and know + how to initialize them. Now the responsibility for initialization + belongs to the GLUI_Control subclasses themselves, where it + belongs. Additionally it means that you can create your own + GLUI_Control subclasses which will be on equal footing with the + built-in controls, whereas before any user-created controls would + always be "second-class citizens" since they would have to be + constructed differently from the built-ins. + + +---------------------------------- +- Removed need for type-declaring arguments when argment type suffices. + This effects GLUI_Spinner and GLUI_EditText (and GLUI_CommandLine?). + + For example, instead of calling + + new GLUI_Spinner( glui, "myspin", GLUI_SPINNER_INT, &live_int_var ); + + you can just omit the GLUI_SPINNER_INT part, because the type of the + live_int_var tells the compiler which type you want. + + new GLUI_Spinner( glui, "myspin", &live_int_var ); + + If you're not using a live, var, you can still use the + GLUI_SPINNER_INT type argument. See glui.h for all the new + constructor signatures. Note this only works with the new + construction API, not with the old "add_blah_to_panel" style of + API. + +---------------------------------- +- GLUI_Rotation uses your matrix live-variable now. + GLUI used to ignore the matrix in your live variable. This version + doesn't ignore it, so you'll need to set it to the identity matrix + yourself if that's what you want it to start as. There could + probably be some improvements to this API, though. + +---------------------------------- +- Improvements to 'const' usage. + Most char*'s in GLUI functions used to be non-const even when the + functions did not modify the string. I changed everywhere + appropriate to use const char* instead. + +---------------------------------- +- Updated license info in the headers + Paul's web page says that GLUI is LGPL, but that wasn't declared in + the code itself. I've modified all the headers with the standard + LGPL notice. + +---------------------------------- +- Updated examples for the API changes + +---------------------------------- +- Created project files for Visual Studio .NET (MSVC7.1) + + +That's about it. Enjoy! + + +If you find yourself with too much time on your hands, the things I +think would be most useful for future improvements to GLUI would be: + +1. The GLUI_TextBox and GLUI_Tree definitely need some work, still. +2. Clipboard integration under Windows/X-Win. I have some code that + works on Win32 that I once integrated with GLUI, but I lost that + version somewhere. I still have the Win32 clipboard code, though + if anyone wants to work on integrating it. I have some X-Win + clipboard code, too, but I never got it working quite right. +3. Remove the dependency on GLUT, making the connection with window + system APIs into a more plug-in/adapter modular design. + So e.g. if you want to use GLUT, you'd link with the GLUI lib and a + GLUI_GLUT lib, and call one extra GLUI_glut_init() function or + something. + + +Definitly consider submitting a patch if you've made some nice improvements +to GLUI. Hopefully being an LGPL sourceforge project will attract some new +interest to the GLUI project. + +Bill Baxter +baxter +at +cs unc edu + +================================================= +JOHN KEW'S ADDITIONS (March 2005) +================================================= + +Thanks to John Kew of Natural Solutions Inc., +there are some new widgets. These are demonstrated in example6.cpp. + +The new widgets are: + +* GLUI_Scrollbar - A scrollbar slider widget +* GLUI_TextBox - A multi-line text widget +* GLUI_List - A static choice list +* GLUI_FileBrowser - A simple filebrowser based on GLUI_List +* GLUI_Tree - Hierarchical tree widget +* GLUI_TreePanel - Manager for the tree widget + +And one other change: + +* GLUI_Rollout has optional embossed border + +================================================= +PAUL'S ORIGINAL GLUI 2.0/2.1 README +================================================= + +Welcome to the GLUI User Interface Library, v2.0 beta! +------------------------------------------------- + +This distribution contains the full GLUI sources, as well as 5 example +programs. You'll find the full manual under "glui_manual.pdf". The +GLUI web page is at + + http://www.cs.unc.edu/~rademach/glui + + + ---------- Windows ---------- + +The directory 'msvc' contains a Visual C++ workspace entitled +'glui.dsw'. To recompile the library and examples, open this +workspace and run the menu command "Build:Batch Build:Build". The 3 +executables will be in the 'bin' directory, and the library in the +'lib' directory. + +To create a new Windows executable using GLUI, create a "Win32 Console +Application" in VC++, add the GLUI library (in 'msvc/lib/glui32.lib'), +and add the OpenGL libs: + + glui32.lib glut32.lib glu32.lib opengl32.lib (Microsoft OpenGL) + +Include the file "glui.h" in any file that uses the GLUI library. + + + ---------- Unix ---------- + +An SGI/HP makefile is found in the file 'makefile' (certain lines may need +to be commented/uncommented). + +To include GLUI in your own apps, add the glui library to your +makefile (before the glut library 'libglut.a'), and include "glui.h" +in your sources. + + + +---------------------------------------------------------------------- + +Please let me know what you think, what you'd like to change or add, +and especially what bugs you encounter. Also, please send me your +e-mail so I can add you to a mailing list for updates. + +Good luck, and thanks for trying this out! + +Paul Rademacher +rademach +at +cs unc edu \ No newline at end of file