Add custom colorable GUIButton implementation
authorrubenwardy <rw@rubenwardy.com>
Fri, 15 Mar 2019 18:39:23 +0000 (18:39 +0000)
committerrubenwardy <rw@rubenwardy.com>
Sat, 3 Aug 2019 18:36:30 +0000 (19:36 +0100)
build/android/jni/Android.mk
src/client/renderingengine.cpp
src/gui/CMakeLists.txt
src/gui/guiButton.cpp [new file with mode: 0644]
src/gui/guiButton.h [new file with mode: 0644]
src/gui/guiFormSpecMenu.cpp
src/gui/guiSkin.cpp [new file with mode: 0644]
src/gui/guiSkin.h [new file with mode: 0644]
util/travis/clang-format-whitelist.txt

index f35067968717fcfaab7c59f9fdbf71dfb0488cf2..75d20ab95a532e117ba9b3053ce0819a301c8c2b 100644 (file)
@@ -186,6 +186,7 @@ LOCAL_SRC_FILES := \
                jni/src/gui/guiPasswordChange.cpp         \
                jni/src/gui/guiPathSelectMenu.cpp         \
                jni/src/gui/guiScrollBar.cpp              \
+               jni/src/gui/guiSkin.cpp                   \
                jni/src/gui/guiTable.cpp                  \
                jni/src/gui/guiVolumeChange.cpp           \
                jni/src/gui/intlGUIEditBox.cpp            \
index b18e91f6e35bc19b49086b8993fa17179bab45fa..e56367afee8c7150a8237b4758d548f6be7e7b83 100644 (file)
@@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "render/factory.h"
 #include "inputhandler.h"
 #include "gettext.h"
+#include "../gui/guiSkin.h"
 
 #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__ANDROID__) && \
                !defined(SERVER) && !defined(__HAIKU__)
@@ -44,6 +45,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/Xatom.h>
+
 #endif
 
 #ifdef __ANDROID__
@@ -52,6 +54,29 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 RenderingEngine *RenderingEngine::s_singleton = nullptr;
 
+
+static gui::GUISkin* createSkin(gui::IGUIEnvironment *environment,
+                                                               gui::EGUI_SKIN_TYPE type, video::IVideoDriver *driver)
+{
+       gui::GUISkin* skin = new gui::GUISkin(type, driver);
+
+       gui::IGUIFont* builtinfont = environment->getBuiltInFont();
+       gui::IGUIFontBitmap* bitfont = 0;
+       if (builtinfont && builtinfont->getType() == gui::EGFT_BITMAP)
+               bitfont = (gui::IGUIFontBitmap*)builtinfont;
+
+       gui::IGUISpriteBank* bank = 0;
+       skin->setFont(builtinfont);
+
+       if (bitfont)
+               bank = bitfont->getSpriteBank();
+
+       skin->setSpriteBank(bank);
+
+       return skin;
+}
+
+
 RenderingEngine::RenderingEngine(IEventReceiver *receiver)
 {
        sanity_check(!s_singleton);
@@ -112,6 +137,11 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
        driver = m_device->getVideoDriver();
 
        s_singleton = this;
+
+       auto skin = createSkin(m_device->getGUIEnvironment(),
+                                                  gui::EGST_WINDOWS_METALLIC, driver);
+       m_device->getGUIEnvironment()->setSkin(skin);
+       skin->drop();
 }
 
 RenderingEngine::~RenderingEngine()
@@ -193,7 +223,7 @@ bool RenderingEngine::setupTopLevelWindow(const std::string &name)
        // sort here that would call the correct toplevel setup methods for
        // the environment Minetest is running in but for now not deviating
        // from the original pattern.
-       
+
        /* Setting Xorg properties for the top level window */
        setupTopLevelXorgWindow(name);
        /* Done with Xorg properties */
@@ -211,7 +241,7 @@ bool RenderingEngine::setupTopLevelWindow(const std::string &name)
        /* Done with general properties */
 
        // FIXME: setWindowIcon returns a bool result but it is unused.
-       // For now continue to return this result. 
+       // For now continue to return this result.
        return result;
 }
 
@@ -223,7 +253,7 @@ void RenderingEngine::setupTopLevelXorgWindow(const std::string &name)
        Display *x11_dpl = reinterpret_cast<Display *>(exposedData.OpenGLLinux.X11Display);
        if (x11_dpl == NULL) {
                warningstream << "Client: Could not find X11 Display in ExposedVideoData"
-                       << std::endl; 
+                       << std::endl;
                return;
        }
 
@@ -244,30 +274,30 @@ void RenderingEngine::setupTopLevelXorgWindow(const std::string &name)
 
        // FIXME: In the future WMNormalHints should be set ... e.g see the
        // gtk/gdk code (gdk/x11/gdksurface-x11.c) for the setup_top_level
-       // method. But for now (as it would require some significant changes) 
-       // leave the code as is. 
-       
+       // method. But for now (as it would require some significant changes)
+       // leave the code as is.
+
        // The following is borrowed from the above gdk source for setting top
        // level windows. The source indicates and the Xlib docs suggest that
-       // this will set the WM_CLIENT_MACHINE and WM_LOCAL_NAME. This will not 
-       // set the WM_CLIENT_MACHINE to a Fully Qualified Domain Name (FQDN) which is 
+       // this will set the WM_CLIENT_MACHINE and WM_LOCAL_NAME. This will not
+       // set the WM_CLIENT_MACHINE to a Fully Qualified Domain Name (FQDN) which is
        // required by the Extended Window Manager Hints (EWMH) spec when setting
        // the _NET_WM_PID (see further down) but running Minetest in an env
        // where the window manager is on another machine from Minetest (therefore
        // making the PID useless) is not expected to be a problem. Further
        // more, using gtk/gdk as the model it would seem that not using a FQDN is
        // not an issue for modern Xorg window managers.
-       
+
        verbosestream << "Client: Setting Xorg window manager Properties"
                << std::endl;
 
        XSetWMProperties (x11_dpl, x11_win, NULL, NULL, NULL, 0, NULL, NULL, NULL);
 
-       // Set the _NET_WM_PID window property according to the EWMH spec. _NET_WM_PID 
-       // (in conjunction with WM_CLIENT_MACHINE) can be used by window managers to 
-       // force a shutdown of an application if it doesn't respond to the destroy 
-       // window message. 
-    
+       // Set the _NET_WM_PID window property according to the EWMH spec. _NET_WM_PID
+       // (in conjunction with WM_CLIENT_MACHINE) can be used by window managers to
+       // force a shutdown of an application if it doesn't respond to the destroy
+       // window message.
+
        verbosestream << "Client: Setting Xorg _NET_WM_PID extened window manager property"
                << std::endl;
 
@@ -277,12 +307,12 @@ void RenderingEngine::setupTopLevelXorgWindow(const std::string &name)
        infostream << "Client: PID is '" << static_cast<long>(pid) << "'"
                << std::endl;
 
