diff --git a/source/gui/CButton.cpp b/source/gui/CButton.cpp index 5de9341152..21c04381e1 100755 --- a/source/gui/CButton.cpp +++ b/source/gui/CButton.cpp @@ -17,6 +17,7 @@ using namespace std; //------------------------------------------------------------------- CButton::CButton() { + AddSetting(GUIST_float, "buffer-zone"); AddSetting(GUIST_CGUIString, "caption"); AddSetting(GUIST_CStr, "font"); AddSetting(GUIST_CStr, "sprite"); @@ -61,40 +62,42 @@ void CButton::SetupText() // Check which alignment to use! EAlign align; EVAlign valign; + float bz; GUI::GetSetting(this, "text-align", align); GUI::GetSetting(this, "text-valign", valign); - - m_TextPos = m_CachedActualSize.TopLeft(); + GUI::GetSetting(this, "buffer-zone", bz); switch (align) { case EAlign_Left: - m_TextPos.x = m_CachedActualSize.left; + m_TextPos.x = m_CachedActualSize.left + bz; break; case EAlign_Center: // Round to integer pixel values, else the fonts look awful m_TextPos.x = floorf(m_CachedActualSize.CenterPoint().x - m_GeneratedTexts[0]->m_Size.cx/2.f); break; case EAlign_Right: - m_TextPos.x = m_CachedActualSize.right - m_GeneratedTexts[0]->m_Size.cx; + m_TextPos.x = m_CachedActualSize.right - m_GeneratedTexts[0]->m_Size.cx - bz; break; default: + debug_warn("Broken EAlign in CButton::SetupText()"); break; } switch (valign) { case EVAlign_Top: - m_TextPos.y = m_CachedActualSize.top; + m_TextPos.y = m_CachedActualSize.top + bz; break; case EVAlign_Center: // Round to integer pixel values, else the fonts look awful m_TextPos.y = floorf(m_CachedActualSize.CenterPoint().y - m_GeneratedTexts[0]->m_Size.cy/2.f); break; case EVAlign_Bottom: - m_TextPos.y = m_CachedActualSize.bottom - m_GeneratedTexts[0]->m_Size.cy; + m_TextPos.y = m_CachedActualSize.bottom - m_GeneratedTexts[0]->m_Size.cy - bz; break; default: + debug_warn("Broken EVAlign in CButton::SetupText()"); break; } diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index 8d6eb36691..234829afd3 100755 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -20,6 +20,7 @@ gee@pyro.nu #include "CText.h" #include "CCheckBox.h" #include "CRadioButton.h" +#include "CInput.h" #include "CProgressBar.h" #include "MiniMap.h" @@ -49,9 +50,9 @@ JSClass GUIClass = { JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, }; - +// Globals used. extern int g_xres, g_yres; - +extern bool keys[SDLK_LAST]; //------------------------------------------------------------------- // called from main loop when (input) events are received. @@ -65,6 +66,8 @@ int gui_handler(const SDL_Event* ev) int CGUI::HandleEvent(const SDL_Event* ev) { + int ret = EV_PASS; + // MT: If something's gone wrong, check this block... (added for hotkey support) if( ev->type == SDL_GUIHOTKEYPRESS ) @@ -102,6 +105,7 @@ int CGUI::HandleEvent(const SDL_Event* ev) // Only one object can be hovered IGUIObject *pNearest = NULL; + // TODO Gee: (2004-09-08) Big TODO, don't do the below if the SDL_Event is something like a keypress! try { // TODO Gee: Optimizations needed! @@ -130,8 +134,20 @@ int CGUI::HandleEvent(const SDL_Event* ev) case SDL_BUTTON_LEFT: if (pNearest) { + if (pNearest != m_FocusedObject) + { + // Update focused object + if (m_FocusedObject) + m_FocusedObject->HandleMessage(SGUIMessage(GUIM_LOST_FOCUS)); + m_FocusedObject = pNearest; + m_FocusedObject->HandleMessage(SGUIMessage(GUIM_GOT_FOCUS)); + } + pNearest->HandleMessage(SGUIMessage(GUIM_MOUSE_PRESS_LEFT)); pNearest->ScriptEvent("mouseleftpress"); + + // Block event, so things on the map (behind the GUI) won't be pressed + LOG(ERROR, LOG_CATEGORY, "Left click blocked"); } break; @@ -155,6 +171,7 @@ int CGUI::HandleEvent(const SDL_Event* ev) break; } + ret = EV_HANDLED; } else if (ev->type == SDL_MOUSEBUTTONUP) @@ -165,6 +182,8 @@ int CGUI::HandleEvent(const SDL_Event* ev) { pNearest->HandleMessage(SGUIMessage(GUIM_MOUSE_RELEASE_LEFT)); pNearest->ScriptEvent("mouseleftrelease"); + + ret = EV_HANDLED; } } @@ -203,7 +222,19 @@ int CGUI::HandleEvent(const SDL_Event* ev) m_MouseButtons &= ~(1 << ev->button.button); } - return EV_PASS; + // Handle keys for input boxes + if (GetFocusedObject() && ev->type == SDL_KEYDOWN) + { + if( (ev->key.keysym.sym != SDLK_ESCAPE ) && + !keys[SDLK_LCTRL] && !keys[SDLK_RCTRL] && + !keys[SDLK_LALT] && !keys[SDLK_RALT]) + { + ret = GetFocusedObject()->ManuallyHandleEvent(ev); + } + // else will return EV_PASS because we never used the button. + } + + return ret; } void CGUI::TickObjects() @@ -216,7 +247,7 @@ void CGUI::TickObjects() //------------------------------------------------------------------- // Constructor / Destructor //------------------------------------------------------------------- -CGUI::CGUI() : m_InternalNameNumber(0), m_MouseButtons(0) +CGUI::CGUI() : m_InternalNameNumber(0), m_MouseButtons(0), m_FocusedObject(NULL) { m_BaseObject = new CGUIDummyObject; m_BaseObject->SetGUI(this); @@ -267,6 +298,7 @@ void CGUI::Initialize() AddObjectType("radiobutton", &CRadioButton::ConstructObject); AddObjectType("progressbar", &CProgressBar::ConstructObject); AddObjectType("minimap", &CMiniMap::ConstructObject); + AddObjectType("input", &CInput::ConstructObject); } void CGUI::Process() @@ -469,8 +501,10 @@ void CGUI::DrawSprite(const CStr& SpriteName, } else { + //glDisable(GL_TEXTURE_2D); + // TODO Gee: (2004-09-04) Shouldn't untextured sprites be able to be transparent too? - glColor3f(cit->m_BackColor.r, cit->m_BackColor.g, cit->m_BackColor.b); + glColor4f(cit->m_BackColor.r, cit->m_BackColor.g, cit->m_BackColor.b, cit->m_BackColor.a); CRect real = cit->m_Size.GetClientArea(Rect); @@ -940,7 +974,8 @@ void CGUI::DrawText(const SGUIText &Text, const CColor &DefaultColor, } - delete font; + if (font) + delete font; for (list::const_iterator it=Text.m_SpriteCalls.begin(); it!=Text.m_SpriteCalls.end(); @@ -999,6 +1034,7 @@ void CGUI::LoadXMLFile(const string &Filename) try { + if (root_name == "objects") { Xeromyces_ReadRootObjects(node, &XeroFile); diff --git a/source/gui/CGUI.h b/source/gui/CGUI.h index 7493a8c4e0..b28a4b37a5 100755 --- a/source/gui/CGUI.h +++ b/source/gui/CGUI.h @@ -274,6 +274,11 @@ private: */ IGUIObject *ConstructObject(const CStr& str); + /** + * Get Focused Object. + */ + IGUIObject *GetFocusedObject() { return m_FocusedObject; } + //-------------------------------------------------------- /** @name XML Reading Xeromyces specific subroutines * @@ -512,6 +517,13 @@ private: */ IGUIObject* m_BaseObject; + /** + * Focused object! + * Say an input box that is selected. That one is focused. + * There can only be one focused object. + */ + IGUIObject* m_FocusedObject; + /** * Just pointers for fast name access, each object * is really constructed within its parent for easy diff --git a/source/gui/CText.cpp b/source/gui/CText.cpp index 49a1edf119..36db86c7c6 100755 --- a/source/gui/CText.cpp +++ b/source/gui/CText.cpp @@ -119,6 +119,9 @@ void CText::HandleMessage(const SGUIMessage &Message) GUI::GetSetting(this, Message.value, scrollbar_style); GetScrollBar(0).SetScrollBarStyle( scrollbar_style ); + + // Update text + SetupText(); } break; diff --git a/source/gui/GUIbase.h b/source/gui/GUIbase.h index da1912dcff..67587d5ff3 100755 --- a/source/gui/GUIbase.h +++ b/source/gui/GUIbase.h @@ -57,8 +57,8 @@ public: \ */ enum EGUIMessageType { - GUIM_PREPROCESS, // questionable - GUIM_POSTPROCESS, // questionable + GUIM_PREPROCESS, // TODO questionable + GUIM_POSTPROCESS, // TODO questionable GUIM_MOUSE_OVER, GUIM_MOUSE_ENTER, GUIM_MOUSE_LEAVE, @@ -73,7 +73,9 @@ enum EGUIMessageType GUIM_SETTINGS_UPDATED, // SGUIMessage.m_Value = name of setting GUIM_PRESSED, GUIM_MOUSE_MOTION, - GUIM_LOAD // Called when an object is added to the GUI. + GUIM_LOAD, // Called when an object is added to the GUI. + GUIM_GOT_FOCUS, + GUIM_LOST_FOCUS }; /** diff --git a/source/gui/GUIutil.cpp b/source/gui/GUIutil.cpp index 92a7ddb1a9..5ad67cf7c6 100755 --- a/source/gui/GUIutil.cpp +++ b/source/gui/GUIutil.cpp @@ -201,6 +201,16 @@ bool __ParseString(const CStr& Value, CGUIString &Output) return true; } +template <> +bool __ParseString(const CStr& Value, CStrW &Output) +{ + // Translate the Value and retrieve the locilised string in + // Unicode. + + Output = translate((CStrW)Value); + return true; +} + //-------------------------------------------------------- // Help Classes/Structs for the GUI implementation //-------------------------------------------------------- @@ -387,6 +397,7 @@ TYPE(int) TYPE(float) TYPE(CClientArea) TYPE(CStr) +TYPE(CStrW) TYPE(CColor) TYPE(CGUIString) TYPE(EAlign) diff --git a/source/gui/GUIutil.h b/source/gui/GUIutil.h index b50bdbcaec..739af65a55 100755 --- a/source/gui/GUIutil.h +++ b/source/gui/GUIutil.h @@ -66,6 +66,9 @@ bool __ParseString(const CStr& Value, EVAlign &Output); template <> bool __ParseString(const CStr& Value, CGUIString &Output); +template <> +bool __ParseString(const CStr& Value, CStrW &Output); + // Icon, you create them in the XML file with root element // you use them in text owned by different objects... Such as CText. @@ -133,7 +136,7 @@ class IGUIObject; * Base class to only the class GUI. This superclass is * kind of a templateless extention of the class GUI. * Used for other functions to friend with, because it - * it can't friend with GUI since it's templated (at least + * can't friend with GUI since it's templated (at least * not on all compilers we're using). */ class CInternalCGUIAccessorBase diff --git a/source/gui/IGUIButtonBehavior.cpp b/source/gui/IGUIButtonBehavior.cpp index 58ef8642b4..40ce762973 100755 --- a/source/gui/IGUIButtonBehavior.cpp +++ b/source/gui/IGUIButtonBehavior.cpp @@ -53,12 +53,6 @@ void IGUIButtonBehavior::HandleMessage(const SGUIMessage &Message) } } break; - case GUIM_SETTINGS_UPDATED: - // If it's hidden, then it can't be pressed - //if (GetBaseSettings().m_Hidden) - // m_Pressed = false; - break; - default: break; } diff --git a/source/gui/IGUIObject.cpp b/source/gui/IGUIObject.cpp index 4c1ec7155b..a91298f43e 100755 --- a/source/gui/IGUIObject.cpp +++ b/source/gui/IGUIObject.cpp @@ -70,6 +70,7 @@ IGUIObject::~IGUIObject() TYPE(CClientArea); TYPE(CGUIString); TYPE(CStr); + TYPE(CStrW); TYPE(EAlign); TYPE(EVAlign); default: @@ -168,6 +169,7 @@ void IGUIObject::AddSetting(const EGUISettingType &Type, const CStr& Name) CASE_TYPE(float) CASE_TYPE(CClientArea) CASE_TYPE(CStr) + CASE_TYPE(CStrW) CASE_TYPE(CColor) CASE_TYPE(CGUIString) CASE_TYPE(EAlign) @@ -232,7 +234,7 @@ bool IGUIObject::SettingExists(const CStr& Setting) const return (m_Settings.count(Setting) >= 1); } -#define ADD_TYPE(type, type_name) \ +#define ADD_TYPE(type) \ else \ if (set.m_Type == GUIST_##type) \ { \ @@ -257,14 +259,15 @@ void IGUIObject::SetSetting(const CStr& Setting, const CStr& Value) { GUI::SetSetting(this, Setting, Value); } - ADD_TYPE(bool, "bool") - ADD_TYPE(float, "float") - ADD_TYPE(int, "int") - ADD_TYPE(CColor, "color") - ADD_TYPE(CClientArea, "client area") - ADD_TYPE(CGUIString, "text") - ADD_TYPE(EAlign, "align") - ADD_TYPE(EVAlign, "valign") + ADD_TYPE(CStrW) + ADD_TYPE(bool) + ADD_TYPE(float) + ADD_TYPE(int) + ADD_TYPE(CColor) + ADD_TYPE(CClientArea) + ADD_TYPE(CGUIString) + ADD_TYPE(EAlign) + ADD_TYPE(EVAlign) else { throw PS_FAIL; @@ -365,8 +368,9 @@ void IGUIObject::LoadStyle(const SGUIStyle &Style) catch (PS_RESULT e) { UNUSED(e); -// debug_warn("IGUIObject::LoadStyle failed"); // (this happens) - // TODO Gee: was ist das? + // The beauty with styles is that it can contain more settings + // than exists for the objects using it. So if the SetSetting + // fails, don't care. } } } @@ -462,7 +466,7 @@ void IGUIObject::ScriptEvent(const CStr& Action) mouseParams[1] = INT_TO_JSVAL(m_pGUI->m_MousePos.y); mouseParams[2] = INT_TO_JSVAL(m_pGUI->m_MouseButtons); JSObject* mouseObj = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_GUIMouse::JSI_class, NULL, m_pGUI->m_ScriptObject, 3, mouseParams); - assert(mouseObj); // need better error handling + assert(mouseObj); // TODO need better error handling // Don't garbage collect the mouse JS_AddRoot(g_ScriptingHost.getContext(), &mouseObj); @@ -494,4 +498,14 @@ CStr IGUIObject::GetPresentableName() const return CStr("[unnamed object]"); else return m_Name; +} + +void IGUIObject::SetFocus() +{ + GetGUI()->m_FocusedObject = this; +} + +bool IGUIObject::IsFocused() const +{ + return GetGUI()->m_FocusedObject == this; } \ No newline at end of file diff --git a/source/gui/IGUIObject.h b/source/gui/IGUIObject.h index 53d146c003..5c21087504 100755 --- a/source/gui/IGUIObject.h +++ b/source/gui/IGUIObject.h @@ -34,6 +34,7 @@ gee@pyro.nu #include "GUI.h" #include #include +#include "input.h" // just for EV_PASS #include "gui/scripting/JSInterface_IGUIObject.h" @@ -76,6 +77,7 @@ enum EGUISettingType GUIST_CClientArea, GUIST_CGUIString, GUIST_CStr, + GUIST_CStrW, GUIST_EAlign, GUIST_EVAlign }; @@ -325,6 +327,18 @@ protected: */ virtual void Draw()=0; + /** + * Some objects need to handle the SDL_Event manually. + * For instance the input box. + * + * Only the object with focus will have this function called. + * + * Returns either EV_PASS or EV_HANDLED. If EV_HANDLED, then + * the key won't be passed on and processed by other handlers. + * This is used for keys that the GUI uses. + */ + virtual int ManuallyHandleEvent(const SDL_Event* ev) { return EV_PASS; } + /** * Loads a style. * @@ -362,6 +376,16 @@ protected: m_MouseHovering = false; } + /** + * Take focus! + */ + void SetFocus(); + + /** + * Check if object is focused. + */ + bool IsFocused() const; + /** * NOTE! This will not just return m_pParent, when that is * need use it! There is one exception to it, when the parent is @@ -442,24 +466,19 @@ private: */ void UpdateMouseOver(IGUIObject * const &pMouseOver); - //@} - // Variables protected: - /// Name of object + // Name of object CStr m_Name; - /// Constructed on the heap, will be destroyed along with the the object + // Constructed on the heap, will be destroyed along with the the object // TODO Gee: really the above? vector_pObjects m_Children; - /// Pointer to parent + // Pointer to parent IGUIObject *m_pParent; - /// Base settings - //SGUIBaseSettings m_BaseSettings; - /** * This is an array of true or false, each element is associated with * a string representing a setting. Number of elements is equal to @@ -474,19 +493,9 @@ protected: // More variables - /// Is mouse hovering the object? used with the function MouseOver() + // Is mouse hovering the object? used with the function MouseOver() bool m_MouseHovering; - /** - * Tells us where a variable by a string name is - * located hardcoded, in order to acquire a pointer - * for that variable... Say "frozen" gives - * the offset from IGUIObject to m_Frozen. - * note! @uNOT from SGUIBaseSettings to - * m_Frozen! - */ - //static map_Settings ms_SettingsInfo; - /** * Settings pool, all an object's settings are located here * If a derived object has got more settings that the base @@ -499,7 +508,7 @@ protected: std::map m_Settings; private: - /// An object can't function stand alone + // An object can't function stand alone CGUI *m_pGUI; }; @@ -517,6 +526,8 @@ class CGUIDummyObject : public IGUIObject public: virtual void HandleMessage(const SGUIMessage& UNUSEDPARAM(Message)) {} virtual void Draw() {} + // Empty can never be hovered. It is only a category. + virtual bool MouseOver() { return false; } }; #endif diff --git a/source/gui/IGUITextOwner.cpp b/source/gui/IGUITextOwner.cpp index 9932a3a6b9..aa21f5a0af 100755 --- a/source/gui/IGUITextOwner.cpp +++ b/source/gui/IGUITextOwner.cpp @@ -40,6 +40,7 @@ void IGUITextOwner::HandleMessage(const SGUIMessage &Message) // it is assumed that the text of the object will be dependent on // these. Although that is not certain, but one will have to manually // change it and disregard this function. + // TODO Gee: (2004-09-07) Make sure this is all options that can affect the text. if (Message.value == CStr("size") || Message.value == CStr("z") || Message.value == CStr("absolute") || Message.value == CStr("caption") || Message.value == CStr("font") || Message.value == CStr("textcolor") ||