/* 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. ### File Specific: main-programmer: Benjamin Grauer co-programmer: ... */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_GUI #include "glgui_widget.h" #include "glgui_cursor.h" #include "material.h" #include "debug.h" #include "loading/load_param.h" /// TODO TAKE THIS OUT OF HERE #include "loading/resource_manager.h" namespace OrxGui { /** * @brief standard constructor */ GLGuiWidget::GLGuiWidget (GLGuiWidget* parent) { this->init(); this->setParentWidget(parent); } /** * @brief loads Parameters for a Style from XML * @param root the XML-Element to load from. */ void GLGuiWidget::loadParams(const TiXmlElement* root) { /// STYLE LoadParam(root, "border-left", this, GLGuiWidget, setBorderLeft); LoadParam(root, "border-right", this, GLGuiWidget, setBorderRight); LoadParam(root, "border-top", this, GLGuiWidget, setBorderTop); LoadParam(root, "border-bottom", this, GLGuiWidget, setBorderBottom); LoadParam(root, "text-size", this, GLGuiWidget, setTextSize); LoadParam(root, "background-color", this, GLGuiWidget, setBackgroundColorS); LoadParam(root, "foreground-color", this, GLGuiWidget, setForegroundColorS); // LoadParamXML(root, "backmat", this, GLGuiWidget, loadBackgroundMaterial); // LoadParamXML(root, "frontmat", this, GLGuiWidget, loadForegroundMaterial); LoadParam(root, "feature-position", this, GLGuiWidget, setFeaturePositionS); LoadParam(root, "Font", this, GLGuiWidget, setFont); LoadParam(root, "animated-state-changes", this, GLGuiWidget, setAnimatedStateChanges); } /** * @brief standard deconstructor */ GLGuiWidget::~GLGuiWidget() { if (this == GLGuiWidget::_mouseFocused) GLGuiWidget::_mouseFocused = NULL; if (this == GLGuiWidget::selected()) this->unselect(); } GLGuiWidget* GLGuiWidget::_selected = NULL; GLGuiWidget* GLGuiWidget::_mouseFocused = NULL; GLGuiWidget* GLGuiWidget::_inputGrabber = NULL; /** * initializes the GUI-element */ void GLGuiWidget::init() { this->setClassID(CL_GLGUI_WIDGET, "GLGuiWidget"); this->_focusable = false; this->_clickable = false; this->_selectable = false; this->_pushed = false; this->_state = OrxGui::Normal; this->_font = Font(ResourceManager::getInstance()->getDataDir() + "/fonts/final_frontier.ttf", 20); this->resetStyle(); this->_animating = false; this->_animationCycle = 0.0; this->_animationDuration = 1.0; this->setBackgroundColor(Color(.51, .3, .3, .5)); this->setBackgroundColor(Color(.3, .5, .3, 1), OrxGui::Selected); this->_style[0]._background.setBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); this->_style[1]._background.setBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); this->_style[2]._background.setBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); this->_style[3]._background.setBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); this->setForegroundColor(Color(.8, .8, 1, 1), OrxGui::Normal); this->setForegroundColor(Color(0, .4, 1.0, 1), OrxGui::Selected); this->setForegroundColor(Color(0, .0, 1.0, 1), OrxGui::Focused); this->setForegroundColor(Color(.1, .1, .1, 1), OrxGui::Insensitive); this->setVisibility(GLGUI_WIDGET_DEFAULT_VISIBLE); this->setBorderLeft(15); this->setBackgroundTexture("gui_element_background.png"); this->switchState(_state); this->_currentStyle = this->_style[_state]; } void GLGuiWidget::setParentWidget(GLGuiWidget* parent) { this->_parent = parent; if (parent != NULL) parent->addChild2D(this); } void GLGuiWidget::setFrontColor(const Color& frontColor, bool instantaniously) { this->_currentStyle._foreground.setDiffuseColor(frontColor); this->animateBack(); }; bool GLGuiWidget::focusOverWidget(const Vector2D& position) const { return (this->getAbsCoor2D().x < position.x && this->getAbsCoor2D().x + this->getSizeX2D() > position.x && this->getAbsCoor2D().y < position.y && this->getAbsCoor2D().y + this->getSizeY2D() > position.y); } bool GLGuiWidget::focusOverWidget(const GLGuiCursor* const cursor) const { return this->focusOverWidget(cursor->getAbsCoor2D()); } /** @brief gives focus to this widget */ void GLGuiWidget::giveMouseFocus() { if (this->_state == OrxGui::Insensitive) return ; if (GLGuiWidget::mouseFocused() != NULL) GLGuiWidget::mouseFocused()->breakMouseFocus(); GLGuiWidget::_mouseFocused = this; this->switchState(OrxGui::Focused); this->receivedFocus(); }; void GLGuiWidget::breakMouseFocus() { if (GLGuiWidget::_mouseFocused == this) { GLGuiWidget::_mouseFocused = NULL; if (GLGuiWidget::_selected != this) this->switchState(OrxGui::Normal); else this->switchState(OrxGui::Selected); this->removedFocus(); } }; /** * @brief selects the Widget, unselecting the old one (if existing) */ void GLGuiWidget::select() { if (GLGuiWidget::_selected != NULL) GLGuiWidget::selected()->unselect(); GLGuiWidget::_selected = this; this->switchState(OrxGui::Selected); } /** * @brief unselects the current Widget. * * if the current Widget is not selected, nothing is done here. */ void GLGuiWidget::unselect() { if (GLGuiWidget::_selected != this) return; if (GLGuiWidget::_mouseFocused == this) this->switchState(OrxGui::Focused); else this->switchState(OrxGui::Normal); GLGuiWidget::_selected = NULL; } void GLGuiWidget::resize() { this->backRect().setSize(this->getSize2D()); if (this->parent() != NULL) this->parent()->resize(); } void GLGuiWidget::click(const Vector2D& pos) { assert (!this->_pushed); this->_pushed = true; this->clicking(pos); } void GLGuiWidget::release(const Vector2D& pos) { if (this->_pushed) { this->releasing(pos, GLGuiWidget::_mouseFocused == this); this->_pushed = false; } } void GLGuiWidget::clicking(const Vector2D& pos) {} void GLGuiWidget::releasing(const Vector2D& pos, bool focused) {} void GLGuiWidget::receivedFocus() { } void GLGuiWidget::removedFocus() { } void GLGuiWidget::selecting() { } void GLGuiWidget::unselecting() { } void GLGuiWidget::destroying() { } void GLGuiWidget::setWidgetSize(const Vector2D& size) { this->setSize2D(size); this->resize(); } void GLGuiWidget::setWidgetSize(float x, float y) { this->setWidgetSize(Vector2D(x, y)); } void GLGuiWidget::connect(GLGuiWidget* sender, Signal& signal, BaseObject* receiver, Slot executor) { sender->connect(signal, receiver, executor); } void GLGuiWidget::connect(Signal& signal, BaseObject* receiver, Slot executor) { signal.push_back(SignalConnector(receiver, executor)); } void GLGuiWidget::show() { this->setVisibility(true); this->showing(); } void GLGuiWidget::hide() { this->setVisibility(false); this->hiding(); } /** * @brief resets the Style to the default Settings. */ void GLGuiWidget::resetStyle() { this->setBorderLeft(1.0); this->setBorderRight(1.0); this->setBorderTop(1.0); this->setBorderBottom(1.0); this->setTextSize(20.0); this->setBackgroundColor(1.0); this->setForegroundColor(1.0); this->setFeaturePosition(FeatureLeft); this->setAnimatedStateChanges(true); } /** * @brief sets the Width of the left border for all States * @param value the borderWidth */ void GLGuiWidget::setBorderLeft(float value) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) setBorderLeft(value, (OrxGui::State)i); } /** * @brief sets the Width of the left border. * @param value the borderWidth * @param state the State to set the borderwidth to */ void GLGuiWidget::setBorderLeft(float value, OrxGui::State state) { _style[state]._borderLeft = value; if (state == _state) _currentStyle._borderLeft = value; } /** * @brief sets the Width of the left border. * @param value the borderWidth * @param stateName the State to set the borderwidth to */ void GLGuiWidget::setBorderLeftS(float value, const std::string& stateName) { OrxGui::State state; if (getState(stateName, &state)) this->setBorderLeft(value, state); else this->setBorderLeft(value); } /** * @brief sets the Width of the right border for all states. * @param value the borderWidth */ void GLGuiWidget::setBorderRight(float value) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) setBorderRight(value, (OrxGui::State)i); } /** * @brief sets the Width of the right border. * @param value the borderWidth * @param state the State to setup. */ void GLGuiWidget::setBorderRight(float value, OrxGui::State state) { _style[state]._borderRight = value; if (state == _state) _currentStyle._borderRight = value; } /** * @brief sets the Width of the right border. * @param value the borderWidth * @param stateName the State to setup. */ void GLGuiWidget::setBorderRightS(float value, const std::string& stateName) { OrxGui::State state; if (getState(stateName, &state)) this->setBorderRight(value, state); else this->setBorderRight(value); } /** * @brief sets the Width of the top border for all states. * @param value the borderWidth */ void GLGuiWidget::setBorderTop(float value) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) setBorderTop(value, (OrxGui::State)i); } /** * @brief sets the Width of the top border. * @param value the borderWidth * @param state the State to setup. */ void GLGuiWidget::setBorderTop(float value, OrxGui::State state) { _style[state]._borderTop = value; if (state == _state) _currentStyle._borderTop = value; } /** * @brief sets the Width of the top border. * @param value the borderWidth * @param stateName the State to setup. */ void GLGuiWidget::setBorderTopS(float value, const std::string& stateName) { OrxGui::State state; if (getState(stateName, &state)) this->setBorderTop(value, state); else this->setBorderTop(value); } /** * @brief sets the Width of the bottom border for all states. * @param value the borderWidth */ void GLGuiWidget::setBorderBottom(float value) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) setBorderBottom(value, (OrxGui::State)i); } /** * @brief sets the Width of the bottom border. * @param value the borderWidth * @param state the State to setup. */ void GLGuiWidget::setBorderBottom(float value, OrxGui::State state) { _style[state]._borderBottom = value; if (state == _state) _currentStyle._borderBottom = value; } /** * @brief sets the Width of the bottom border for all states. * @param value the borderWidth * @param stateName the State to setup. */ void GLGuiWidget::setBorderBottomS(float value, const std::string& stateName) { OrxGui::State state; if (getState(stateName, &state)) this->setBorderBottom(value, state); else this->setBorderBottom(value); } /** * @brief sets the TextSize for all states. * @param value the TextSize */ void GLGuiWidget::setTextSize(float value) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) setTextSize(value, (OrxGui::State)i); } /** * @brief sets the TextSize. * @param value the TextSize. * @param state: the State to setup */ void GLGuiWidget::setTextSize(float value, OrxGui::State state) { _style[state]._textSize = value; if (state == _state) _currentStyle._textSize = value; } /** * @brief sets the TextSize. * @param value the TextSize. * @param stateName: the State to setup */ void GLGuiWidget::setTextSizeS(float value, const std::string& stateName) { OrxGui::State state; if (getState(stateName, &state)) this->setTextSize(value, state); else this->setTextSize(value); } /** * @brief sets the Background Color for all States. * @param color the Color. */ void GLGuiWidget::setBackgroundColor(const Color& color) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) setBackgroundColor(color, (OrxGui::State)i); } /** * @brief sets the Background Color. * @param color the Color. * @param state: the State to setup */ void GLGuiWidget::setBackgroundColor(const Color& color, OrxGui::State state) { _style[state]._background.setDiffuseColor(color); if (state == _state) _currentStyle._background.setDiffuseColor(color); } /** * @brief sets the Background Color. * @param r the Color's red part. * @param g the Color's green part. * @param b the Color's blue part. * @param a the Color's alpha part. * @param stateName: the State to setup */ void GLGuiWidget::setBackgroundColorS(float r, float g, float b, float a, const std::string& stateName) { OrxGui::State state; if (getState(stateName, &state)) this->setBackgroundColor(Color(r,g,b,a), state); else this->setBackgroundColor(Color(r,g,b,a)); } /** * @brief sets the Background Texture for all States. * @param texture the Texture. */ void GLGuiWidget::setBackgroundTexture(const Texture& texture) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) setBackgroundTexture(texture, (OrxGui::State)i); } /** * @brief sets the Background Texture to all States. * @param textureName the Texture's fileName. */ void GLGuiWidget::setBackgroundTexture(const std::string& textureName) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) _style[i]._background.setDiffuseMap(textureName); this->_currentStyle._background.setDiffuseMap(textureName); } /** * @brief sets the Background Texture. * @param texture the Texture. * @param state the State to setup. */ void GLGuiWidget::setBackgroundTexture(const Texture& texture, OrxGui::State state) { _style[state]._background.setDiffuseMap(texture); if (state == _state) _currentStyle._background.setDiffuseMap(texture); } /** * @brief sets the Background Texture. * @param texture the Texture. * @param stateName the State to setup. */ void GLGuiWidget::setBackgroundTexture(const std::string& textureName, const std::string& stateName) { OrxGui::State state; if (getState(stateName, &state)) ; /// FIXME this->setBackgroundTexture(textureName, state); else ; /// this->setBackgroundTexture(textureName); } /** * @brief sets the Foreground Color for all States. * @param color the Color. */ void GLGuiWidget::setForegroundColor(const Color& color) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) setForegroundColor(color, (OrxGui::State)i); } /** * @brief sets the Foreground Color. * @param color the Color. * @param state the State to setup */ void GLGuiWidget::setForegroundColor(const Color& color, OrxGui::State state) { _style[state]._foreground.setDiffuseColor(color); if (state == _state) _currentStyle._foreground.setDiffuseColor(color); } /** * @brief sets the Foreground Color. * @param r the Color's red part. * @param g the Color's green part. * @param b the Color's blue part. * @param a the Color's alpha part. * @param stateName: the State to setup */ void GLGuiWidget::setForegroundColorS(float r, float g, float b, float a, const std::string& stateName) { OrxGui::State state; if (getState(stateName, &state)) this->setForegroundColor(Color(r,g,b,a), state); else this->setForegroundColor(Color(r,g,b,a)); } /** * @brief sets the Foreground Texture for all States. * @param texture the Texture. */ void GLGuiWidget::setForegroundTexture(const Texture& texture) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) setForegroundTexture(texture, (OrxGui::State)i); } /** * @brief sets the Foreground Texture to all States. * @param textureName the Texture's fileName. */ void GLGuiWidget::setForegroundTexture(const std::string& textureName) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) _style[i]._foreground.setDiffuseMap(textureName); this->_currentStyle._foreground.setDiffuseMap(textureName); } /** * @brief sets the Foreground Texture. * @param texture the Texture. * @param state the State to setup. */ void GLGuiWidget::setForegroundTexture(const Texture& texture, OrxGui::State state) { _style[state]._background.setDiffuseMap(texture); if (state == _state) _currentStyle._background.setDiffuseMap(texture); } /** * @brief sets the Foreground Texture. * @param texture the Texture. * @param stateName the State to setup. */ void GLGuiWidget::setForegroundTexture(const std::string& textureName, const std::string& stateName) { OrxGui::State state; if (getState(stateName, &state)) ; /// FIXME this->setForegroundTexture(textureName, state); else ; /// this->setForegroundTexture(textureName); } void GLGuiWidget::loadBackgroundMaterial(const Material& material) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) this->loadForegroundMaterial(material, (OrxGui::State)i); } void GLGuiWidget::loadBackgroundMaterial(const Material& material, OrxGui::State state) { this->_style[state]._background = material; if (state == _state) _currentStyle._background = material; } void GLGuiWidget::loadBackgroundMaterial(const TiXmlElement* element) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) this->loadBackgroundMaterial(element, (OrxGui::State)i); } void GLGuiWidget::loadBackgroundMaterial(const TiXmlElement* element, OrxGui::State state) { this->_style[state]._background.loadParams(element); if (state == _state) this->_currentStyle._background = _style[state]._background; } void GLGuiWidget::loadBackgroundMaterialS(const TiXmlElement* element, const std::string& stateName) { OrxGui::State state; if (getState(stateName, &state)) this->loadBackgroundMaterial(element, state); else this->loadBackgroundMaterial(element); } void GLGuiWidget::loadForegroundMaterial(const Material& material) {} void GLGuiWidget::loadForegroundMaterial(const Material& material, OrxGui::State state) {} void GLGuiWidget::loadForegroundMaterial(const TiXmlElement* element, OrxGui::State state) {} void GLGuiWidget::loadForegroundMaterialS(const TiXmlElement* element, const std::string& stateName) {} /** * @brief sets the Feature-Position. * @param featurePosition the Feature-Position. */ void GLGuiWidget::setFeaturePosition(FeaturePosition featurePosition) { this->_featurePosition = featurePosition; } /** * @brief sets the Feature-Position by converting from a String. * @param featurePosition the Feature-Position. */ void GLGuiWidget::setFeaturePositionS(const std::string& featurePosition) { for (unsigned int i = 0; i < 4; ++i) { if (featurePosition == FeaturePositionString[i]) { this->setFeaturePosition((FeaturePosition)i); } } } /** * @brief sets the Font. * @param font the Font. */ void GLGuiWidget::setFont(const Font& font) { this->_font = font; } /** * @brief sets the font from a Font-Name. * @param fontName the FileName of the Font. */ void GLGuiWidget::setFont(const std::string& fontName, unsigned int renderSize) { this->_font = Font(fontName, renderSize); } /** * @brief sets the AnimatedState. * @param animated: it states-changes should animate true, otherwise false. */ void GLGuiWidget::setAnimatedStateChanges(bool animated) { this->_animatedStateChanges = animated; } void GLGuiWidget::switchState(OrxGui::State state) { //this->_currentStyle = this->_style[state]; this->_state = state; PRINTF(4)("%s::%s Switches to state %s\n", this->getClassName(), this->getName(), OrxGui::StateString[state].c_str()); this->animateBack(); } void GLGuiWidget::animateBack() { this->_animating = true; this->_animationCycle = 0.0f; } void GLGuiWidget::tick(float dt) { if (this->_animating) { this->foregroundColor(); _animationCycle += dt / _animationDuration; if (_animationCycle >= 1.0) { _currentStyle._foreground.diffuseColor() = this->foregroundColor(_state); _currentStyle._background.diffuseColor() = this->backgroundColor(_state); _animating = false; } else { _currentStyle._foreground.diffuseColor().slerp(this->foregroundColor(_state), _animationCycle); _currentStyle._background.diffuseColor().slerp(this->backgroundColor(_state), _animationCycle); } this->updateFrontColor(); } } /** * USE THIS FUNCTION ONLY FROM DERIVED CLASS */ void GLGuiWidget::draw() const { this->background().select(); this->drawRect(this->backRect()); this->background().unselect(); } /** * @param stateName the Name of a State. * @param state the found State is returned here if found. * @returns true if String is found, false otherwise. */ bool GLGuiWidget::getState(const std::string& stateName, OrxGui::State* state) { for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) if (stateName == OrxGui::StateString[i]) { *state = (OrxGui::State)i; return true; } return false; } /** * @brief print out some nice debug output about the Widget. */ void GLGuiWidget::debug(unsigned int level) const { PRINT(0)("Debug of %s::%s - WidgetPart ", this->getClassName(), this->getName()); if (_parent != NULL) PRINT(0)("- Parent %s::%s ", _parent->getClassName(), _parent->getName()); PRINT(0)("- State: %s", StateString[_state].c_str()); if (_focusable) PRINT(0)("- focusable "); if (_clickable) PRINT(0)("- Clickable "); if (_pushed) PRINT(0)("- Pushed "); PRINT(0)("\n"); PRINT(0)("Minimum Size %0.2f %0.2f ", _minSize.x, _minSize.y); PRINT(0)("Back Rect: "); _backRect.debug(); PRINT(0)("Style:\n"); for (unsigned int i = 0; i < GLGUI_STATE_COUNT; ++i) { PRINT(0)("In State %s: \n", StateString[i].c_str()); PRINT(0)(" Borders: Left: %0.2f, Right: %0.2f, Top: %0.2f, Bottom %0.2f\n", _style[i]._borderLeft, _style[i]._borderRight, _style[i]._borderTop, _style[i]._borderBottom); PRINT(0)(" TextSize %0.2f\n", _style[i]._textSize); PRINT(0)(" BackgroundColor: "); _style[i]._background.diffuseColor().debug(); PRINT(0)(" ForegroundColor: "); _style[i]._foreground.diffuseColor().debug(); PRINT(0)("\n"); } PRINT(0)(" Feature at %s ", FeaturePositionString[_featurePosition].c_str()); /// TODO PRINT(0)(""); Font* _font; //!< The Font used in the current Widget. if (_animatedStateChanges) PRINT(0)("- AnimatedStateChanges"); PRINT(0)("\n"); /* if (_animating) PRINT(0)("- Animated "); // float _animationCycle; float _animationDuration; StatedStyle _currentStyle; OrxGui::State _currentState; */ } }