-       XChangeProperty(x11_dpl, x11_win, NET_WM_PID, 
-                       XA_CARDINAL, 32, PropModeReplace, 
+       XChangeProperty(x11_dpl, x11_win, NET_WM_PID,
+                       XA_CARDINAL, 32, PropModeReplace,
                        reinterpret_cast<unsigned char *>(&pid),1);
 
        // Set the WM_CLIENT_LEADER window property here. Minetest has only one
-       // window and that window will always be the leader. 
+       // window and that window will always be the leader.
 
        verbosestream << "Client: Setting Xorg WM_CLIENT_LEADER property"
                << std::endl;
index 48ba3fa8c7ddd2473875e4466bea86692a818e68..2307856a4c41c3ee50c808fa56ff4d6cf2a14e2e 100644 (file)
@@ -1,4 +1,5 @@
 set(gui_SRCS
+       ${CMAKE_CURRENT_SOURCE_DIR}/guiButton.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiConfirmRegistration.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiEditBoxWithScrollbar.cpp
@@ -8,6 +9,7 @@ set(gui_SRCS
        ${CMAKE_CURRENT_SOURCE_DIR}/guiPasswordChange.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiPathSelectMenu.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiScrollBar.cpp
+       ${CMAKE_CURRENT_SOURCE_DIR}/guiSkin.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiTable.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiVolumeChange.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/intlGUIEditBox.cpp
diff --git a/src/gui/guiButton.cpp b/src/gui/guiButton.cpp
new file mode 100644 (file)
index 0000000..60d330f
--- /dev/null
@@ -0,0 +1,649 @@
+// Copyright (C) 2002-2012 Nikolaus Gebhardt\r
+// This file is part of the "Irrlicht Engine".\r
+// For conditions of distribution and use, see copyright notice in irrlicht.h\r
+\r
+#include "guiButton.h"\r
+\r
+\r
+#include "IGUISkin.h"\r
+#include "IGUIEnvironment.h"\r
+#include "IVideoDriver.h"\r
+#include "IGUIFont.h"\r
+#include "porting.h"\r
+\r
+using namespace irr;\r
+using namespace gui;\r
+\r
+//! constructor\r
+GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,\r
+                       s32 id, core::rect<s32> rectangle, bool noclip)\r
+: IGUIButton(environment, parent, id, rectangle),\r
+       SpriteBank(0), OverrideFont(0),\r
+       OverrideColorEnabled(false), OverrideColor(video::SColor(101,255,255,255)),\r
+       ClickTime(0), HoverTime(0), FocusTime(0),\r
+       ClickShiftState(false), ClickControlState(false),\r
+       IsPushButton(false), Pressed(false),\r
+       UseAlphaChannel(false), DrawBorder(true), ScaleImage(false)\r
+{\r
+       setNotClipped(noclip);\r
+\r
+       // This element can be tabbed.\r
+       setTabStop(true);\r
+       setTabOrder(-1);\r
+\r
+       // PATCH\r
+       for (size_t i = 0; i < 4; i++) {\r
+               Colors[i] = Environment->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);\r
+       }\r
+       // END PATCH\r
+}\r
+\r
+//! destructor\r
+GUIButton::~GUIButton()\r
+{\r
+       if (OverrideFont)\r
+               OverrideFont->drop();\r
+\r
+       if (SpriteBank)\r
+               SpriteBank->drop();\r
+}\r
+\r
+\r
+//! Sets if the images should be scaled to fit the button\r
+void GUIButton::setScaleImage(bool scaleImage)\r
+{\r
+       ScaleImage = scaleImage;\r
+}\r
+\r
+\r
+//! Returns whether the button scale the used images\r
+bool GUIButton::isScalingImage() const\r
+{\r
+       return ScaleImage;\r
+}\r
+\r
+\r
+//! Sets if the button should use the skin to draw its border\r
+void GUIButton::setDrawBorder(bool border)\r
+{\r
+       DrawBorder = border;\r
+}\r
+\r
+\r
+void GUIButton::setSpriteBank(IGUISpriteBank* sprites)\r
+{\r
+       if (sprites)\r
+               sprites->grab();\r
+\r
+       if (SpriteBank)\r
+               SpriteBank->drop();\r
+\r
+       SpriteBank = sprites;\r
+}\r
+\r
+void GUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop, bool scale)\r
+{\r
+       ButtonSprites[(u32)state].Index = index;\r
+       ButtonSprites[(u32)state].Color = color;\r
+       ButtonSprites[(u32)state].Loop  = loop;\r
+       ButtonSprites[(u32)state].Scale = scale;\r
+}\r
+\r
+//! Get the sprite-index for the given state or -1 when no sprite is set\r
+s32 GUIButton::getSpriteIndex(EGUI_BUTTON_STATE state) const\r
+{\r
+       return ButtonSprites[(u32)state].Index;\r
+}\r
+\r
+//! Get the sprite color for the given state. Color is only used when a sprite is set.\r
+video::SColor GUIButton::getSpriteColor(EGUI_BUTTON_STATE state) const\r
+{\r
+       return ButtonSprites[(u32)state].Color;\r
+}\r
+\r
+//! Returns if the sprite in the given state does loop\r
+bool GUIButton::getSpriteLoop(EGUI_BUTTON_STATE state) const\r
+{\r
+       return ButtonSprites[(u32)state].Loop;\r
+}\r
+\r
+//! Returns if the sprite in the given state is scaled\r
+bool GUIButton::getSpriteScale(EGUI_BUTTON_STATE state) const\r
+{\r
+       return ButtonSprites[(u32)state].Scale;\r
+}\r
+\r
+//! called if an event happened.\r
+bool GUIButton::OnEvent(const SEvent& event)\r
+{\r
+       if (!isEnabled())\r
+               return IGUIElement::OnEvent(event);\r
+\r
+       switch(event.EventType)\r
+       {\r
+       case EET_KEY_INPUT_EVENT:\r
+               if (event.KeyInput.PressedDown &&\r
+                       (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))\r
+               {\r
+                       if (!IsPushButton)\r
+                               setPressed(true);\r
+                       else\r
+                               setPressed(!Pressed);\r
+\r
+                       return true;\r
+               }\r
+               if (Pressed && !IsPushButton && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)\r
+               {\r
+                       setPressed(false);\r
+                       return true;\r
+               }\r
+               else\r
+               if (!event.KeyInput.PressedDown && Pressed &&\r
+                       (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))\r
+               {\r
+\r
+                       if (!IsPushButton)\r
+                               setPressed(false);\r
+\r
+                       if (Parent)\r
+                       {\r
+                               ClickShiftState = event.KeyInput.Shift;\r
+                               ClickControlState = event.KeyInput.Control;\r
+\r
+                               SEvent newEvent;\r
+                               newEvent.EventType = EET_GUI_EVENT;\r
+                               newEvent.GUIEvent.Caller = this;\r
+                               newEvent.GUIEvent.Element = 0;\r
+                               newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;\r
+                               Parent->OnEvent(newEvent);\r
+                       }\r
+                       return true;\r
+               }\r
+               break;\r
+       case EET_GUI_EVENT:\r
+               if (event.GUIEvent.Caller == this)\r
+               {\r
+                       if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)\r
+                       {\r
+                               if (!IsPushButton)\r
+                                       setPressed(false);\r
+                               FocusTime = (u32)porting::getTimeMs();\r
+                       }\r
+                       else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)\r
+                       {\r
+                               FocusTime = (u32)porting::getTimeMs();\r
+                       }\r
+                       else if (event.GUIEvent.EventType == EGET_ELEMENT_HOVERED || event.GUIEvent.EventType == EGET_ELEMENT_LEFT)\r
+                       {\r
+                               HoverTime = (u32)porting::getTimeMs();\r
+                       }\r
+               }\r
+               break;\r
+       case EET_MOUSE_INPUT_EVENT:\r
+               if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)\r
+               {\r
+                       if (!IsPushButton)\r
+                               setPressed(true);\r
+\r
+                       return true;\r
+               }\r
+               else\r
+               if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)\r
+               {\r
+                       bool wasPressed = Pressed;\r
+\r
+                       if ( !AbsoluteClippingRect.isPointInside( core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ) ) )\r
+                       {\r
+                               if (!IsPushButton)\r
+                                       setPressed(false);\r
+                               return true;\r
+                       }\r
+\r
+                       if (!IsPushButton)\r
+                               setPressed(false);\r
+                       else\r
+                       {\r
+                               setPressed(!Pressed);\r
+                       }\r
+\r
+                       if ((!IsPushButton && wasPressed && Parent) ||\r
+                               (IsPushButton && wasPressed != Pressed))\r
+                       {\r
+                               ClickShiftState = event.MouseInput.Shift;\r
+                               ClickControlState = event.MouseInput.Control;\r
+\r
+                               SEvent newEvent;\r
+                               newEvent.EventType = EET_GUI_EVENT;\r
+                               newEvent.GUIEvent.Caller = this;\r
+                               newEvent.GUIEvent.Element = 0;\r
+                               newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;\r
+                               Parent->OnEvent(newEvent);\r
+                       }\r
+\r
+                       return true;\r
+               }\r
+               break;\r
+       default:\r
+               break;\r
+       }\r
+\r
+       return Parent ? Parent->OnEvent(event) : false;\r
+}\r
+\r
+\r
+//! draws the element and its children\r
+void GUIButton::draw()\r
+{\r
+       if (!IsVisible)\r
+               return;\r
+\r
+       // PATCH\r
+       GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());\r
+       video::IVideoDriver* driver = Environment->getVideoDriver();\r
+       // END PATCH\r
+\r
+       if (DrawBorder)\r
+       {\r
+               if (!Pressed)\r
+               {\r
+                       // PATCH\r
+                       skin->drawColored3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect, Colors);\r
+                       // END PATCH\r
+               }\r
+               else\r
+               {\r
+                       // PATCH\r
+                       skin->drawColored3DButtonPanePressed(this, AbsoluteRect, &AbsoluteClippingRect, Colors);\r
+                       // END PATCH\r
+               }\r
+       }\r
+\r
+       const core::position2di buttonCenter(AbsoluteRect.getCenter());\r
+       EGUI_BUTTON_IMAGE_STATE imageState = getImageState(Pressed);\r
+       if ( ButtonImages[(u32)imageState].Texture )\r
+       {\r
+               core::position2d<s32> pos(buttonCenter);\r
+               core::rect<s32> sourceRect(ButtonImages[(u32)imageState].SourceRect);\r
+               if ( sourceRect.getWidth() == 0 && sourceRect.getHeight() == 0 )\r
+                       sourceRect = core::rect<s32>(core::position2di(0,0), ButtonImages[(u32)imageState].Texture->getOriginalSize());\r
+\r
+               pos.X -= sourceRect.getWidth() / 2;\r
+               pos.Y -= sourceRect.getHeight() / 2;\r
+\r
+               if ( Pressed )\r
+               {\r
+                       // Create a pressed-down effect by moving the image when it looks identical to the unpressed state image\r
+                       EGUI_BUTTON_IMAGE_STATE unpressedState = getImageState(false);\r
+                       if ( unpressedState == imageState || ButtonImages[(u32)imageState] == ButtonImages[(u32)unpressedState] )\r
+                       {\r
+                               pos.X += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X);\r
+                               pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y);\r
+                       }\r
+               }\r
+\r
+               driver->draw2DImage(ButtonImages[(u32)imageState].Texture,\r
+                               ScaleImage? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),\r
+                               sourceRect, &AbsoluteClippingRect,\r
+                               0, UseAlphaChannel);\r
+       }\r
+\r
+       if (SpriteBank)\r
+       {\r
+               core::position2di pos(buttonCenter);\r
+\r
+               if (isEnabled())\r
+               {\r
+                       // pressed / unpressed animation\r
+                       EGUI_BUTTON_STATE state = Pressed ? EGBS_BUTTON_DOWN : EGBS_BUTTON_UP;\r
+                       drawSprite(state, ClickTime, pos);\r
+\r
+                       // focused / unfocused animation\r
+                       state = Environment->hasFocus(this) ? EGBS_BUTTON_FOCUSED : EGBS_BUTTON_NOT_FOCUSED;\r
+                       drawSprite(state, FocusTime, pos);\r
+\r
+                       // mouse over / off animation\r
+                       state = Environment->getHovered() == this ? EGBS_BUTTON_MOUSE_OVER : EGBS_BUTTON_MOUSE_OFF;\r
+                       drawSprite(state, HoverTime, pos);\r
+               }\r
+               else\r
+               {\r
+                       // draw disabled\r
+//                     drawSprite(EGBS_BUTTON_DISABLED, 0, pos);\r
+               }\r
+       }\r
+\r
+       if (Text.size())\r
+       {\r
+               IGUIFont* font = getActiveFont();\r
+\r
+               core::rect<s32> rect = AbsoluteRect;\r
+               if (Pressed)\r
+               {\r
+                       rect.UpperLeftCorner.X += skin->getSize(EGDS_BUTTON_PRESSED_TEXT_OFFSET_X);\r
+                       rect.UpperLeftCorner.Y += skin->getSize(EGDS_BUTTON_PRESSED_TEXT_OFFSET_Y);\r
+               }\r
+\r
+               if (font)\r
+                       font->draw(Text.c_str(), rect,\r
+                               OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT),\r
+                               true, true, &AbsoluteClippingRect);\r
+       }\r
+\r
+       IGUIElement::draw();\r
+}\r
+\r
+void GUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center)\r
+{\r
+       u32 stateIdx = (u32)state;\r
+\r
+       if (ButtonSprites[stateIdx].Index != -1)\r
+       {\r
+               if ( ButtonSprites[stateIdx].Scale )\r
+               {\r
+                       const video::SColor colors[] = {ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color};\r
+                       SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, AbsoluteRect.UpperLeftCorner,\r
+                                       &AbsoluteClippingRect, colors[0], // FIXME: remove [0]\r
+                                       porting::getTimeMs()-startTime, ButtonSprites[stateIdx].Loop);\r
+               }\r
+               else\r
+               {\r
+                       SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, center,\r
+                               &AbsoluteClippingRect, ButtonSprites[stateIdx].Color, startTime, porting::getTimeMs(),\r
+                               ButtonSprites[stateIdx].Loop, true);\r
+               }\r
+       }\r
+}\r
+\r
+EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed) const\r
+{\r
+       // figure state we should have\r
+       EGUI_BUTTON_IMAGE_STATE state = EGBIS_IMAGE_DISABLED;\r
+       bool focused = Environment->hasFocus((IGUIElement*)this);\r
+       bool mouseOver = static_cast<const IGUIElement*>(Environment->getHovered()) == this;    // (static cast for Borland)\r
+       if (isEnabled())\r
+       {\r
+               if ( pressed )\r
+               {\r
+                       if ( focused && mouseOver )\r
+                               state = EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER;\r
+                       else if ( focused )\r
+                               state = EGBIS_IMAGE_DOWN_FOCUSED;\r
+                       else if ( mouseOver )\r
+                               state = EGBIS_IMAGE_DOWN_MOUSEOVER;\r
+                       else\r
+                               state = EGBIS_IMAGE_DOWN;\r
+               }\r
+               else // !pressed\r
+               {\r
+                       if ( focused && mouseOver )\r
+                               state = EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER;\r
+                       else if ( focused )\r
+                               state = EGBIS_IMAGE_UP_FOCUSED;\r
+                       else if ( mouseOver )\r
+                               state = EGBIS_IMAGE_UP_MOUSEOVER;\r
+                       else\r
+                               state = EGBIS_IMAGE_UP;\r
+               }\r
+       }\r
+\r
+       // find a compatible state that has images\r
+       while ( state != EGBIS_IMAGE_UP && !ButtonImages[(u32)state].Texture )\r
+       {\r
+               switch ( state )\r
+               {\r
+                       case EGBIS_IMAGE_UP_FOCUSED:\r
+                               state = EGBIS_IMAGE_UP_MOUSEOVER;\r
+                               break;\r
+                       case EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER:\r
+                               state = EGBIS_IMAGE_UP_FOCUSED;\r
+                               break;\r
+                       case EGBIS_IMAGE_DOWN_MOUSEOVER:\r
+                               state = EGBIS_IMAGE_DOWN;\r
+                               break;\r
+                       case EGBIS_IMAGE_DOWN_FOCUSED:\r
+                               state = EGBIS_IMAGE_DOWN_MOUSEOVER;\r
+                               break;\r
+                       case EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER:\r
+                               state = EGBIS_IMAGE_DOWN_FOCUSED;\r
+                               break;\r
+                       case EGBIS_IMAGE_DISABLED:\r
+                               if ( pressed )\r
+                                       state = EGBIS_IMAGE_DOWN;\r
+                               else\r
+                                       state = EGBIS_IMAGE_UP;\r
+                               break;\r
+                       default:\r
+                               state = EGBIS_IMAGE_UP;\r
+               }\r
+       }\r
+\r
+       return state;\r
+}\r
+\r
+//! sets another skin independent font. if this is set to zero, the button uses the font of the skin.\r
+void GUIButton::setOverrideFont(IGUIFont* font)\r
+{\r
+       if (OverrideFont == font)\r
+               return;\r
+\r
+       if (OverrideFont)\r
+               OverrideFont->drop();\r
+\r
+       OverrideFont = font;\r
+\r
+       if (OverrideFont)\r
+               OverrideFont->grab();\r
+}\r
+\r
+//! Gets the override font (if any)\r
+IGUIFont * GUIButton::getOverrideFont() const\r
+{\r
+       return OverrideFont;\r
+}\r
+\r
+//! Get the font which is used right now for drawing\r
+IGUIFont* GUIButton::getActiveFont() const\r
+{\r
+       if ( OverrideFont )\r
+               return OverrideFont;\r
+       IGUISkin* skin = Environment->getSkin();\r
+       if (skin)\r
+               return skin->getFont(EGDF_BUTTON);\r
+       return 0;\r
+}\r
+\r
+//! Sets another color for the text.\r
+void GUIButton::setOverrideColor(video::SColor color)\r
+{\r
+       OverrideColor = color;\r
+       OverrideColorEnabled = true;\r
+}\r
+\r
+video::SColor GUIButton::getOverrideColor() const\r
+{\r
+       return OverrideColor;\r
+}\r
+\r
+void GUIButton::enableOverrideColor(bool enable)\r
+{\r
+       OverrideColorEnabled = enable;\r
+}\r
+\r
+bool GUIButton::isOverrideColorEnabled() const\r
+{\r
+       return OverrideColorEnabled;\r
+}\r
+\r
+void GUIButton::setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image, const core::rect<s32>& sourceRect)\r
+{\r
+       if ( state >= EGBIS_COUNT )\r
+               return;\r
+\r
+       if ( image )\r
+               image->grab();\r
+\r
+       u32 stateIdx = (u32)state;\r
+       if ( ButtonImages[stateIdx].Texture )\r
+               ButtonImages[stateIdx].Texture->drop();\r
+\r
+       ButtonImages[stateIdx].Texture = image;\r
+       ButtonImages[stateIdx].SourceRect = sourceRect;\r
+}\r
+\r
+//! Sets if the button should behave like a push button. Which means it\r
+//! can be in two states: Normal or Pressed. With a click on the button,\r
+//! the user can change the state of the button.\r
+void GUIButton::setIsPushButton(bool isPushButton)\r
+{\r
+       IsPushButton = isPushButton;\r
+}\r
+\r
+\r
+//! Returns if the button is currently pressed\r
+bool GUIButton::isPressed() const\r
+{\r
+       return Pressed;\r
+}\r
+\r
+\r
+//! Sets the pressed state of the button if this is a pushbutton\r
+void GUIButton::setPressed(bool pressed)\r
+{\r
+       if (Pressed != pressed)\r
+       {\r
+               ClickTime = porting::getTimeMs();\r
+               Pressed = pressed;\r
+       }\r
+}\r
+\r
+\r
+//! Returns whether the button is a push button\r
+bool GUIButton::isPushButton() const\r
+{\r
+       return IsPushButton;\r
+}\r
+\r
+\r
+//! Sets if the alpha channel should be used for drawing images on the button (default is false)\r
+void GUIButton::setUseAlphaChannel(bool useAlphaChannel)\r
+{\r
+       UseAlphaChannel = useAlphaChannel;\r
+}\r
+\r
+\r
+//! Returns if the alpha channel should be used for drawing images on the button\r
+bool GUIButton::isAlphaChannelUsed() const\r
+{\r
+       return UseAlphaChannel;\r
+}\r
+\r
+\r
+bool GUIButton::isDrawingBorder() const\r
+{\r
+       return DrawBorder;\r
+}\r
+\r
+\r
+//! Writes attributes of the element.\r
+void GUIButton::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const\r
+{\r
+       IGUIButton::serializeAttributes(out,options);\r
+\r
+       out->addBool    ("PushButton",          IsPushButton );\r
+       if (IsPushButton)\r
+               out->addBool("Pressed",             Pressed);\r
+\r
+       for ( u32 i=0; i<(u32)EGBIS_COUNT; ++i )\r
+       {\r
+               if ( ButtonImages[i].Texture )\r
+               {\r
+                       core::stringc name( GUIButtonImageStateNames[i] );\r
+                       out->addTexture(name.c_str(), ButtonImages[i].Texture);\r
+                       name += "Rect";\r
+                       out->addRect(name.c_str(), ButtonImages[i].SourceRect);\r
+               }\r
+       }\r
+\r
+       out->addBool    ("UseAlphaChannel",     UseAlphaChannel);\r
+       out->addBool    ("Border",                  DrawBorder);\r
+       out->addBool    ("ScaleImage",          ScaleImage);\r
+\r
+       for ( u32 i=0; i<(u32)EGBS_COUNT; ++i )\r
+       {\r
+               if ( ButtonSprites[i].Index >= 0 )\r
+               {\r
+                       core::stringc nameIndex( GUIButtonStateNames[i] );\r
+                       nameIndex += "Index";\r
+                       out->addInt(nameIndex.c_str(), ButtonSprites[i].Index );\r
+\r
+                       core::stringc nameColor( GUIButtonStateNames[i] );\r
+                       nameColor += "Color";\r
+                       out->addColor(nameColor.c_str(), ButtonSprites[i].Color );\r
+\r
+                       core::stringc nameLoop( GUIButtonStateNames[i] );\r
+                       nameLoop += "Loop";\r
+                       out->addBool(nameLoop.c_str(), ButtonSprites[i].Loop );\r
+\r
+                       core::stringc nameScale( GUIButtonStateNames[i] );\r
+                       nameScale += "Scale";\r
+                       out->addBool(nameScale.c_str(), ButtonSprites[i].Scale );\r
+               }\r
+       }\r
+\r
+       //   out->addString  ("OverrideFont",   OverrideFont);\r
+}\r
+\r
+\r
+//! Reads attributes of the element\r
+void GUIButton::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)\r
+{\r
+       IGUIButton::deserializeAttributes(in,options);\r
+\r
+       IsPushButton    = in->getAttributeAsBool("PushButton");\r
+       Pressed         = IsPushButton ? in->getAttributeAsBool("Pressed") : false;\r
+\r
+       core::rect<s32> rec = in->getAttributeAsRect("ImageRect");\r
+       if (rec.isValid())\r
+               setImage( in->getAttributeAsTexture("Image"), rec);\r
+       else\r
+               setImage( in->getAttributeAsTexture("Image") );\r
+\r
+       rec = in->getAttributeAsRect("PressedImageRect");\r
+       if (rec.isValid())\r
+               setPressedImage( in->getAttributeAsTexture("PressedImage"), rec);\r
+       else\r
+               setPressedImage( in->getAttributeAsTexture("PressedImage") );\r
+\r
+       setDrawBorder(in->getAttributeAsBool("Border"));\r
+       setUseAlphaChannel(in->getAttributeAsBool("UseAlphaChannel"));\r
+       setScaleImage(in->getAttributeAsBool("ScaleImage"));\r
+\r
+       //   setOverrideFont(in->getAttributeAsString("OverrideFont"));\r
+\r
+       updateAbsolutePosition();\r
+}\r
+\r
+// PATCH\r
+GUIButton* GUIButton::addButton(IGUIEnvironment *environment, const core::rect<s32>& rectangle,\r
+                                                               IGUIElement* parent, s32 id, const wchar_t* text, const wchar_t *tooltiptext)\r
+{\r
+       GUIButton* button = new GUIButton(environment, parent ? parent : environment->getRootGUIElement(), id, rectangle);\r
+       if (text)\r
+               button->setText(text);\r
+\r
+       if ( tooltiptext )\r
+               button->setToolTipText ( tooltiptext );\r
+\r
+       button->drop();\r
+       return button;\r
+}\r
+\r
+void GUIButton::setColor(video::SColor color)\r
+{\r
+       float d = 0.65f;\r
+       for (size_t i = 0; i < 4; i++) {\r
+               video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);\r
+               Colors[i] = base.getInterpolated(color, d);\r
+       }\r
+}\r
+// END PATCH\r
diff --git a/src/gui/guiButton.h b/src/gui/guiButton.h
new file mode 100644 (file)
index 0000000..04c24d4
--- /dev/null
@@ -0,0 +1,306 @@
+// Copyright (C) 2002-2012 Nikolaus Gebhardt\r
+// This file is part of the "Irrlicht Engine".\r
+// For conditions of distribution and use, see copyright notice in irrlicht.h\r
+\r
+#pragma once\r
+\r
+#include "IrrCompileConfig.h"\r
+\r
+#include "IGUIButton.h"\r
+#include "IGUISpriteBank.h"\r
+#include "ITexture.h"\r
+#include "SColor.h"\r
+#include "guiSkin.h"\r
+\r
+using namespace irr;\r
+\r
+#if (IRRLICHT_VERSION_MAJOR > 1 || IRRLICHT_VERSION_MINOR != 8 || IRRLICHT_VERSION_REVISION < 5)\r
+       namespace irr { namespace gui {\r
+\r
+               //! State of buttons used for drawing texture images.\r
+               //! Note that only a single state is active at a time\r
+               //! Also when no image is defined for a state it will use images from another state\r
+               //! and if that state is not set from the replacement for that,etc.\r
+               //! So in many cases setting EGBIS_IMAGE_UP and EGBIS_IMAGE_DOWN is sufficient.\r
+               enum EGUI_BUTTON_IMAGE_STATE {\r
+                       //! When no other states have images they will all use this one.\r
+                                       EGBIS_IMAGE_UP,\r
+                       //! When not set EGBIS_IMAGE_UP is used.\r
+                                       EGBIS_IMAGE_UP_MOUSEOVER,\r
+                       //! When not set EGBIS_IMAGE_UP_MOUSEOVER is used.\r
+                                       EGBIS_IMAGE_UP_FOCUSED,\r
+                       //! When not set EGBIS_IMAGE_UP_FOCUSED is used.\r
+                                       EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER,\r
+                       //! When not set EGBIS_IMAGE_UP is used.\r
+                                       EGBIS_IMAGE_DOWN,\r
+                       //! When not set EGBIS_IMAGE_DOWN is used.\r
+                                       EGBIS_IMAGE_DOWN_MOUSEOVER,\r
+                       //! When not set EGBIS_IMAGE_DOWN_MOUSEOVER is used.\r
+                                       EGBIS_IMAGE_DOWN_FOCUSED,\r
+                       //! When not set EGBIS_IMAGE_DOWN_FOCUSED is used.\r
+                                       EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER,\r
+                       //! When not set EGBIS_IMAGE_UP or EGBIS_IMAGE_DOWN are used (depending on button state).\r
+                                       EGBIS_IMAGE_DISABLED,\r
+                       //! not used, counts the number of enumerated items\r
+                                       EGBIS_COUNT\r
+               };\r
+\r
+               //! Names for gui button image states\r
+               const c8 *const GUIButtonImageStateNames[EGBIS_COUNT + 1] =\r
+                               {\r
+                                               "Image",    // not "ImageUp" as it otherwise breaks serialization of old files\r
+                                               "ImageUpOver",\r
+                                               "ImageUpFocused",\r
+                                               "ImageUpFocusedOver",\r
+                                               "PressedImage",    // not "ImageDown" as it otherwise breaks serialization of old files\r
+                                               "ImageDownOver",\r
+                                               "ImageDownFocused",\r
+                                               "ImageDownFocusedOver",\r
+                                               "ImageDisabled",\r
+                                               0    // count\r
+                               };\r
+\r
+       }}\r
+\r
+#endif\r
+\r
+class GUIButton : public gui::IGUIButton\r
+{\r
+public:\r
+\r
+       //! constructor\r
+       GUIButton(gui::IGUIEnvironment* environment, gui::IGUIElement* parent,\r
+                          s32 id, core::rect<s32> rectangle, bool noclip=false);\r
+\r
+       //! destructor\r
+       virtual ~GUIButton();\r
+\r
+       //! called if an event happened.\r
+       virtual bool OnEvent(const SEvent& event);\r
+\r
+       //! draws the element and its children\r
+       virtual void draw();\r
+\r
+       //! sets another skin independent font. if this is set to zero, the button uses the font of the skin.\r
+       virtual void setOverrideFont(gui::IGUIFont* font=0);\r
+\r
+       //! Gets the override font (if any)\r
+       virtual gui::IGUIFont* getOverrideFont() const;\r
+\r
+       //! Get the font which is used right now for drawing\r
+       virtual gui::IGUIFont* getActiveFont() const;\r
+\r
+       //! Sets another color for the button text.\r
+       virtual void setOverrideColor(video::SColor color);\r
+\r
+       //! Gets the override color\r
+       virtual video::SColor getOverrideColor(void) const;\r
+\r
+       //! Sets if the button text should use the override color or the color in the gui skin.\r
+       virtual void enableOverrideColor(bool enable);\r
+\r
+       //! Checks if an override color is enabled\r
+       virtual bool isOverrideColorEnabled(void) const;\r
+\r
+       //! Sets an image which should be displayed on the button when it is in the given state.\r
+       virtual void setImage(gui::EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image=0, const core::rect<s32>& sourceRect=core::rect<s32>(0,0,0,0));\r
+\r
+       //! Sets an image which should be displayed on the button when it is in normal state.\r
+       virtual void setImage(video::ITexture* image=0)\r
+       {\r
+               setImage(gui::EGBIS_IMAGE_UP, image);\r
+       }\r
+\r
+       //! Sets an image which should be displayed on the button when it is in normal state.\r
+       virtual void setImage(video::ITexture* image, const core::rect<s32>& pos)\r
+       {\r
+               setImage(gui::EGBIS_IMAGE_UP, image, pos);\r
+       }\r
+\r
+       //! Sets an image which should be displayed on the button when it is in pressed state.\r
+       virtual void setPressedImage(video::ITexture* image=0)\r
+       {\r
+               setImage(gui::EGBIS_IMAGE_DOWN, image);\r
+       }\r
+\r
+       //! Sets an image which should be displayed on the button when it is in pressed state.\r
+       virtual void setPressedImage(video::ITexture* image, const core::rect<s32>& pos)\r
+       {\r
+               setImage(gui::EGBIS_IMAGE_DOWN, image, pos);\r
+       }\r
+\r
+       //! Sets the sprite bank used by the button\r
+       virtual void setSpriteBank(gui::IGUISpriteBank* bank=0);\r
+\r
+       //! Sets the animated sprite for a specific button state\r
+       /** \param index: Number of the sprite within the sprite bank, use -1 for no sprite\r
+       \param state: State of the button to set the sprite for\r
+       \param index: The sprite number from the current sprite bank\r
+       \param color: The color of the sprite\r
+       */\r
+       virtual void setSprite(gui::EGUI_BUTTON_STATE state, s32 index,\r
+                                                  video::SColor color=video::SColor(255,255,255,255),\r
+                                                  bool loop=false, bool scale=false);\r
+\r
+       void setSprite(gui::EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop) override {\r
+               setSprite(state, index, color, loop, false);\r
+       }\r
+\r
+       //! Get the sprite-index for the given state or -1 when no sprite is set\r
+       virtual s32 getSpriteIndex(gui::EGUI_BUTTON_STATE state) const;\r
+\r
+       //! Get the sprite color for the given state. Color is only used when a sprite is set.\r
+       virtual video::SColor getSpriteColor(gui::EGUI_BUTTON_STATE state) const;\r
+\r
+       //! Returns if the sprite in the given state does loop\r
+       virtual bool getSpriteLoop(gui::EGUI_BUTTON_STATE state) const;\r
+\r
+       //! Returns if the sprite in the given state is scaled\r
+       virtual bool getSpriteScale(gui::EGUI_BUTTON_STATE state) const;\r
+\r
+       //! Sets if the button should behave like a push button. Which means it\r
+       //! can be in two states: Normal or Pressed. With a click on the button,\r
+       //! the user can change the state of the button.\r
+       virtual void setIsPushButton(bool isPushButton=true);\r
+\r
+       //! Checks whether the button is a push button\r
+       virtual bool isPushButton() const;\r
+\r
+       //! Sets the pressed state of the button if this is a pushbutton\r
+       virtual void setPressed(bool pressed=true);\r
+\r
+       //! Returns if the button is currently pressed\r
+       virtual bool isPressed() const;\r
+\r
+       //! Sets if the button should use the skin to draw its border\r
+       virtual void setDrawBorder(bool border=true);\r
+\r
+       //! Checks if the button face and border are being drawn\r
+       virtual bool isDrawingBorder() const;\r
+\r
+       //! Sets if the alpha channel should be used for drawing images on the button (default is false)\r
+       virtual void setUseAlphaChannel(bool useAlphaChannel=true);\r
+\r
+       //! Checks if the alpha channel should be used for drawing images on the button\r
+       virtual bool isAlphaChannelUsed() const;\r
+\r
+       //! Sets if the button should scale the button images to fit\r
+       virtual void setScaleImage(bool scaleImage=true);\r
+\r
+       //! Checks whether the button scales the used images\r
+       virtual bool isScalingImage() const;\r
+\r
+       //! Get if the shift key was pressed in last EGET_BUTTON_CLICKED event\r
+       virtual bool getClickShiftState() const\r
+       {\r
+               return ClickShiftState;\r
+       }\r
+\r
+       //! Get if the control key was pressed in last EGET_BUTTON_CLICKED event\r
+       virtual bool getClickControlState() const\r
+       {\r
+               return ClickControlState;\r
+       }\r
+\r
+       //! Writes attributes of the element.\r
+       virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;\r
+\r
+       //! Reads attributes of the element\r
+       virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);\r
+\r
+\r
+\r
+       void setColor(video::SColor color);\r
+\r
+\r
+       //! Do not drop returned handle\r
+       static GUIButton* addButton(gui::IGUIEnvironment *environment, const core::rect<s32>& rectangle,\r
+                                                                       IGUIElement* parent, s32 id, const wchar_t* text, const wchar_t *tooltiptext=L"");\r
+\r
+protected:\r
+       void drawSprite(gui::EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center);\r
+       gui::EGUI_BUTTON_IMAGE_STATE getImageState(bool pressed) const;\r
+\r
+private:\r
+\r
+       struct ButtonSprite\r
+       {\r
+               ButtonSprite() : Index(-1), Loop(false), Scale(false)\r
+               {\r
+               }\r
+\r
+               bool operator==(const ButtonSprite& other) const\r
+               {\r
+                       return Index == other.Index && Color == other.Color && Loop == other.Loop && Scale == other.Scale;\r
+               }\r
+\r
+               s32 Index;\r
+               video::SColor Color;\r
+               bool Loop;\r
+               bool Scale;\r
+       };\r
+\r
+       ButtonSprite ButtonSprites[gui::EGBS_COUNT];\r
+       gui::IGUISpriteBank* SpriteBank;\r
+\r
+       struct ButtonImage\r
+       {\r
+               ButtonImage() : Texture(0), SourceRect(core::rect<s32>(0,0,0,0))\r
+               {\r
+               }\r
+\r
+               ButtonImage(const ButtonImage& other) : Texture(0), SourceRect(core::rect<s32>(0,0,0,0))\r
+               {\r
+                       *this = other;\r
+               }\r
+\r
+               ~ButtonImage()\r
+               {\r
+                       if ( Texture )\r
+                               Texture->drop();\r
+               }\r
+\r
+               ButtonImage& operator=(const ButtonImage& other)\r
+               {\r
+                       if ( this == &other )\r
+                               return *this;\r
+\r
+                       if (other.Texture)\r
+                               other.Texture->grab();\r
+                       if ( Texture )\r
+                               Texture->drop();\r
+                       Texture = other.Texture;\r
+                       SourceRect = other.SourceRect;\r
+                       return *this;\r
+               }\r
+\r
+               bool operator==(const ButtonImage& other) const\r
+               {\r
+                       return Texture == other.Texture && SourceRect == other.SourceRect;\r
+               }\r
+\r
+\r
+               video::ITexture* Texture;\r
+               core::rect<s32> SourceRect;\r
+       };\r
+\r
+       ButtonImage ButtonImages[gui::EGBIS_COUNT];\r
+\r
+       gui::IGUIFont* OverrideFont;\r
+\r
+       bool OverrideColorEnabled;\r
+       video::SColor OverrideColor;\r
+\r
+       u32 ClickTime, HoverTime, FocusTime;\r
+\r
+       bool ClickShiftState;\r
+       bool ClickControlState;\r
+\r
+       bool IsPushButton;\r
+       bool Pressed;\r
+       bool UseAlphaChannel;\r
+       bool DrawBorder;\r
+       bool ScaleImage;\r
+\r
+       video::SColor Colors[4];\r
+};\r
index 4d3409f3bd44ffb6732fa6c3694f5bef9cf33db5..382fbbd540708adf201b7727154cba270537f70b 100644 (file)
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <iterator>
 #include <sstream>
 #include <limits>
