/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ### File Specific: main-programmer: Benjamin Grauer */ #include #include "orxonox_gui_gtk.h" using namespace std; // temporarily. #include "orxonox_gui_flags.h" #include "orxonox_gui_exec.h" extern Window* orxonoxGUI; extern OrxonoxGuiFlags* flags; extern OrxonoxGuiExec* exec; /* WIDGET */ /** \brief deletes any given Widget This is still pretty crappy. */ Widget::~Widget() { // cout << "hiding: " <label <<"\n"; this->hide(); // cout << "check if Packer: "<label <<"\n"; if (this->isOption < 0) { // cout << "get Down "<label <<"\n"; static_cast(this)->down->~Widget(); } // cout << "next != NULL?: " <label <<"\n"; if (this->next != NULL) this->next->~Widget(); cout << "delete Widget: " <label <<"\n"; // delete widget; } /** \brief Initializes a widget. Initializes the next Pointer and the other Widget-specific Defaults. */ void Widget::init() { next = NULL; label = NULL; return; } /** \brief makes the widget visible. */ void Widget::show() { gtk_widget_show (this->widget); } /** \brief hides the widget. */ void Widget::hide() { gtk_widget_hide (this->widget); } /** \brief Sets the resolution of a specific widget to the given size. \param width the width of the widget to set. \param height the height of the widget to set. */ void Widget::setSize(int width, int height) { gtk_widget_set_usize (this->widget, width, height); } /** \brief Connect any signal to any given Sub-widget */ gulong Widget::connectSignal (char* event, gint (*signal)(GtkWidget*, GdkEvent*, void *)) { return g_signal_connect (G_OBJECT (this->widget), event, G_CALLBACK (signal), NULL); } /** \brief Connect a signal with additionally passing the whole Object */ gulong Widget::connectSignal (char* event, gint (*signal)( GtkWidget*, Widget *)) { return g_signal_connect (G_OBJECT (this->widget), event, G_CALLBACK (signal), this); } /** \brief Connect a signal with additionally passing a whole external Object */ gulong Widget::connectSignal (char* event, void* extObj, gint (*signal)(GtkWidget*, GdkEvent*, void *)) { return g_signal_connect (G_OBJECT (this->widget), event, G_CALLBACK (signal), extObj); } /** \brief Connect a signal with additionally passing a whole external Object */ gulong Widget::connectSignal (char* event, void* extObj, gint (*signal)(GtkWidget*, GdkEventKey*, void *)) { return g_signal_connect (G_OBJECT (this->widget), event, G_CALLBACK (signal), extObj); } void Widget::disconnectSignal (gulong signalID) { g_signal_handler_disconnect (G_OBJECT (this->widget), signalID); } /** \brief Moves through all the Widgets downwards from this and executes the function on them. \param function must be of type void and takes a Widget* as an Input. */ void Widget::walkThrough (void (*function)(Widget*)) { function(this); if (this->isOption < 0) { static_cast(this)->down->walkThrough (function); } if (this->next != NULL) this->next->walkThrough(function); } /** \brief This is for listing the option of "widget" \param widget specifies the widget that should be listed */ void Widget::listOptions (Widget* widget) { if (widget->isOption >= 1) cout << static_cast(widget)->label <<" is : " << static_cast(widget)->value <isOption >= 1) static_cast(widget)->redraw();// <<" is : " << static_cast(this)->value <setGroupName (""); static_cast(this)->init(); return; } /** \brief Sets the group name under which all the lower widgets of this will be saved. \param name The name of the group. */ void Packer::setGroupName (char* name) { groupName = name; } /** \brief Retrieves the group name under which all the lower widgets of this will be saved. \returns name The name of the group. */ char* Packer::getGroupName (void) { return groupName; } /* CONTAINERS */ /** \brief Initializes a Container. sets the Container-Specific defaults. */ void Container::init (void) { isOption = -1; static_cast(this)->init(); return; } /** \briefFills a Container with lowerWidget. It does this by filling up the down pointer only if down points to NULL. \param lowerWidget the Widget that should be filled into the Container. */ void Container::fill (Widget *lowerWidget) { if (this->down == NULL) { gtk_container_add (GTK_CONTAINER (this->widget), lowerWidget->widget); this->down = lowerWidget; } else cout << "!!error!! You try to put more than one Widget into a Container. \nNot including this item.\nThis is only possible with Boxes.\n"<next) tmpWindow = tmpWindow->next; tmpWindow->next = windowToAdd; return; } /** \brief Creating a new Window without a Name */ Window::Window (void) { this->init(); } /** \brief Creating a Window with a name \param windowName the name the window should get. */ Window::Window (char* windowName) { this->init(); this->setTitle (windowName); } /** \brief initializes a new Window */ void Window::init() { if (!mainWindow) mainWindow = this; isOpen = false; static_cast(this)->init(); widget = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_policy (GTK_WINDOW(widget), TRUE, TRUE, TRUE); #if !defined(__WIN32__) // gtk_window_set_decorated (GTK_WINDOW (widget), FALSE); #endif gtk_container_set_border_width (GTK_CONTAINER (widget), 3); } /** \brief Shows all Widgets that are included within this->widget. */ void Window::showall () { if (!isOpen) { printf ("showall\n"); gtk_widget_show_all (widget); isOpen = true; } else { printf ("showone\n"); gtk_widget_show (widget); } } /** \brief Set The Window-title to title \param title title the Window should get. */ void Window::setTitle (char* title) { if (label) delete label; label = new char[strlen(title)+1]; strcpy(label, title); gtk_window_set_title (GTK_WINDOW (widget), title); } /** \brief opens up a Window and fixes the Focus to it */ void Window::open() { if (this != mainWindow) { isOpen = true; gtk_widget_show_all(widget); gtk_grab_add(widget); } } /** \brief closes up a Window and removes the Focus from it */ void Window::close() { if (this != mainWindow) { isOpen = false; gtk_grab_remove(widget); gtk_widget_hide (widget); } } /** \brief opens up a window (not topmost Window). this is the Signal that does it. !!SIGNALS ARE STATIC!! \param widget the widget that did it! \param event the event that did it! \param window the Window that should be opened */ gint Window::windowOpen (GtkWidget *widget, GdkEvent* event, void* window) { static_cast(window)->open(); } /** \brief closes a window (not topmost Window). this is the Signal that does it. !!SIGNALS ARE STATIC!! \param widget the widget that did it! \param event the event that did it! \param window the Window that should be closed */ gint Window::windowClose (GtkWidget *widget, GdkEvent* event, void* window) { static_cast(window)->close(); } /** * Quits the orxonox_GUI. * This can be called as a Signal and is therefor static \param widget The widget that called this function \param event the event that happened to execute this function \param data some data passed with the Signal */ gint Window::orxonox_gui_quit (GtkWidget *widget, GdkEvent *event, gpointer data) { if (exec->shouldsave()) exec->writeToFile (orxonoxGUI); gtk_main_quit(); return FALSE; } /* FRAME */ /** \brief Creates a new Frame without a name */ Frame::Frame (void) { this->init(); } /** \brief Creates a new Frame with name title */ Frame::Frame (char* title) { this->init(); this->setTitle(title); } /** \brief Initializes a new Frame with default settings */ void Frame::init() { static_cast(this)->init(); widget = gtk_frame_new (""); gtk_container_set_border_width (GTK_CONTAINER (widget), 3); } /** \brief Sets the Frames name to title \param title The title the Frame should get. */ void Frame::setTitle (char* title) { if (label) delete label; label = new char[strlen(title)+1]; strcpy(label, title); gtk_frame_set_label (GTK_FRAME (widget), title); } // EVENTBOX // /** \brief Creates a new EventBox with default settings. */ EventBox::EventBox () { this->init(); } /** \brief Creates a new EventBox with name title \param title title the Eventbox should get (only data-structure-internal) */ EventBox::EventBox (char* title) { this->init(); this->setTitle(title); } /** \brief Initializes a new EventBox */ void EventBox::init(void) { isOption = -1; static_cast(this)->init(); widget = gtk_event_box_new (); gtk_container_set_border_width (GTK_CONTAINER (widget), 3); } /** \brief Sets the Title of the EventBox (not implemented) \param title Name the EventBox should get (only datastructure-internal). */ void EventBox::setTitle (char* title) { if (label) delete label; label = new char[strlen(title)+1]; strcpy(label, title); } /* BOX */ /** \brief Creates a new horizontal Box */ Box::Box (void) { this->init('h'); } /** \brief Creates a new Box of type boxtype \param boxtype if 'v' the Box will be vertically, if 'h' the Box will be horizontally */ Box::Box (char boxtype) { this->init(boxtype); } /** \brief Initializes a new Box with type boxtype \param boxtype see Box(char boxtype) */ void Box::init(char boxtype) { isOption = -2; static_cast(this)->init(); if (boxtype == 'v') { widget = gtk_vbox_new (FALSE, 0); } else { widget = gtk_hbox_new (FALSE, 0); } } /** \brief Fills a box with a given Widget. It does this by apending the first one to its down-pointer and all its following ones to the preceding next-pointer. The last one will receive a NULL pointer as Next \param lowerWidget the next Widget that should be appendet to this Box */ void Box::fill (Widget *lowerWidget) { gtk_box_pack_start (GTK_BOX (this->widget), lowerWidget->widget, TRUE, TRUE, 0); if (this->down == NULL) this->down = lowerWidget; else { Widget* tmp; tmp = this->down; while (tmp->next != NULL) { tmp = tmp->next; } tmp->next = lowerWidget; } } /* IMAGE */ /** \brief Creates a new Image \param imagename the location of the Image on the Hard Disc */ Image::Image (char* imagename) { if (label) delete label; label = new char[strlen(imagename)+1]; strcpy(label, imagename); this->init(); widget = gtk_image_new_from_file (imagename); } /** \brief Initializes a new Image */ void Image::init() { isOption = 0; static_cast(this)->init(); } /* OPTION */ /** \brief Initializes a new Option. sets all Option-Specific-Values to their defaults. */ void Option::init() { value = 0; flagName = NULL; flagNameShort = NULL; saveable = false; defaultValue = 0; static_cast(this)->init(); return; } /** \brief This sets The FlagName of an Option and defines its default Values !! Options will be saved if flagname is different from "" !! \param flagname the Name that will be displayed in the output \param defaultvalue the default Value for this Option (see definition of defaultvalue */ void Option::setFlagName (char* flagname, int defaultvalue) { if (flagName) delete flagName; flagName = new char [strlen(flagname)+1]; strcpy(flagName, flagname); defaultValue = defaultvalue; cout << "Set Flagname of " << label << " to " << flagname << endl; } /** \brief see Option::setFlagName (char* flagname, int defaultvalue) \param flagname the Name that will be displayed in the output \param defaultvalue the default Value for this Option (see definition of defaultvalue \param flagnameshort a short flagname to be displayed in the output */ void Option::setFlagName (char* flagname, char* flagnameshort, int defaultvalue) { if (flagName) delete flagName; flagName = new char [strlen(flagname)+1]; strcpy(flagName, flagname); if (flagNameShort) delete flagNameShort; flagNameShort = new char [strlen(flagnameshort)+1]; strcpy(flagName, flagnameshort); defaultValue = defaultvalue; cout << "Set Flagname of " << label << " to " << flagname << endl; } /* BUTTON */ /** \brief Creates a new Button with a buttonname \param buttonname sets the Name of the Button */ Button::Button(char* buttonname) { this->init(); this->setTitle(buttonname); } /** \brief Initializes a new Button */ void Button::init(void) { isOption = 0; static_cast(this)->init(); widget = gtk_button_new_with_label (""); } /** \brief Sets a new name to the Button \param title The name the Button should get */ void Button::setTitle (char *title) { label = title; gtk_button_set_label (GTK_BUTTON(widget), title); } /** \brief redraws the Button not implemented yet */ void Button::redraw () { } /* CHECKBUTTON */ /** \brief Creates a new CheckButton with an ame \param buttonname The name the CheckButton should display. */ CheckButton::CheckButton (char* buttonname) { this->init(); this->setTitle(buttonname); this->connectSignal ("clicked", this->OptionChange); } /** \brief Initialize a new CheckButton with default settings */ void CheckButton::init(void) { isOption = 1; static_cast(this)->init(); widget = gtk_check_button_new_with_label (""); } /** \brief Sets a new Title to a CheckButton \param title The new Name the CheckButton should display. */ void CheckButton::setTitle(char* title) { if (label) delete label; label = new char[strlen(title)+1]; strcpy(label, title); gtk_button_set_label(GTK_BUTTON(widget), title); } bool CheckButton::isActive() { return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); } /** \brief Signal OptionChange writes the Value from the CheckButton to its Object-Database. \param widget The widget(CheckButton) that has a changed Value \param checkbutton the CheckButton-Object that should receive the change. */ gint CheckButton::OptionChange (GtkWidget *widget, Widget* checkbutton) { static_cast(checkbutton)->value = (int)gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON ((CheckButton*)checkbutton->widget)); flags->setTextFromFlags(orxonoxGUI); ////// must be different!!! cout << static_cast(checkbutton)->label << " set to: " << static_cast(checkbutton)->value << endl; } /** \brief Redraws the CheckButton (if option has changed). Example: if new settings are loaded the Button must be redrawn for the GUI to display that Change */ void CheckButton::redraw () { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value); } /* SLIDER */ /** \brief Creates a new Slider \param slidername The data-structure-name of the slider. \param start The minimal Value of the slider. \param end The maximal Value of the slider. */ Slider::Slider (char* slidername, int start, int end) { this->init(start, end); this->setValue(start); this->setTitle(slidername); this->connectSignal ("value_changed", this->OptionChange); } /** \brief Initializes a Slider with start and end Values params: see Slider::Slider (char* slidername, int start, int end) */ void Slider::init(int start, int end) { isOption = 2; static_cast(this)->init(); widget = gtk_hscale_new_with_range (start, end, 5); } /** \brief Sets a new Title to the Slider \param title The new Name of the slider */ void Slider::setTitle(char* title) { if (label) delete label; label = new char[strlen(title)+1]; strcpy(label, title); } /** \brief Setting a new value to the Slider. Maybe you also require a Slider::redraw() for this to display */ void Slider::setValue(int value) { this->value = value; } /** \brief Signal OptionChange writes the Value from the Slider to its Object-Database. \param widget The widget(Slider) that has a changed Value \param slider the Slider-Object that should receive the change. */ gint Slider::OptionChange (GtkWidget *widget, Widget* slider) { static_cast(slider)->value = (int)gtk_range_get_value (GTK_RANGE ((Slider*)slider->widget)); flags->setTextFromFlags(orxonoxGUI); //// must be different !!! cout << static_cast(slider)->label << " set to: "<< static_cast(slider)->value << endl; } /** \brief Redraws the widget Example: see void CheckButton::redraw () */ void Slider::redraw () { gtk_range_set_value (GTK_RANGE (widget), value); } /* MENU */ /** \brief Creates a Menu-Item-list out of multiple input. !! Consider, that the last input argument has to be "lastItem" for this to work!! \param menuname The Database-Name of this Menu \param ... items to be added to this Menu. !! Consider, that the last input argument has to be "lastItem" for this to work!! */ Menu::Menu (char* menuname, ...) { this->init(); this->setTitle(menuname); char *itemName; va_start (itemlist, menuname); while (strcmp (itemName = va_arg (itemlist, char*), "lastItem")) { this->addItem(itemName); } va_end(itemlist); gtk_option_menu_set_menu (GTK_OPTION_MENU (widget), menu); this->connectSignal ("changed", this->OptionChange); } /** \brief Initializes a new Menu with no items */ void Menu::init(void) { isOption = 2; static_cast(this)->init(); widget = gtk_option_menu_new (); menu = gtk_menu_new (); } /** * Sets the Database-Name of this Menu \param title Database-Name to be set. */ void Menu::setTitle(char* title) { if (label) delete label; label = new char[strlen(title)+1]; strcpy(label, title); } /** \brief appends a new Item to the Menu-List. \param itemName the itemName to be appendet. */ void Menu::addItem (char* itemName) { item = gtk_menu_item_new_with_label (itemName); gtk_menu_shell_append(GTK_MENU_SHELL (menu), item); } /** \brief Signal OptionChange writes the Value from the Menu to its Object-Database. \param widget The widget(Menu) that has a changed Value \param menu the Menu-Object that should receive the change. */ gint Menu::OptionChange (GtkWidget *widget, Widget* menu) { static_cast(menu)->value = (int)gtk_option_menu_get_history (GTK_OPTION_MENU (menu->widget)); flags->setTextFromFlags(orxonoxGUI); //// must be different !!! cout << static_cast(menu)->label << " changed to : " << static_cast(menu)->value << endl; } /** \brief Redraws the widget Example: see void CheckButton::redraw () */ void Menu::redraw () { gtk_option_menu_set_history (GTK_OPTION_MENU (widget), value); } OptionLabel::OptionLabel(char* text) { init(); setTitle(text); } void OptionLabel::init(void) { isOption = 4; static_cast(this)->init(); widget = gtk_label_new (""); } void OptionLabel::setTitle(char* title) { gtk_label_set_text (GTK_LABEL (widget), title); } void OptionLabel::redraw(void) { } /** \brief Creates a new default Label with no Text. You migth consider adding Label::setTitle with this. */ Label::Label () { this->init(); } /** \brief Creates a new Label with a Text. \param text The text to be displayed. */ Label:: Label (char* text) { this->init(); this->setText(text); } /** \brief initializes a new Label */ void Label::init(void) { isOption = 0; static_cast(this)->init(); widget = gtk_label_new (""); gtk_label_set_line_wrap (GTK_LABEL(widget), TRUE); } /** \brief Sets a new Text to a Label. \param text The text to be inserted into the Label. */ void Label::setText (char* text) { if (label) delete label; label = new char[strlen(text)+1]; strcpy(label, text); gtk_label_set_text (GTK_LABEL (this->widget), text); } /** \brief get the Text of a Label \return The Text the Label holds. */ char* Label::getText () { return ((char*)gtk_label_get_text (GTK_LABEL (this->widget))); }