+#include "guiButton.h"
 #include "guiFormSpecMenu.h"
 #include "guiTable.h"
 #include "constants.h"
@@ -698,9 +699,8 @@ void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element,
                spec.ftype = f_Button;
                if(type == "button_exit")
                        spec.is_exit = true;
-               gui::IGUIButton* e = Environment->addButton(rect, this, spec.fid,
-                               spec.flabel.c_str());
 
+               GUIButton *e = GUIButton::addButton(Environment, rect, this, spec.fid, spec.flabel.c_str());
                if (spec.fname == data->focused_fieldname) {
                        Environment->setFocus(e);
                }
diff --git a/src/gui/guiSkin.cpp b/src/gui/guiSkin.cpp
new file mode 100644 (file)
index 0000000..8892a00
--- /dev/null
@@ -0,0 +1,1084 @@
+// Copyright (C) 2002-2012 Nikolaus Gebhardt\r
+// Copyright (C) 2019 Irrlick\r
+//\r
+// This file is part of the "Irrlicht Engine".\r
+// For conditions of distribution and use, see copyright notice in irrlicht.h\r
+\r
+#include "guiSkin.h"\r
+#ifdef _IRR_COMPILE_WITH_GUI_\r
+\r
+#include "IGUIFont.h"\r
+#include "IGUISpriteBank.h"\r
+#include "IGUIElement.h"\r
+#include "IVideoDriver.h"\r
+#include "IAttributes.h"\r
+\r
+namespace irr\r
+{\r
+namespace gui\r
+{\r
+\r
+GUISkin::GUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver)\r
+: SpriteBank(0), Driver(driver), Type(type)\r
+{\r
+       #ifdef _DEBUG\r
+       setDebugName("GUISkin");\r
+       #endif\r
+\r
+       if ((Type == EGST_WINDOWS_CLASSIC) || (Type == EGST_WINDOWS_METALLIC))\r
+       {\r
+               Colors[EGDC_3D_DARK_SHADOW]     = video::SColor(101,50,50,50);\r
+               Colors[EGDC_3D_SHADOW]          = video::SColor(101,130,130,130);\r
+               Colors[EGDC_3D_FACE]            = video::SColor(101,210,210,210);\r
+               Colors[EGDC_3D_HIGH_LIGHT]      = video::SColor(101,255,255,255);\r
+               Colors[EGDC_3D_LIGHT]           = video::SColor(101,210,210,210);\r
+               Colors[EGDC_ACTIVE_BORDER]      = video::SColor(101,16,14,115);\r
+               Colors[EGDC_ACTIVE_CAPTION]     = video::SColor(255,255,255,255);\r
+               Colors[EGDC_APP_WORKSPACE]      = video::SColor(101,100,100,100);\r
+               Colors[EGDC_BUTTON_TEXT]        = video::SColor(240,10,10,10);\r
+               Colors[EGDC_GRAY_TEXT]          = video::SColor(240,130,130,130);\r
+               Colors[EGDC_HIGH_LIGHT]         = video::SColor(101,8,36,107);\r
+               Colors[EGDC_HIGH_LIGHT_TEXT]    = video::SColor(240,255,255,255);\r
+               Colors[EGDC_INACTIVE_BORDER]    = video::SColor(101,165,165,165);\r
+               Colors[EGDC_INACTIVE_CAPTION]   = video::SColor(255,30,30,30);\r
+               Colors[EGDC_TOOLTIP]            = video::SColor(200,0,0,0);\r
+               Colors[EGDC_TOOLTIP_BACKGROUND] = video::SColor(200,255,255,225);\r
+               Colors[EGDC_SCROLLBAR]          = video::SColor(101,230,230,230);\r
+               Colors[EGDC_WINDOW]             = video::SColor(101,255,255,255);\r
+               Colors[EGDC_WINDOW_SYMBOL]      = video::SColor(200,10,10,10);\r
+               Colors[EGDC_ICON]               = video::SColor(200,255,255,255);\r
+               Colors[EGDC_ICON_HIGH_LIGHT]    = video::SColor(200,8,36,107);\r
+               Colors[EGDC_GRAY_WINDOW_SYMBOL] = video::SColor(240,100,100,100);\r
+               Colors[EGDC_EDITABLE]                   = video::SColor(255,255,255,255);\r
+               Colors[EGDC_GRAY_EDITABLE]              = video::SColor(255,120,120,120);\r
+               Colors[EGDC_FOCUSED_EDITABLE]   = video::SColor(255,240,240,255);\r
+\r
+\r
+               Sizes[EGDS_SCROLLBAR_SIZE] = 14;\r
+               Sizes[EGDS_MENU_HEIGHT] = 30;\r
+               Sizes[EGDS_WINDOW_BUTTON_WIDTH] = 15;\r
+               Sizes[EGDS_CHECK_BOX_WIDTH] = 18;\r
+               Sizes[EGDS_MESSAGE_BOX_WIDTH] = 500;\r
+               Sizes[EGDS_MESSAGE_BOX_HEIGHT] = 200;\r
+               Sizes[EGDS_BUTTON_WIDTH] = 80;\r
+               Sizes[EGDS_BUTTON_HEIGHT] = 30;\r
+\r
+               Sizes[EGDS_TEXT_DISTANCE_X] = 2;\r
+               Sizes[EGDS_TEXT_DISTANCE_Y] = 0;\r
+\r
+               Sizes[EGDS_TITLEBARTEXT_DISTANCE_X] = 2;\r
+               Sizes[EGDS_TITLEBARTEXT_DISTANCE_Y] = 0;\r
+       }\r
+       else\r
+       {\r
+               //0x80a6a8af\r
+               Colors[EGDC_3D_DARK_SHADOW]     =       0x60767982;\r
+               //Colors[EGDC_3D_FACE]                  =       0xc0c9ccd4;             // tab background\r
+               Colors[EGDC_3D_FACE]                    =       0xc0cbd2d9;             // tab background\r
+               Colors[EGDC_3D_SHADOW]                  =       0x50e4e8f1;             // tab background, and left-top highlight\r
+               Colors[EGDC_3D_HIGH_LIGHT]              =       0x40c7ccdc;\r
+               Colors[EGDC_3D_LIGHT]                   =       0x802e313a;\r
+               Colors[EGDC_ACTIVE_BORDER]              =       0x80404040;             // window title\r
+               Colors[EGDC_ACTIVE_CAPTION]     =       0xffd0d0d0;\r
+               Colors[EGDC_APP_WORKSPACE]              =       0xc0646464;             // unused\r
+               Colors[EGDC_BUTTON_TEXT]                =       0xd0161616;\r
+               Colors[EGDC_GRAY_TEXT]                  =       0x3c141414;\r
+               Colors[EGDC_HIGH_LIGHT]                 =       0x6c606060;\r
+               Colors[EGDC_HIGH_LIGHT_TEXT]    =       0xd0e0e0e0;\r
+               Colors[EGDC_INACTIVE_BORDER]    =       0xf0a5a5a5;\r
+               Colors[EGDC_INACTIVE_CAPTION]   =       0xffd2d2d2;\r
+               Colors[EGDC_TOOLTIP]                    =       0xf00f2033;\r
+               Colors[EGDC_TOOLTIP_BACKGROUND] =       0xc0cbd2d9;\r
+               Colors[EGDC_SCROLLBAR]                  =       0xf0e0e0e0;\r
+               Colors[EGDC_WINDOW]                             =       0xf0f0f0f0;\r
+               Colors[EGDC_WINDOW_SYMBOL]              =       0xd0161616;\r
+               Colors[EGDC_ICON]                               =       0xd0161616;\r
+               Colors[EGDC_ICON_HIGH_LIGHT]    =       0xd0606060;\r
+               Colors[EGDC_GRAY_WINDOW_SYMBOL] =       0x3c101010;\r
+               Colors[EGDC_EDITABLE]                   =       0xf0ffffff;\r
+               Colors[EGDC_GRAY_EDITABLE]              =       0xf0cccccc;\r
+               Colors[EGDC_FOCUSED_EDITABLE]   =       0xf0fffff0;\r
+\r
+               Sizes[EGDS_SCROLLBAR_SIZE] = 14;\r
+               Sizes[EGDS_MENU_HEIGHT] = 48;\r
+               Sizes[EGDS_WINDOW_BUTTON_WIDTH] = 15;\r
+               Sizes[EGDS_CHECK_BOX_WIDTH] = 18;\r
+               Sizes[EGDS_MESSAGE_BOX_WIDTH] = 500;\r
+               Sizes[EGDS_MESSAGE_BOX_HEIGHT] = 200;\r
+               Sizes[EGDS_BUTTON_WIDTH] = 80;\r
+               Sizes[EGDS_BUTTON_HEIGHT] = 30;\r
+\r
+               Sizes[EGDS_TEXT_DISTANCE_X] = 3;\r
+               Sizes[EGDS_TEXT_DISTANCE_Y] = 2;\r
+\r
+               Sizes[EGDS_TITLEBARTEXT_DISTANCE_X] = 3;\r
+               Sizes[EGDS_TITLEBARTEXT_DISTANCE_Y] = 2;\r
+       }\r
+\r
+       Sizes[EGDS_MESSAGE_BOX_GAP_SPACE] = 15;\r
+       Sizes[EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH] = 0;\r
+       Sizes[EGDS_MESSAGE_BOX_MAX_TEXT_WIDTH] = 500;\r
+       Sizes[EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT] = 0;\r
+       Sizes[EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT] = 99999;\r
+\r
+       Sizes[EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X] = 1;\r
+       Sizes[EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y] = 1;\r
+       Sizes[EGDS_BUTTON_PRESSED_TEXT_OFFSET_X] = 0;\r
+       Sizes[EGDS_BUTTON_PRESSED_TEXT_OFFSET_Y] = 2;\r
+\r
+       Texts[EGDT_MSG_BOX_OK] = L"OK";\r
+       Texts[EGDT_MSG_BOX_CANCEL] = L"Cancel";\r
+       Texts[EGDT_MSG_BOX_YES] = L"Yes";\r
+       Texts[EGDT_MSG_BOX_NO] = L"No";\r
+       Texts[EGDT_WINDOW_CLOSE] = L"Close";\r
+       Texts[EGDT_WINDOW_RESTORE] = L"Restore";\r
+       Texts[EGDT_WINDOW_MINIMIZE] = L"Minimize";\r
+       Texts[EGDT_WINDOW_MAXIMIZE] = L"Maximize";\r
+\r
+       Icons[EGDI_WINDOW_MAXIMIZE] = 225;\r
+       Icons[EGDI_WINDOW_RESTORE] = 226;\r
+       Icons[EGDI_WINDOW_CLOSE] = 227;\r
+       Icons[EGDI_WINDOW_MINIMIZE] = 228;\r
+       Icons[EGDI_CURSOR_UP] = 229;\r
+       Icons[EGDI_CURSOR_DOWN] = 230;\r
+       Icons[EGDI_CURSOR_LEFT] = 231;\r
+       Icons[EGDI_CURSOR_RIGHT] = 232;\r
+       Icons[EGDI_MENU_MORE] = 232;\r
+       Icons[EGDI_CHECK_BOX_CHECKED] = 233;\r
+       Icons[EGDI_DROP_DOWN] = 234;\r
+       Icons[EGDI_SMALL_CURSOR_UP] = 235;\r
+       Icons[EGDI_SMALL_CURSOR_DOWN] = 236;\r
+       Icons[EGDI_RADIO_BUTTON_CHECKED] = 237;\r
+       Icons[EGDI_MORE_LEFT] = 238;\r
+       Icons[EGDI_MORE_RIGHT] = 239;\r
+       Icons[EGDI_MORE_UP] = 240;\r
+       Icons[EGDI_MORE_DOWN] = 241;\r
+       Icons[EGDI_WINDOW_RESIZE] = 242;\r
+       Icons[EGDI_EXPAND] = 243;\r
+       Icons[EGDI_COLLAPSE] = 244;\r
+\r
+       Icons[EGDI_FILE] = 245;\r
+       Icons[EGDI_DIRECTORY] = 246;\r
+\r
+       for (u32 i=0; i<EGDF_COUNT; ++i)\r
+               Fonts[i] = 0;\r
+\r
+       UseGradient = (Type == EGST_WINDOWS_METALLIC) || (Type == EGST_BURNING_SKIN) ;\r
+}\r
+\r
+\r
+//! destructor\r
+GUISkin::~GUISkin()\r
+{\r
+       for (u32 i=0; i<EGDF_COUNT; ++i)\r
+       {\r
+               if (Fonts[i])\r
+                       Fonts[i]->drop();\r
+       }\r
+\r
+       if (SpriteBank)\r
+               SpriteBank->drop();\r
+}\r
+\r
+\r
+//! returns default color\r
+video::SColor GUISkin::getColor(EGUI_DEFAULT_COLOR color) const\r
+{\r
+       if ((u32)color < EGDC_COUNT)\r
+               return Colors[color];\r
+       else\r
+               return video::SColor();\r
+}\r
+\r
+\r
+//! sets a default color\r
+void GUISkin::setColor(EGUI_DEFAULT_COLOR which, video::SColor newColor)\r
+{\r
+       if ((u32)which < EGDC_COUNT)\r
+               Colors[which] = newColor;\r
+}\r
+\r
+\r
+//! returns size for the given size type\r
+s32 GUISkin::getSize(EGUI_DEFAULT_SIZE size) const\r
+{\r
+       if ((u32)size < EGDS_COUNT)\r
+               return Sizes[size];\r
+       else\r
+               return 0;\r
+}\r
+\r
+\r
+//! sets a default size\r
+void GUISkin::setSize(EGUI_DEFAULT_SIZE which, s32 size)\r
+{\r
+       if ((u32)which < EGDS_COUNT)\r
+               Sizes[which] = size;\r
+}\r
+\r
+\r
+//! returns the default font\r
+IGUIFont* GUISkin::getFont(EGUI_DEFAULT_FONT which) const\r
+{\r
+       if (((u32)which < EGDF_COUNT) && Fonts[which])\r
+               return Fonts[which];\r
+       else\r
+               return Fonts[EGDF_DEFAULT];\r
+}\r
+\r
+\r
+//! sets a default font\r
+void GUISkin::setFont(IGUIFont* font, EGUI_DEFAULT_FONT which)\r
+{\r
+       if ((u32)which >= EGDF_COUNT)\r
+               return;\r
+\r
+       if (font)\r
+       {\r
+               font->grab();\r
+               if (Fonts[which])\r
+                       Fonts[which]->drop();\r
+\r
+               Fonts[which] = font;\r
+       }\r
+}\r
+\r
+\r
+//! gets the sprite bank stored\r
+IGUISpriteBank* GUISkin::getSpriteBank() const\r
+{\r
+       return SpriteBank;\r
+}\r
+\r
+\r
+//! set a new sprite bank or remove one by passing 0\r
+void GUISkin::setSpriteBank(IGUISpriteBank* bank)\r
+{\r
+       if (bank)\r
+               bank->grab();\r
+\r
+       if (SpriteBank)\r
+               SpriteBank->drop();\r
+\r
+       SpriteBank = bank;\r
+}\r
+\r
+\r
+//! Returns a default icon\r
+u32 GUISkin::getIcon(EGUI_DEFAULT_ICON icon) const\r
+{\r
+       if ((u32)icon < EGDI_COUNT)\r
+               return Icons[icon];\r
+       else\r
+               return 0;\r
+}\r
+\r
+\r
+//! Sets a default icon\r
+void GUISkin::setIcon(EGUI_DEFAULT_ICON icon, u32 index)\r
+{\r
+       if ((u32)icon < EGDI_COUNT)\r
+               Icons[icon] = index;\r
+}\r
+\r
+\r
+//! Returns a default text. For example for Message box button captions:\r
+//! "OK", "Cancel", "Yes", "No" and so on.\r
+const wchar_t* GUISkin::getDefaultText(EGUI_DEFAULT_TEXT text) const\r
+{\r
+       if ((u32)text < EGDT_COUNT)\r
+               return Texts[text].c_str();\r
+       else\r
+               return Texts[0].c_str();\r
+}\r
+\r
+\r
+//! Sets a default text. For example for Message box button captions:\r
+//! "OK", "Cancel", "Yes", "No" and so on.\r
+void GUISkin::setDefaultText(EGUI_DEFAULT_TEXT which, const wchar_t* newText)\r
+{\r
+       if ((u32)which < EGDT_COUNT)\r
+               Texts[which] = newText;\r
+}\r
+\r
+\r
+//! draws a standard 3d button pane\r
+/**    Used for drawing for example buttons in normal state.\r
+It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and\r
+EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details.\r
+\param rect: Defining area where to draw.\r
+\param clip: Clip area.\r
+\param element: Pointer to the element which wishes to draw this. This parameter\r
+is usually not used by ISkin, but can be used for example by more complex\r
+implementations to find out how to draw the part exactly. */\r
+// PATCH\r
+void GUISkin::drawColored3DButtonPaneStandard(IGUIElement* element,\r
+                                       const core::rect<s32>& r,\r
+                                       const core::rect<s32>* clip,\r
+                                       const video::SColor* colors)\r
+{\r
+       if (!Driver)\r
+               return;\r
+\r
+       if (!colors)\r
+               colors = Colors;\r
+\r
+       core::rect<s32> rect = r;\r
+\r
+       if ( Type == EGST_BURNING_SKIN )\r
+       {\r
+               rect.UpperLeftCorner.X -= 1;\r
+               rect.UpperLeftCorner.Y -= 1;\r
+               rect.LowerRightCorner.X += 1;\r
+               rect.LowerRightCorner.Y += 1;\r
+               draw3DSunkenPane(element,\r
+                                       colors[ EGDC_WINDOW ].getInterpolated( 0xFFFFFFFF, 0.9f )\r
+                                       ,false, true, rect, clip);\r
+               return;\r
+       }\r
+\r
+       Driver->draw2DRectangle(colors[EGDC_3D_DARK_SHADOW], rect, clip);\r
+\r
+       rect.LowerRightCorner.X -= 1;\r
+       rect.LowerRightCorner.Y -= 1;\r
+       Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], rect, clip);\r
+\r
+       rect.UpperLeftCorner.X += 1;\r
+       rect.UpperLeftCorner.Y += 1;\r
+       Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], rect, clip);\r
+\r
+       rect.LowerRightCorner.X -= 1;\r
+       rect.LowerRightCorner.Y -= 1;\r
+\r
+       if (!UseGradient)\r
+       {\r
+               Driver->draw2DRectangle(colors[EGDC_3D_FACE], rect, clip);\r
+       }\r
+       else\r
+       {\r
+               const video::SColor c1 = colors[EGDC_3D_FACE];\r
+               const video::SColor c2 = c1.getInterpolated(colors[EGDC_3D_DARK_SHADOW], 0.4f);\r
+               Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip);\r
+       }\r
+}\r
+// END PATCH\r
+\r
+\r
+//! draws a pressed 3d button pane\r
+/**    Used for drawing for example buttons in pressed state.\r
+It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and\r
+EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details.\r
+\param rect: Defining area where to draw.\r
+\param clip: Clip area.\r
+\param element: Pointer to the element which wishes to draw this. This parameter\r
+is usually not used by ISkin, but can be used for example by more complex\r
+implementations to find out how to draw the part exactly. */\r
+// PATCH\r
+void GUISkin::drawColored3DButtonPanePressed(IGUIElement* element,\r
+                                       const core::rect<s32>& r,\r
+                                       const core::rect<s32>* clip,\r
+                                       const video::SColor* colors)\r
+{\r
+       if (!Driver)\r
+               return;\r
+\r
+       if (!colors)\r
+               colors = Colors;\r
+\r
+       core::rect<s32> rect = r;\r
+       Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], rect, clip);\r
+\r
+       rect.LowerRightCorner.X -= 1;\r
+       rect.LowerRightCorner.Y -= 1;\r
+       Driver->draw2DRectangle(colors[EGDC_3D_DARK_SHADOW], rect, clip);\r
+\r
+       rect.UpperLeftCorner.X += 1;\r
+       rect.UpperLeftCorner.Y += 1;\r
+       Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], rect, clip);\r
+\r
+       rect.UpperLeftCorner.X += 1;\r
+       rect.UpperLeftCorner.Y += 1;\r
+\r
+       if (!UseGradient)\r
+       {\r
+               Driver->draw2DRectangle(colors[EGDC_3D_FACE], rect, clip);\r
+       }\r
+       else\r
+       {\r
+               const video::SColor c1 = colors[EGDC_3D_FACE];\r
+               const video::SColor c2 = c1.getInterpolated(colors[EGDC_3D_DARK_SHADOW], 0.4f);\r
+               Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip);\r
+       }\r
+}\r
+// END PATCH\r
+\r
+\r
+//! draws a sunken 3d pane\r
+/** Used for drawing the background of edit, combo or check boxes.\r
+\param element: Pointer to the element which wishes to draw this. This parameter\r
+is usually not used by ISkin, but can be used for example by more complex\r
+implementations to find out how to draw the part exactly.\r
+\param bgcolor: Background color.\r
+\param flat: Specifies if the sunken pane should be flat or displayed as sunken\r
+deep into the ground.\r
+\param rect: Defining area where to draw.\r
+\param clip: Clip area.        */\r
+// PATCH\r
+void GUISkin::drawColored3DSunkenPane(IGUIElement* element, video::SColor bgcolor,\r
+                               bool flat, bool fillBackGround,\r
+                               const core::rect<s32>& r,\r
+                               const core::rect<s32>* clip,\r
+                               const video::SColor* colors)\r
+{\r
+       if (!Driver)\r
+               return;\r
+\r
+       if (!colors)\r
+               colors = Colors;\r
+\r
+       core::rect<s32> rect = r;\r
+\r
+       if (fillBackGround)\r
+               Driver->draw2DRectangle(bgcolor, rect, clip);\r
+\r
+       if (flat)\r
+       {\r
+               // draw flat sunken pane\r
+\r
+               rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], rect, clip);    // top\r
+\r
+               ++rect.UpperLeftCorner.Y;\r
+               rect.LowerRightCorner.Y = r.LowerRightCorner.Y;\r
+               rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], rect, clip);    // left\r
+\r
+               rect = r;\r
+               ++rect.UpperLeftCorner.Y;\r
+               rect.UpperLeftCorner.X = rect.LowerRightCorner.X - 1;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], rect, clip);        // right\r
+\r
+               rect = r;\r
+               ++rect.UpperLeftCorner.X;\r
+               rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1;\r
+               --rect.LowerRightCorner.X;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], rect, clip);        // bottom\r
+       }\r
+       else\r
+       {\r
+               // draw deep sunken pane\r
+               rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], rect, clip);    // top\r
+               ++rect.UpperLeftCorner.X;\r
+               ++rect.UpperLeftCorner.Y;\r
+               --rect.LowerRightCorner.X;\r
+               ++rect.LowerRightCorner.Y;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_DARK_SHADOW], rect, clip);\r
+\r
+               rect.UpperLeftCorner.X = r.UpperLeftCorner.X;\r
+               rect.UpperLeftCorner.Y = r.UpperLeftCorner.Y+1;\r
+               rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1;\r
+               rect.LowerRightCorner.Y = r.LowerRightCorner.Y;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], rect, clip);    // left\r
+               ++rect.UpperLeftCorner.X;\r
+               ++rect.UpperLeftCorner.Y;\r
+               ++rect.LowerRightCorner.X;\r
+               --rect.LowerRightCorner.Y;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_DARK_SHADOW], rect, clip);\r
+\r
+               rect = r;\r
+               rect.UpperLeftCorner.X = rect.LowerRightCorner.X - 1;\r
+               ++rect.UpperLeftCorner.Y;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], rect, clip);        // right\r
+               --rect.UpperLeftCorner.X;\r
+               ++rect.UpperLeftCorner.Y;\r
+               --rect.LowerRightCorner.X;\r
+               --rect.LowerRightCorner.Y;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_LIGHT], rect, clip);\r
+\r
+               rect = r;\r
+               ++rect.UpperLeftCorner.X;\r
+               rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1;\r
+               --rect.LowerRightCorner.X;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], rect, clip);        // bottom\r
+               ++rect.UpperLeftCorner.X;\r
+               --rect.UpperLeftCorner.Y;\r
+               --rect.LowerRightCorner.X;\r
+               --rect.LowerRightCorner.Y;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_LIGHT], rect, clip);\r
+       }\r
+}\r
+// END PATCH\r
+\r
+//! draws a window background\r
+// return where to draw title bar text.\r
+// PATCH\r
+core::rect<s32> GUISkin::drawColored3DWindowBackground(IGUIElement* element,\r
+                               bool drawTitleBar, video::SColor titleBarColor,\r
+                               const core::rect<s32>& r,\r
+                               const core::rect<s32>* clip,\r
+                               core::rect<s32>* checkClientArea,\r
+                               const video::SColor* colors)\r
+{\r
+       if (!Driver)\r
+       {\r
+               if ( checkClientArea )\r
+               {\r
+                       *checkClientArea = r;\r
+               }\r
+               return r;\r
+       }\r
+\r
+       if (!colors)\r
+               colors = Colors;\r
+\r
+       core::rect<s32> rect = r;\r
+\r
+       // top border\r
+       rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1;\r
+       if ( !checkClientArea )\r
+       {\r
+               Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], rect, clip);\r
+       }\r
+\r
+       // left border\r
+       rect.LowerRightCorner.Y = r.LowerRightCorner.Y;\r
+       rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1;\r
+       if ( !checkClientArea )\r
+       {\r
+               Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], rect, clip);\r
+       }\r
+\r
+       // right border dark outer line\r
+       rect.UpperLeftCorner.X = r.LowerRightCorner.X - 1;\r
+       rect.LowerRightCorner.X = r.LowerRightCorner.X;\r
+       rect.UpperLeftCorner.Y = r.UpperLeftCorner.Y;\r
+       rect.LowerRightCorner.Y = r.LowerRightCorner.Y;\r
+       if ( !checkClientArea )\r
+       {\r
+               Driver->draw2DRectangle(colors[EGDC_3D_DARK_SHADOW], rect, clip);\r
+       }\r
+\r
+       // right border bright innner line\r
+       rect.UpperLeftCorner.X -= 1;\r
+       rect.LowerRightCorner.X -= 1;\r
+       rect.UpperLeftCorner.Y += 1;\r
+       rect.LowerRightCorner.Y -= 1;\r
+       if ( !checkClientArea )\r
+       {\r
+               Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], rect, clip);\r
+       }\r
+\r
+       // bottom border dark outer line\r
+       rect.UpperLeftCorner.X = r.UpperLeftCorner.X;\r
+       rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1;\r
+       rect.LowerRightCorner.Y = r.LowerRightCorner.Y;\r
+       rect.LowerRightCorner.X = r.LowerRightCorner.X;\r
+       if ( !checkClientArea )\r
+       {\r
+               Driver->draw2DRectangle(colors[EGDC_3D_DARK_SHADOW], rect, clip);\r
+       }\r
+\r
+       // bottom border bright inner line\r
+       rect.UpperLeftCorner.X += 1;\r
+       rect.LowerRightCorner.X -= 1;\r
+       rect.UpperLeftCorner.Y -= 1;\r
+       rect.LowerRightCorner.Y -= 1;\r
+       if ( !checkClientArea )\r
+       {\r
+               Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], rect, clip);\r
+       }\r
+\r
+       // client area for background\r
+       rect = r;\r
+       rect.UpperLeftCorner.X +=1;\r
+       rect.UpperLeftCorner.Y +=1;\r
+       rect.LowerRightCorner.X -= 2;\r
+       rect.LowerRightCorner.Y -= 2;\r
+       if (checkClientArea)\r
+       {\r
+               *checkClientArea = rect;\r
+       }\r
+\r
+       if ( !checkClientArea )\r
+       {\r
+               if (!UseGradient)\r
+               {\r
+                       Driver->draw2DRectangle(colors[EGDC_3D_FACE], rect, clip);\r
+               }\r
+               else if ( Type == EGST_BURNING_SKIN )\r
+               {\r
+                       const video::SColor c1 = colors[EGDC_WINDOW].getInterpolated ( 0xFFFFFFFF, 0.9f );\r
+                       const video::SColor c2 = colors[EGDC_WINDOW].getInterpolated ( 0xFFFFFFFF, 0.8f );\r
+\r
+                       Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip);\r
+               }\r
+               else\r
+               {\r
+                       const video::SColor c2 = colors[EGDC_3D_SHADOW];\r
+                       const video::SColor c1 = colors[EGDC_3D_FACE];\r
+                       Driver->draw2DRectangle(rect, c1, c1, c1, c2, clip);\r
+               }\r
+       }\r
+\r
+       // title bar\r
+       rect = r;\r
+       rect.UpperLeftCorner.X += 2;\r
+       rect.UpperLeftCorner.Y += 2;\r
+       rect.LowerRightCorner.X -= 2;\r
+       rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + getSize(EGDS_WINDOW_BUTTON_WIDTH) + 2;\r
+\r
+       if (drawTitleBar )\r
+       {\r
+               if (checkClientArea)\r
+               {\r
+                       (*checkClientArea).UpperLeftCorner.Y = rect.LowerRightCorner.Y;\r
+               }\r
+               else\r
+               {\r
+                       // draw title bar\r
+                       //if (!UseGradient)\r
+                       //      Driver->draw2DRectangle(titleBarColor, rect, clip);\r
+                       //else\r
+                       if ( Type == EGST_BURNING_SKIN )\r
+                       {\r
+                               const video::SColor c = titleBarColor.getInterpolated( video::SColor(titleBarColor.getAlpha(),255,255,255), 0.8f);\r
+                               Driver->draw2DRectangle(rect, titleBarColor, titleBarColor, c, c, clip);\r
+                       }\r
+                       else\r
+                       {\r
+                               const video::SColor c = titleBarColor.getInterpolated(video::SColor(titleBarColor.getAlpha(),0,0,0), 0.2f);\r
+                               Driver->draw2DRectangle(rect, titleBarColor, c, titleBarColor, c, clip);\r
+                       }\r
+               }\r
+       }\r
+\r
+       return rect;\r
+}\r
+// END PATCH\r
+\r
+\r
+//! draws a standard 3d menu pane\r
+/**    Used for drawing for menus and context menus.\r
+It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and\r
+EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details.\r
+\param element: Pointer to the element which wishes to draw this. This parameter\r
+is usually not used by ISkin, but can be used for example by more complex\r
+implementations to find out how to draw the part exactly.\r
+\param rect: Defining area where to draw.\r
+\param clip: Clip area.        */\r
+// PATCH\r
+void GUISkin::drawColored3DMenuPane(IGUIElement* element,\r
+                       const core::rect<s32>& r, const core::rect<s32>* clip,\r
+                       const video::SColor* colors)\r
+{\r
+       if (!Driver)\r
+               return;\r
+\r
+       if (!colors)\r
+               colors = Colors;\r
+\r
+       core::rect<s32> rect = r;\r
+\r
+       if ( Type == EGST_BURNING_SKIN )\r
+       {\r
+               rect.UpperLeftCorner.Y -= 3;\r
+               draw3DButtonPaneStandard(element, rect, clip);\r
+               return;\r
+       }\r
+\r
+       // in this skin, this is exactly what non pressed buttons look like,\r
+       // so we could simply call\r
+       // draw3DButtonPaneStandard(element, rect, clip);\r
+       // here.\r
+       // but if the skin is transparent, this doesn't look that nice. So\r
+       // We draw it a little bit better, with some more draw2DRectangle calls,\r
+       // but there aren't that much menus visible anyway.\r
+\r
+       rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1;\r
+       Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], rect, clip);\r
+\r
+       rect.LowerRightCorner.Y = r.LowerRightCorner.Y;\r
+       rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1;\r
+       Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], rect, clip);\r
+\r
+       rect.UpperLeftCorner.X = r.LowerRightCorner.X - 1;\r
+       rect.LowerRightCorner.X = r.LowerRightCorner.X;\r
+       rect.UpperLeftCorner.Y = r.UpperLeftCorner.Y;\r
+       rect.LowerRightCorner.Y = r.LowerRightCorner.Y;\r
+       Driver->draw2DRectangle(colors[EGDC_3D_DARK_SHADOW], rect, clip);\r
+\r
+       rect.UpperLeftCorner.X -= 1;\r
+       rect.LowerRightCorner.X -= 1;\r
+       rect.UpperLeftCorner.Y += 1;\r
+       rect.LowerRightCorner.Y -= 1;\r
+       Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], rect, clip);\r
+\r
+       rect.UpperLeftCorner.X = r.UpperLeftCorner.X;\r
+       rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1;\r
+       rect.LowerRightCorner.Y = r.LowerRightCorner.Y;\r
+       rect.LowerRightCorner.X = r.LowerRightCorner.X;\r
+       Driver->draw2DRectangle(colors[EGDC_3D_DARK_SHADOW], rect, clip);\r
+\r
+       rect.UpperLeftCorner.X += 1;\r
+       rect.LowerRightCorner.X -= 1;\r
+       rect.UpperLeftCorner.Y -= 1;\r
+       rect.LowerRightCorner.Y -= 1;\r
+       Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], rect, clip);\r
+\r
+       rect = r;\r
+       rect.UpperLeftCorner.X +=1;\r
+       rect.UpperLeftCorner.Y +=1;\r
+       rect.LowerRightCorner.X -= 2;\r
+       rect.LowerRightCorner.Y -= 2;\r
+\r
+       if (!UseGradient)\r
+               Driver->draw2DRectangle(colors[EGDC_3D_FACE], rect, clip);\r
+       else\r
+       {\r
+               const video::SColor c1 = colors[EGDC_3D_FACE];\r
+               const video::SColor c2 = colors[EGDC_3D_SHADOW];\r
+               Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip);\r
+       }\r
+}\r
+// END PATCH\r
+\r
+\r
+//! draws a standard 3d tool bar\r
+/**    Used for drawing for toolbars and menus.\r
+\param element: Pointer to the element which wishes to draw this. This parameter\r
+is usually not used by ISkin, but can be used for example by more complex\r
+implementations to find out how to draw the part exactly.\r
+\param rect: Defining area where to draw.\r
+\param clip: Clip area.        */\r
+// PATCH\r
+void GUISkin::drawColored3DToolBar(IGUIElement* element,\r
+                               const core::rect<s32>& r,\r
+                               const core::rect<s32>* clip,\r
+                               const video::SColor* colors)\r
+{\r
+       if (!Driver)\r
+               return;\r
+\r
+       if (!colors)\r
+               colors = Colors;\r
+\r
+       core::rect<s32> rect = r;\r
+\r
+       rect.UpperLeftCorner.X = r.UpperLeftCorner.X;\r
+       rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1;\r
+       rect.LowerRightCorner.Y = r.LowerRightCorner.Y;\r
+       rect.LowerRightCorner.X = r.LowerRightCorner.X;\r
+       Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], rect, clip);\r
+\r
+       rect = r;\r
+       rect.LowerRightCorner.Y -= 1;\r
+\r
+       if (!UseGradient)\r
+       {\r
+               Driver->draw2DRectangle(colors[EGDC_3D_FACE], rect, clip);\r
+       }\r
+       else\r
+       if ( Type == EGST_BURNING_SKIN )\r
+       {\r
+               const video::SColor c1 = 0xF0000000 | colors[EGDC_3D_FACE].color;\r
+               const video::SColor c2 = 0xF0000000 | colors[EGDC_3D_SHADOW].color;\r
+\r
+               rect.LowerRightCorner.Y += 1;\r
+               Driver->draw2DRectangle(rect, c1, c2, c1, c2, clip);\r
+       }\r
+       else\r
+       {\r
+               const video::SColor c1 = colors[EGDC_3D_FACE];\r
+               const video::SColor c2 = colors[EGDC_3D_SHADOW];\r
+               Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip);\r
+       }\r
+}\r
+// END PATCH\r
+\r
+//! draws a tab button\r
+/**    Used for drawing for tab buttons on top of tabs.\r
+\param element: Pointer to the element which wishes to draw this. This parameter\r
+is usually not used by ISkin, but can be used for example by more complex\r
+implementations to find out how to draw the part exactly.\r
+\param active: Specifies if the tab is currently active.\r
+\param rect: Defining area where to draw.\r
+\param clip: Clip area.        */\r
+// PATCH\r
+void GUISkin::drawColored3DTabButton(IGUIElement* element, bool active,\r
+       const core::rect<s32>& frameRect, const core::rect<s32>* clip, EGUI_ALIGNMENT alignment,\r
+       const video::SColor* colors)\r
+{\r
+       if (!Driver)\r
+               return;\r
+\r
+       if (!colors)\r
+               colors = Colors;\r
+\r
+       core::rect<s32> tr = frameRect;\r
+\r
+       if ( alignment == EGUIA_UPPERLEFT )\r
+       {\r
+               tr.LowerRightCorner.X -= 2;\r
+               tr.LowerRightCorner.Y = tr.UpperLeftCorner.Y + 1;\r
+               tr.UpperLeftCorner.X += 1;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], tr, clip);\r
+\r
+               // draw left highlight\r
+               tr = frameRect;\r
+               tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1;\r
+               tr.UpperLeftCorner.Y += 1;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], tr, clip);\r
+\r
+               // draw grey background\r
+               tr = frameRect;\r
+               tr.UpperLeftCorner.X += 1;\r
+               tr.UpperLeftCorner.Y += 1;\r
+               tr.LowerRightCorner.X -= 2;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_FACE], tr, clip);\r
+\r
+               // draw right middle gray shadow\r
+               tr.LowerRightCorner.X += 1;\r
+               tr.UpperLeftCorner.X = tr.LowerRightCorner.X - 1;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], tr, clip);\r
+\r
+               tr.LowerRightCorner.X += 1;\r
+               tr.UpperLeftCorner.X += 1;\r
+               tr.UpperLeftCorner.Y += 1;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_DARK_SHADOW], tr, clip);\r
+       }\r
+       else\r
+       {\r
+               tr.LowerRightCorner.X -= 2;\r
+               tr.UpperLeftCorner.Y = tr.LowerRightCorner.Y - 1;\r
+               tr.UpperLeftCorner.X += 1;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], tr, clip);\r
+\r
+               // draw left highlight\r
+               tr = frameRect;\r
+               tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1;\r
+               tr.LowerRightCorner.Y -= 1;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], tr, clip);\r
+\r
+               // draw grey background\r
+               tr = frameRect;\r
+               tr.UpperLeftCorner.X += 1;\r
+               tr.UpperLeftCorner.Y -= 1;\r
+               tr.LowerRightCorner.X -= 2;\r
+               tr.LowerRightCorner.Y -= 1;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_FACE], tr, clip);\r
+\r
+               // draw right middle gray shadow\r
+               tr.LowerRightCorner.X += 1;\r
+               tr.UpperLeftCorner.X = tr.LowerRightCorner.X - 1;\r
+               //tr.LowerRightCorner.Y -= 1;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], tr, clip);\r
+\r
+               tr.LowerRightCorner.X += 1;\r
+               tr.UpperLeftCorner.X += 1;\r
+               tr.LowerRightCorner.Y -= 1;\r
+               Driver->draw2DRectangle(colors[EGDC_3D_DARK_SHADOW], tr, clip);\r
+       }\r
+}\r
+// END PATCH\r
+\r
+\r
+//! draws a tab control body\r
+/**    \param element: Pointer to the element which wishes to draw this. This parameter\r
+is usually not used by ISkin, but can be used for example by more complex\r
+implementations to find out how to draw the part exactly.\r
+\param border: Specifies if the border should be drawn.\r
+\param background: Specifies if the background should be drawn.\r
+\param rect: Defining area where to draw.\r
+\param clip: Clip area.        */\r
+// PATCH\r
+void GUISkin::drawColored3DTabBody(IGUIElement* element, bool border, bool background,\r
+       const core::rect<s32>& rect, const core::rect<s32>* clip, s32 tabHeight, EGUI_ALIGNMENT alignment,\r
+       const video::SColor* colors)\r
+{\r
+       if (!Driver)\r
+               return;\r
+\r
+       if (!colors)\r
+               colors = Colors;\r
+\r
+       core::rect<s32> tr = rect;\r
+\r
+       if ( tabHeight == -1 )\r
+               tabHeight = getSize(gui::EGDS_BUTTON_HEIGHT);\r
+\r
+       // draw border.\r
+       if (border)\r
+       {\r
+               if ( alignment == EGUIA_UPPERLEFT )\r
+               {\r
+                       // draw left hightlight\r
+                       tr.UpperLeftCorner.Y += tabHeight + 2;\r
+                       tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1;\r
+                       Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], tr, clip);\r
+\r
+                       // draw right shadow\r
+                       tr.UpperLeftCorner.X = rect.LowerRightCorner.X - 1;\r
+                       tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1;\r
+                       Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], tr, clip);\r
+\r
+                       // draw lower shadow\r
+                       tr = rect;\r
+                       tr.UpperLeftCorner.Y = tr.LowerRightCorner.Y - 1;\r
+                       Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], tr, clip);\r
+               }\r
+               else\r
+               {\r
+                       // draw left hightlight\r
+                       tr.LowerRightCorner.Y -= tabHeight + 2;\r
+                       tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1;\r
+                       Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], tr, clip);\r
+\r
+                       // draw right shadow\r
+                       tr.UpperLeftCorner.X = rect.LowerRightCorner.X - 1;\r
+                       tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1;\r
+                       Driver->draw2DRectangle(colors[EGDC_3D_SHADOW], tr, clip);\r
+\r
+                       // draw lower shadow\r
+                       tr = rect;\r
+                       tr.LowerRightCorner.Y = tr.UpperLeftCorner.Y + 1;\r
+                       Driver->draw2DRectangle(colors[EGDC_3D_HIGH_LIGHT], tr, clip);\r
+               }\r
+       }\r
+\r
+       if (background)\r
+       {\r
+               if ( alignment == EGUIA_UPPERLEFT )\r
+               {\r
+                       tr = rect;\r
+                       tr.UpperLeftCorner.Y += tabHeight + 2;\r
+                       tr.LowerRightCorner.X -= 1;\r
+                       tr.UpperLeftCorner.X += 1;\r
+                       tr.LowerRightCorner.Y -= 1;\r
+               }\r
+               else\r
+               {\r
+                       tr = rect;\r
+                       tr.UpperLeftCorner.X += 1;\r
+                       tr.UpperLeftCorner.Y -= 1;\r
+                       tr.LowerRightCorner.X -= 1;\r
+                       tr.LowerRightCorner.Y -= tabHeight + 2;\r
+                       //tr.UpperLeftCorner.X += 1;\r
+               }\r
+\r
+               if (!UseGradient)\r
+                       Driver->draw2DRectangle(colors[EGDC_3D_FACE], tr, clip);\r
+               else\r
+               {\r
+                       video::SColor c1 = colors[EGDC_3D_FACE];\r
+                       video::SColor c2 = colors[EGDC_3D_SHADOW];\r
+                       Driver->draw2DRectangle(tr, c1, c1, c2, c2, clip);\r
+               }\r
+       }\r
+}\r
+// END PATCH\r
+\r
+\r
+//! draws an icon, usually from the skin's sprite bank\r
+/**    \param parent: Pointer to the element which wishes to draw this icon.\r
+This parameter is usually not used by IGUISkin, but can be used for example\r
+by more complex implementations to find out how to draw the part exactly.\r
+\param icon: Specifies the icon to be drawn.\r
+\param position: The position to draw the icon\r
+\param starttime: The time at the start of the animation\r
+\param currenttime: The present time, used to calculate the frame number\r
+\param loop: Whether the animation should loop or not\r
+\param clip: Clip area.        */\r
+// PATCH\r
+void GUISkin::drawColoredIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon,\r
+                       const core::position2di position,\r
+                       u32 starttime, u32 currenttime,\r
+                       bool loop, const core::rect<s32>* clip,\r
+                       const video::SColor* colors)\r
+{\r
+       if (!SpriteBank)\r
+               return;\r
+\r
+       if (!colors)\r
+               colors = Colors;\r
+\r
+       bool gray = element && !element->isEnabled();\r
+       SpriteBank->draw2DSprite(Icons[icon], position, clip,\r
+                       colors[gray? EGDC_GRAY_WINDOW_SYMBOL : EGDC_WINDOW_SYMBOL], starttime, currenttime, loop, true);\r
+}\r
+// END PATCH\r
+\r
+\r
+EGUI_SKIN_TYPE GUISkin::getType() const\r
+{\r
+       return Type;\r
+}\r
+\r
+\r
+//! draws a 2d rectangle.\r
+void GUISkin::draw2DRectangle(IGUIElement* element,\r
+               const video::SColor &color, const core::rect<s32>& pos,\r
+               const core::rect<s32>* clip)\r
+{\r
+       Driver->draw2DRectangle(color, pos, clip);\r
+}\r
+\r
+\r
+//! Writes attributes of the object.\r
+//! Implement this to expose the attributes of your scene node animator for\r
+//! scripting languages, editors, debuggers or xml serialization purposes.\r
+void GUISkin::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const\r
+{\r
+       u32 i;\r
+       for (i=0; i<EGDC_COUNT; ++i)\r
+               out->addColor(GUISkinColorNames[i], Colors[i]);\r
+\r
+       for (i=0; i<EGDS_COUNT; ++i)\r
+               out->addInt(GUISkinSizeNames[i], Sizes[i]);\r
+\r
+       for (i=0; i<EGDT_COUNT; ++i)\r
+               out->addString(GUISkinTextNames[i], Texts[i].c_str());\r
+\r
+       for (i=0; i<EGDI_COUNT; ++i)\r
+               out->addInt(GUISkinIconNames[i], Icons[i]);\r
+}\r
+\r
+\r
+//! Reads attributes of the object.\r
+//! Implement this to set the attributes of your scene node animator for\r
+//! scripting languages, editors, debuggers or xml deserialization purposes.\r
+void GUISkin::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)\r
+{\r
+       // TODO: This is not nice code for downward compatibility, whenever new values are added and users\r
+       // load an old skin the corresponding values will be set to 0.\r
+       u32 i;\r
+       for (i=0; i<EGDC_COUNT; ++i)\r
+               Colors[i] = in->getAttributeAsColor(GUISkinColorNames[i]);\r
+\r
+       for (i=0; i<EGDS_COUNT; ++i)\r
+               Sizes[i] = in->getAttributeAsInt(GUISkinSizeNames[i]);\r
+\r
+       for (i=0; i<EGDT_COUNT; ++i)\r
+               Texts[i] = in->getAttributeAsStringW(GUISkinTextNames[i]);\r
+\r
+       for (i=0; i<EGDI_COUNT; ++i)\r
+               Icons[i] = in->getAttributeAsInt(GUISkinIconNames[i]);\r
+}\r
+\r
+\r
+//! gets the colors\r
+// PATCH\r
+void GUISkin::getColors(video::SColor* colors)\r
+{\r
+       u32 i;\r
+       for (i=0; i<EGDC_COUNT; ++i)\r
+               colors[i] = Colors[i];\r
+}\r
+// END PATCH\r
+\r
+} // end namespace gui\r
+} // end namespace irr\r
+\r
+\r
+#endif // _IRR_COMPILE_WITH_GUI_\r
+\r
diff --git a/src/gui/guiSkin.h b/src/gui/guiSkin.h
new file mode 100644 (file)
index 0000000..bbb900f
--- /dev/null
@@ -0,0 +1,376 @@
+// Copyright (C) 2002-2012 Nikolaus Gebhardt\r
+// This file is part of the "Irrlicht Engine".\r
+// For conditions of distribution and use, see copyright notice in irrlicht.h\r
+\r
+#ifndef __GUI_SKIN_H_INCLUDED__\r
+#define __GUI_SKIN_H_INCLUDED__\r
+\r
+#include "IrrCompileConfig.h"\r
+#ifdef _IRR_COMPILE_WITH_GUI_\r
+\r
+#include "IGUISkin.h"\r
+#include "irrString.h"\r
+#include <string>\r
+#include "ITexture.h"\r
+\r
+namespace irr\r
+{\r
+namespace video\r
+{\r
+       class IVideoDriver;\r
+}\r
+namespace gui\r
+{\r
+       class GUISkin : public IGUISkin\r
+       {\r
+       public:\r
+\r
+               GUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver);\r
+\r
+               //! destructor\r
+               virtual ~GUISkin();\r
+\r
+               //! returns default color\r
+               virtual video::SColor getColor(EGUI_DEFAULT_COLOR color) const;\r
+\r
+               //! sets a default color\r
+               virtual void setColor(EGUI_DEFAULT_COLOR which, video::SColor newColor);\r
+\r
+               //! returns size for the given size type\r
+               virtual s32 getSize(EGUI_DEFAULT_SIZE size) const;\r
+\r
+               //! sets a default size\r
+               virtual void setSize(EGUI_DEFAULT_SIZE which, s32 size);\r
+\r
+               //! returns the default font\r
+               virtual IGUIFont* getFont(EGUI_DEFAULT_FONT which=EGDF_DEFAULT) const;\r
+\r
+               //! sets a default font\r
+               virtual void setFont(IGUIFont* font, EGUI_DEFAULT_FONT which=EGDF_DEFAULT);\r
+\r
+               //! sets the sprite bank used for drawing icons\r
+               virtual void setSpriteBank(IGUISpriteBank* bank);\r
+\r
+               //! gets the sprite bank used for drawing icons\r
+               virtual IGUISpriteBank* getSpriteBank() const;\r
+\r
+               //! Returns a default icon\r
+               /** Returns the sprite index within the sprite bank */\r
+               virtual u32 getIcon(EGUI_DEFAULT_ICON icon) const;\r
+\r
+               //! Sets a default icon\r
+               /** Sets the sprite index used for drawing icons like arrows,\r
+               close buttons and ticks in checkboxes\r
+               \param icon: Enum specifying which icon to change\r
+               \param index: The sprite index used to draw this icon */\r
+               virtual void setIcon(EGUI_DEFAULT_ICON icon, u32 index);\r
+\r
+               //! Returns a default text.\r
+               /** For example for Message box button captions:\r
+               "OK", "Cancel", "Yes", "No" and so on. */\r
+               virtual const wchar_t* getDefaultText(EGUI_DEFAULT_TEXT text) const;\r
+\r
+               //! Sets a default text.\r
+               /** For example for Message box button captions:\r
+               "OK", "Cancel", "Yes", "No" and so on. */\r
+               virtual void setDefaultText(EGUI_DEFAULT_TEXT which, const wchar_t* newText);\r
+\r
+               //! draws a standard 3d button pane\r
+               /** Used for drawing for example buttons in normal state.\r
+               It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and\r
+               EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details.\r
+               \param rect: Defining area where to draw.\r
+               \param clip: Clip area.\r
+               \param element: Pointer to the element which wishes to draw this. This parameter\r
+               is usually not used by ISkin, but can be used for example by more complex\r
+               implementations to find out how to draw the part exactly. */\r
+               virtual void draw3DButtonPaneStandard(IGUIElement* element,\r
+                               const core::rect<s32>& rect,\r
+                               const core::rect<s32>* clip=0)\r
+               {\r
+                       drawColored3DButtonPaneStandard(element, rect,clip);\r
+               }\r
+\r
+               virtual void drawColored3DButtonPaneStandard(IGUIElement* element,\r
+                               const core::rect<s32>& rect,\r
+                               const core::rect<s32>* clip=0,\r
+                               const video::SColor* colors=0);\r
+\r
+               //! draws a pressed 3d button pane\r
+               /** Used for drawing for example buttons in pressed state.\r
+               It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and\r
+               EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details.\r
+               \param rect: Defining area where to draw.\r
+               \param clip: Clip area.\r
+               \param element: Pointer to the element which wishes to draw this. This parameter\r
+               is usually not used by ISkin, but can be used for example by more complex\r
+               implementations to find out how to draw the part exactly. */\r
+               virtual void draw3DButtonPanePressed(IGUIElement* element,\r
+                               const core::rect<s32>& rect,\r
+                               const core::rect<s32>* clip=0)\r
+               {\r
+                       drawColored3DButtonPanePressed(element, rect, clip);\r
+               }\r
+\r
+               virtual void drawColored3DButtonPanePressed(IGUIElement* element,\r
+                               const core::rect<s32>& rect,\r
+                               const core::rect<s32>* clip=0,\r
+                               const video::SColor* colors=0);\r
+\r
+               //! draws a sunken 3d pane\r
+               /** Used for drawing the background of edit, combo or check boxes.\r
+               \param element: Pointer to the element which wishes to draw this. This parameter\r
+               is usually not used by ISkin, but can be used for example by more complex\r
+               implementations to find out how to draw the part exactly.\r
+               \param bgcolor: Background color.\r
+               \param flat: Specifies if the sunken pane should be flat or displayed as sunken\r
+               deep into the ground.\r
+               \param rect: Defining area where to draw.\r
+               \param clip: Clip area. */\r
+               virtual void draw3DSunkenPane(IGUIElement* element,\r
+                               video::SColor bgcolor, bool flat,\r
+                               bool fillBackGround,\r
+                               const core::rect<s32>& rect,\r
+                               const core::rect<s32>* clip=0)\r
+               {\r
+                       drawColored3DSunkenPane(element, bgcolor, flat, fillBackGround, rect, clip);\r
+               }\r
+\r
+               virtual void drawColored3DSunkenPane(IGUIElement* element,\r
+                               video::SColor bgcolor, bool flat,\r
+                               bool fillBackGround,\r
+                               const core::rect<s32>& rect,\r
+                               const core::rect<s32>* clip=0,\r
+                               const video::SColor* colors=0);\r
+\r
+               //! draws a window background\r
+               /** Used for drawing the background of dialogs and windows.\r
+               \param element: Pointer to the element which wishes to draw this. This parameter\r
+               is usually not used by ISkin, but can be used for example by more complex\r
+               implementations to find out how to draw the part exactly.\r
+               \param titleBarColor: Title color.\r
+               \param drawTitleBar: True to enable title drawing.\r
+               \param rect: Defining area where to draw.\r
+               \param clip: Clip area.\r
+               \param checkClientArea: When set to non-null the function will not draw anything,\r
+               but will instead return the clientArea which can be used for drawing by the calling window.\r
+               That is the area without borders and without titlebar.\r
+               \return Returns rect where it would be good to draw title bar text. This will\r
+               work even when checkClientArea is set to a non-null value.*/\r
+               virtual core::rect<s32> draw3DWindowBackground(IGUIElement* element,\r
+                               bool drawTitleBar, video::SColor titleBarColor,\r
+                               const core::rect<s32>& rect,\r
+                               const core::rect<s32>* clip,\r
+                               core::rect<s32>* checkClientArea)\r
+               {\r
+                       return drawColored3DWindowBackground(element, drawTitleBar, titleBarColor,\r
+                               rect, clip, checkClientArea);\r
+               }\r
+\r
+               virtual core::rect<s32> drawColored3DWindowBackground(IGUIElement* element,\r
+                               bool drawTitleBar, video::SColor titleBarColor,\r
+                               const core::rect<s32>& rect,\r
+                               const core::rect<s32>* clip,\r
+                               core::rect<s32>* checkClientArea,\r
+                               const video::SColor* colors=0);\r
+\r
+               //! draws a standard 3d menu pane\r
+               /** Used for drawing for menus and context menus.\r
+               It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and\r
+               EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details.\r
+               \param element: Pointer to the element which wishes to draw this. This parameter\r
+               is usually not used by ISkin, but can be used for example by more complex\r
+               implementations to find out how to draw the part exactly.\r
+               \param rect: Defining area where to draw.\r
+               \param clip: Clip area. */\r
+               virtual void draw3DMenuPane(IGUIElement* element,\r
+                               const core::rect<s32>& rect,\r
+                               const core::rect<s32>* clip=0)\r
+               {\r
+                       drawColored3DMenuPane(element, rect, clip);\r
+               }\r
+\r
+               virtual void drawColored3DMenuPane(IGUIElement* element,\r
+                               const core::rect<s32>& rect,\r
+                               const core::rect<s32>* clip=0,\r
+                               const video::SColor* colors=0);\r
+\r
+               //! draws a standard 3d tool bar\r
+               /** Used for drawing for toolbars and menus.\r
+               \param element: Pointer to the element which wishes to draw this. This parameter\r
+               is usually not used by ISkin, but can be used for example by more complex\r
+               implementations to find out how to draw the part exactly.\r
+               \param rect: Defining area where to draw.\r
+               \param clip: Clip area. */\r
+               virtual void draw3DToolBar(IGUIElement* element,\r
+                               const core::rect<s32>& rect,\r
+                               const core::rect<s32>* clip=0)\r
+               {\r
+                       drawColored3DToolBar(element, rect, clip);\r
+               }\r
+\r
+               virtual void drawColored3DToolBar(IGUIElement* element,\r
+                               const core::rect<s32>& rect,\r
+                               const core::rect<s32>* clip=0,\r
+                               const video::SColor* colors=0);\r
+\r
+               //! draws a tab button\r
+               /** Used for drawing for tab buttons on top of tabs.\r
+               \param element: Pointer to the element which wishes to draw this. This parameter\r
+               is usually not used by ISkin, but can be used for example by more complex\r
+               implementations to find out how to draw the part exactly.\r
+               \param active: Specifies if the tab is currently active.\r
+               \param rect: Defining area where to draw.\r
+               \param clip: Clip area. */\r
+               virtual void draw3DTabButton(IGUIElement* element, bool active,\r
+                       const core::rect<s32>& rect, const core::rect<s32>* clip=0, EGUI_ALIGNMENT alignment=EGUIA_UPPERLEFT)\r
+               {\r
+                       drawColored3DTabButton(element, active, rect, clip, alignment);\r
+               }\r
+\r
+               virtual void drawColored3DTabButton(IGUIElement* element, bool active,\r
+                       const core::rect<s32>& rect, const core::rect<s32>* clip=0, EGUI_ALIGNMENT alignment=EGUIA_UPPERLEFT,\r
+                       const video::SColor* colors=0);\r
+\r
+               //! draws a tab control body\r
+               /** \param element: Pointer to the element which wishes to draw this. This parameter\r
+               is usually not used by ISkin, but can be used for example by more complex\r
+               implementations to find out how to draw the part exactly.\r
+               \param border: Specifies if the border should be drawn.\r
+               \param background: Specifies if the background should be drawn.\r
+               \param rect: Defining area where to draw.\r
+               \param clip: Clip area. */\r
+               virtual void draw3DTabBody(IGUIElement* element, bool border, bool background,\r
+                       const core::rect<s32>& rect, const core::rect<s32>* clip=0, s32 tabHeight=-1, EGUI_ALIGNMENT alignment=EGUIA_UPPERLEFT)\r
+               {\r
+                       drawColored3DTabBody(element, border, background, rect, clip, tabHeight, alignment);\r
+               }\r
+\r
+               virtual void drawColored3DTabBody(IGUIElement* element, bool border, bool background,\r
+                       const core::rect<s32>& rect, const core::rect<s32>* clip=0, s32 tabHeight=-1, EGUI_ALIGNMENT alignment=EGUIA_UPPERLEFT,\r
+                       const video::SColor* colors=0);\r
+\r
+               //! draws an icon, usually from the skin's sprite bank\r
+               /** \param element: Pointer to the element which wishes to draw this icon.\r
+               This parameter is usually not used by IGUISkin, but can be used for example\r
+               by more complex implementations to find out how to draw the part exactly.\r
+               \param icon: Specifies the icon to be drawn.\r
+               \param position: The position to draw the icon\r
+               \param starttime: The time at the start of the animation\r
+               \param currenttime: The present time, used to calculate the frame number\r
+               \param loop: Whether the animation should loop or not\r
+               \param clip: Clip area. */\r
+               virtual void drawIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon,\r
+                               const core::position2di position,\r
+                               u32 starttime=0, u32 currenttime=0,\r
+                               bool loop=false, const core::rect<s32>* clip=0)\r
+               {\r
+                       drawColoredIcon(element, icon, position, starttime, currenttime, loop, clip);\r
+               }\r
+\r
+               virtual void drawColoredIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon,\r
+                               const core::position2di position,\r
+                               u32 starttime=0, u32 currenttime=0,\r
+                               bool loop=false, const core::rect<s32>* clip=0,\r
+                               const video::SColor* colors=0);\r
+\r
+               //! draws a 2d rectangle.\r
+               /** \param element: Pointer to the element which wishes to draw this icon.\r
+               This parameter is usually not used by IGUISkin, but can be used for example\r
+               by more complex implementations to find out how to draw the part exactly.\r
+               \param color: Color of the rectangle to draw. The alpha component specifies how\r
+               transparent the rectangle will be.\r
+               \param pos: Position of the rectangle.\r
+               \param clip: Pointer to rectangle against which the rectangle will be clipped.\r
+               If the pointer is null, no clipping will be performed. */\r
+               virtual void draw2DRectangle(IGUIElement* element, const video::SColor &color,\r
+                               const core::rect<s32>& pos, const core::rect<s32>* clip = 0);\r
+\r
+\r
+               //! get the type of this skin\r
+               virtual EGUI_SKIN_TYPE getType() const;\r
+\r
+               //! Writes attributes of the object.\r
+               //! Implement this to expose the attributes of your scene node animator for\r
+               //! scripting languages, editors, debuggers or xml serialization purposes.\r
+               virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;\r
+\r
+               //! Reads attributes of the object.\r
+               //! Implement this to set the attributes of your scene node animator for\r
+               //! scripting languages, editors, debuggers or xml deserialization purposes.\r
+               virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);\r
+\r
+               //! gets the colors\r
+               virtual void getColors(video::SColor* colors); // ::PATCH:\r
+\r
+       private:\r
+\r
+               video::SColor Colors[EGDC_COUNT];\r
+               s32 Sizes[EGDS_COUNT];\r
+               u32 Icons[EGDI_COUNT];\r
+               IGUIFont* Fonts[EGDF_COUNT];\r
+               IGUISpriteBank* SpriteBank;\r
+               core::stringw Texts[EGDT_COUNT];\r
+               video::IVideoDriver* Driver;\r
+               bool UseGradient;\r
+\r
+               EGUI_SKIN_TYPE Type;\r
+       };\r
+\r
+       #define set3DSkinColors(skin, button_color) \\r
+               { \\r
+                       skin->setColor(EGDC_3D_FACE, button_color); \\r
+                       skin->setColor(EGDC_3D_DARK_SHADOW, button_color, 0.25f); \\r
+                       skin->setColor(EGDC_3D_SHADOW, button_color, 0.5f); \\r
+                       skin->setColor(EGDC_3D_LIGHT, button_color); \\r
+                       skin->setColor(EGDC_3D_HIGH_LIGHT, button_color, 1.5f); \\r
+               }\r
+\r
+       #define getElementSkinColor(color) \\r
+               { \\r
+                       if (!Colors) \\r
+                       { \\r
+                               IGUISkin* skin = Environment->getSkin(); \\r
+                               if (skin) \\r
+                                       return skin->getColor(color); \\r
+                       } \\r
+                       return Colors[color]; \\r
+               }\r
+\r
+       #define setElementSkinColor(which, newColor, shading) \\r
+               { \\r
+                       if (!Colors) \\r
+                       { \\r
+                               Colors = new video::SColor[EGDC_COUNT]; \\r
+                               GUISkin* skin = (GUISkin *)Environment->getSkin(); \\r
+                               if (skin) \\r
+                                       skin->getColors(Colors); \\r
+                       } \\r
+                       Colors[which] = newColor; \\r
+                       setShading(Colors[which],shading); \\r
+               }\r
+} // end namespace gui\r
+//! Sets the shading\r
+inline void setShading(video::SColor &color,f32 s) // :PATCH:\r
+{\r
+       if (s < 1.0f)\r
+       {\r
+               color.setRed(color.getRed() * s);\r
+               color.setGreen(color.getGreen() * s);\r
+               color.setBlue(color.getBlue() * s);\r
+       }\r
+       else if (s > 1.0f)\r
+       {\r
+               s -= 1.0f;\r
+\r
+               color.setRed(color.getRed() + (255 - color.getRed()) * s);\r
+               color.setGreen(color.getGreen() + (255 - color.getGreen()) * s);\r
+               color.setBlue(color.getBlue() + (255 - color.getBlue()) * s);\r
+       }\r
+}\r
+} // end namespace irr\r
+\r
+\r
+#endif // _IRR_COMPILE_WITH_GUI_\r
+\r
+#endif\r
index 15aa9bbcec42549c2ec1363b6fbe2f04ecc0dac3..f9cf150ed8a35b626a4da0120a52aa8eef169985 100644 (file)
@@ -155,6 +155,8 @@ src/genericobject.cpp
 src/genericobject.h
 src/gettext.cpp
 src/gettext.h
+src/gui/guiButton.cpp
+src/gui/guiButton.h
 src/gui/guiChatConsole.cpp
 src/gui/guiChatConsole.h
 src/gui/guiConfirmRegistration.cpp
@@ -170,6 +172,8 @@ src/gui/guiPasswordChange.cpp
 src/gui/guiPathSelectMenu.cpp
 src/gui/guiPathSelectMenu.h
 src/gui/guiScrollBar.cpp
+src/gui/guiSkin.cpp
+src/gui/guiSkin.h
 src/gui/guiTable.cpp
 src/gui/guiTable.h
 src/gui/guiVolumeChange.cpp