diff --git a/binaries/data/mods/official/gui/gui.dtd b/binaries/data/mods/official/gui/gui.dtd index aeadd42fd3..b02c48b573 100755 --- a/binaries/data/mods/official/gui/gui.dtd +++ b/binaries/data/mods/official/gui/gui.dtd @@ -134,6 +134,23 @@ cell-id CDATA #IMPLIED > + + + + diff --git a/source/gui/CButton.cpp b/source/gui/CButton.cpp index 7361a9e120..3f06a1b55d 100755 --- a/source/gui/CButton.cpp +++ b/source/gui/CButton.cpp @@ -31,6 +31,8 @@ CButton::CButton() AddSetting(GUIST_CColor, "textcolor-over"); AddSetting(GUIST_CColor, "textcolor-pressed"); AddSetting(GUIST_CColor, "textcolor-disabled"); + AddSetting(GUIST_CStr, "tooltip"); + AddSetting(GUIST_CStr, "tooltip-style"); // Add text AddText(new SGUIText()); diff --git a/source/gui/CCheckBox.cpp b/source/gui/CCheckBox.cpp index 126aabcc69..3b2f3e818a 100755 --- a/source/gui/CCheckBox.cpp +++ b/source/gui/CCheckBox.cpp @@ -35,17 +35,19 @@ CCheckBox::CCheckBox() CStr m_ToolTip; CStr m_ToolTipStyle; */ - AddSetting(GUIST_CGUIString, "caption"); - AddSetting(GUIST_bool, "checked"); - AddSetting(GUIST_CGUISpriteInstance,"sprite"); - AddSetting(GUIST_CGUISpriteInstance,"sprite-over"); - AddSetting(GUIST_CGUISpriteInstance,"sprite-pressed"); - AddSetting(GUIST_CGUISpriteInstance,"sprite-disabled"); - AddSetting(GUIST_CGUISpriteInstance,"sprite2"); - AddSetting(GUIST_CGUISpriteInstance,"sprite2-over"); - AddSetting(GUIST_CGUISpriteInstance,"sprite2-pressed"); - AddSetting(GUIST_CGUISpriteInstance,"sprite2-disabled"); - AddSetting(GUIST_int, "square-side"); + AddSetting(GUIST_CGUIString, "caption"); + AddSetting(GUIST_bool, "checked"); + AddSetting(GUIST_CGUISpriteInstance, "sprite"); + AddSetting(GUIST_CGUISpriteInstance, "sprite-over"); + AddSetting(GUIST_CGUISpriteInstance, "sprite-pressed"); + AddSetting(GUIST_CGUISpriteInstance, "sprite-disabled"); + AddSetting(GUIST_CGUISpriteInstance, "sprite2"); + AddSetting(GUIST_CGUISpriteInstance, "sprite2-over"); + AddSetting(GUIST_CGUISpriteInstance, "sprite2-pressed"); + AddSetting(GUIST_CGUISpriteInstance, "sprite2-disabled"); + AddSetting(GUIST_int, "square-side"); + AddSetting(GUIST_CStr, "tooltip"); + AddSetting(GUIST_CStr, "tooltip-style"); // Add text AddText(new SGUIText()); diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index 83148a5670..ec32ab13c3 100755 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -22,6 +22,7 @@ gee@pyro.nu #include "CRadioButton.h" #include "CInput.h" #include "CProgressBar.h" +#include "CTooltip.h" #include "MiniMap.h" #include "ps/Xeromyces.h" @@ -183,8 +184,9 @@ int CGUI::HandleEvent(const SDL_Event* ev) else if (ev->type == SDL_MOUSEBUTTONUP) { - if (ev->button.button == SDL_BUTTON_LEFT) + switch (ev->button.button) { + case SDL_BUTTON_LEFT: if (pNearest) { pNearest->HandleMessage(SGUIMessage(GUIM_MOUSE_RELEASE_LEFT)); @@ -192,6 +194,7 @@ int CGUI::HandleEvent(const SDL_Event* ev) ret = EV_HANDLED; } + break; } // Reset all states on all visible objects @@ -249,6 +252,16 @@ void CGUI::TickObjects() CStr action = "tick"; GUI::RecurseObject(0, m_BaseObject, &IGUIObject::ScriptEvent, action); + + // Also update tooltips: + + // TODO: Efficiency + IGUIObject* pNearest = NULL; + GUI::RecurseObject(GUIRR_HIDDEN | GUIRR_GHOST, m_BaseObject, + &IGUIObject::ChooseMouseOverAndClosest, + pNearest); + + m_Tooltip.Update(pNearest, m_MousePos, this); } //------------------------------------------------------------------- @@ -667,8 +680,8 @@ SGUIText CGUI::GenerateText(const CGUIString &string, // this won't be exact because we're assuming the line_height // will be as our preliminary calculation said. But that may change, // although we'd have to add a couple of more loops to try straightening - // this problem out, and it is very unlikely to happen noticably if one - // stuctures his text in a stylistically pure fashion. Even if not, it + // this problem out, and it is very unlikely to happen noticeably if one + // structures his text in a stylistically pure fashion. Even if not, it // is still quite unlikely it will happen. // Loop through left and right side, from and to. for (int j=0; j<2; ++j) @@ -832,7 +845,7 @@ void CGUI::DrawText(SGUIText &Text, const CColor &DefaultColor, const CPos &pos, const float &z) { // TODO Gee: All these really necessary? Some - // are deafults and if you changed them + // are defaults and if you changed them // the opposite value at the end of the functions, // some things won't be drawn correctly. glEnable(GL_TEXTURE_2D); @@ -1054,7 +1067,15 @@ void CGUI::Xeromyces_ReadRootSetup(XMBElement Element, CXeromyces* pFile) { Xeromyces_ReadIcon(child, pFile); } - // No need for else, we're using DTD. + else + if (name == "tooltip") + { + Xeromyces_ReadTooltip(child, pFile); + } + else + { + debug_warn("Invalid data - DTD shouldn't allow this"); + } } } @@ -1105,8 +1126,8 @@ void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObjec // CStr argStyle (attributes.getNamedItem(attr_style)); - if (m_Styles.count(CStr("default")) == 1) - object->LoadStyle(*this, CStr("default")); + if (m_Styles.count("default") == 1) + object->LoadStyle(*this, "default"); if (argStyle.Length()) { @@ -1134,7 +1155,7 @@ void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObjec XMBAttribute attr = attributes.item(i); // If value is "null", then it is equivalent as never being entered - if ((CStr)attr.Value == (CStr)"null") + if ((CStr)attr.Value == "null") continue; // Ignore "type" and "style", we've already checked it @@ -1156,47 +1177,6 @@ void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObjec if (attr.Name == attr_z) ManuallySetZ = true; - -/* TODO: Reimplement this inside GUIRenderer.cpp - - // Generate "stretched:filename" sprites. - // - // Check whether it's actually one of the many sprite... parameters. - if (pFile->getAttributeString(attr.Name).substr(0, 6) == "sprite") - { - // Check whether it's a special stretched one - CStr SpriteName (attr.Value); - if (SpriteName.substr(0, 10) == "stretched:" && - m_Sprites.find(SpriteName) == m_Sprites.end() ) - { - - CStr TexFilename ("art/textures/ui/"); - TexFilename += SpriteName.substr(10); - - Handle tex = tex_load(TexFilename); - if (tex <= 0) - { - LOG(ERROR, LOG_CATEGORY, "Error opening texture '%s': %lld", TexFilename.c_str(), tex); - } - else - { - CGUISprite sprite; - SGUIImage image; - - CStr DefaultSize ("0 0 100% 100%"); - image.m_TextureSize = CClientArea(DefaultSize); - image.m_Size = CClientArea(DefaultSize); - - image.m_TextureName = TexFilename; - image.m_Texture = tex; - tex_upload(tex); - - sprite.AddImage(image); - m_Sprites[SpriteName] = sprite; - } - } - } -*/ // Try setting the value if (object->SetSetting(pFile->getAttributeString(attr.Name), (CStr)attr.Value) != PS_OK) { @@ -1214,8 +1194,8 @@ void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObjec } // Attempt to register the hotkey tag, if one was provided - if( hotkeyTag.Length() ) - hotkeyRegisterGUIObject( object->GetName(), hotkeyTag ); + if (hotkeyTag.Length()) + hotkeyRegisterGUIObject(object->GetName(), hotkeyTag); CStrW caption (Element.getText()); if (caption.Length()) @@ -1376,6 +1356,9 @@ void CGUI::Xeromyces_ReadSprite(XMBElement Element, CXeromyces* pFile) // Get name, we know it exists because of DTD requirements name = Element.getAttributes().getNamedItem( pFile->getAttributeID("name") ); + if (m_Sprites.find(name) != m_Sprites.end()) + LOG(WARNING, LOG_CATEGORY, "Sprite name '%s' used more than once; first definition will be discarded", (const char*)name); + // // Read Children (the images) // @@ -1404,7 +1387,7 @@ void CGUI::Xeromyces_ReadSprite(XMBElement Element, CXeromyces* pFile) } else { - debug_warn("Oops"); // DTD shouldn't allow this + debug_warn("Invalid data - DTD shouldn't allow this"); } } @@ -1521,7 +1504,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite } else { - debug_warn("Oops"); // DTD shouldn't allow this + debug_warn("Invalid data - DTD shouldn't allow this"); } } @@ -1539,7 +1522,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite } else { - debug_warn("Oops"); // DTD shouldn't allow this + debug_warn("Invalid data - DTD shouldn't allow this"); } } @@ -1581,7 +1564,7 @@ void CGUI::Xeromyces_ReadEffects(XMBElement Element, CXeromyces* pFile, SGUIImag BOOL("grayscale", Greyscale) { - debug_warn("Oops"); // DTD shouldn't allow this + debug_warn("Invalid data - DTD shouldn't allow this"); } } } @@ -1746,9 +1729,36 @@ void CGUI::Xeromyces_ReadIcon(XMBElement Element, CXeromyces* pFile) } else { - debug_warn("Oops"); // DTD shouldn't allow this + debug_warn("Invalid data - DTD shouldn't allow this"); } } m_Icons[name] = icon; } + +void CGUI::Xeromyces_ReadTooltip(XMBElement Element, CXeromyces* pFile) +{ + IGUIObject* object = new CTooltip; + + object->SetName(CStr("__internal(") + CStr(m_InternalNameNumber) + CStr(")")); + ++m_InternalNameNumber; + + XMBAttributeList attributes = Element.getAttributes(); + for (int i=0; igetAttributeString(attr.Name)); + CStr attr_value (attr.Value); + + if (attr_name == "name") + { + object->SetName(attr_value); + } + else + { + object->SetSetting(attr_name, attr_value); + } + } + + AddObject(object); +} diff --git a/source/gui/CGUI.h b/source/gui/CGUI.h index 44741c83bf..12129b5250 100755 --- a/source/gui/CGUI.h +++ b/source/gui/CGUI.h @@ -25,6 +25,7 @@ ERROR_TYPE(GUI, JSOpenFailed); //-------------------------------------------------------- #include "GUI.h" +#include "GUITooltip.h" #include "Singleton.h" #include "input.h" // JW: grr, classes suck in this case :P @@ -476,6 +477,8 @@ private: */ void Xeromyces_ReadIcon(XMBElement Element, CXeromyces* pFile); + void Xeromyces_ReadTooltip(XMBElement Element, CXeromyces* pFile); + //@} private: @@ -511,6 +514,8 @@ private: // TODO Gee: Used? int16_t m_Errors; + GUITooltip m_Tooltip; + //@} //-------------------------------------------------------- /** @name Objects */ diff --git a/source/gui/CImage.cpp b/source/gui/CImage.cpp index d086ca280e..d9ffecf2e1 100755 --- a/source/gui/CImage.cpp +++ b/source/gui/CImage.cpp @@ -19,6 +19,8 @@ CImage::CImage() { AddSetting(GUIST_CGUISpriteInstance, "sprite"); AddSetting(GUIST_int, "cell-id"); + AddSetting(GUIST_CStr, "tooltip"); + AddSetting(GUIST_CStr, "tooltip-style"); } CImage::~CImage() diff --git a/source/gui/CInput.cpp b/source/gui/CInput.cpp index b9d4074107..93df806e5e 100755 --- a/source/gui/CInput.cpp +++ b/source/gui/CInput.cpp @@ -33,6 +33,8 @@ CInput::CInput() : m_iBufferPos(0) AddSetting(GUIST_CGUISpriteInstance, "sprite"); AddSetting(GUIST_int, "cell-id"); AddSetting(GUIST_CColor, "textcolor"); + AddSetting(GUIST_CStr, "tooltip"); + AddSetting(GUIST_CStr, "tooltip-style"); // TODO Gee: (2004-08-14) // Add a setting for buffer zone //AddSetting(GUIST_int, " diff --git a/source/gui/CProgressBar.cpp b/source/gui/CProgressBar.cpp index 34c4457e0c..1fc487e932 100755 --- a/source/gui/CProgressBar.cpp +++ b/source/gui/CProgressBar.cpp @@ -20,6 +20,8 @@ CProgressBar::CProgressBar() AddSetting(GUIST_CGUISpriteInstance, "sprite-background"); AddSetting(GUIST_CGUISpriteInstance, "sprite-bar"); AddSetting(GUIST_float, "caption"); // aka value from 0 to 100 + AddSetting(GUIST_CStr, "tooltip"); + AddSetting(GUIST_CStr, "tooltip-style"); } CProgressBar::~CProgressBar() diff --git a/source/gui/CText.cpp b/source/gui/CText.cpp index 53e660b76f..fd19ced348 100755 --- a/source/gui/CText.cpp +++ b/source/gui/CText.cpp @@ -28,6 +28,8 @@ CText::CText() AddSetting(GUIST_CGUISpriteInstance, "sprite"); AddSetting(GUIST_int, "cell-id"); AddSetting(GUIST_CColor, "textcolor"); + AddSetting(GUIST_CStr, "tooltip"); + AddSetting(GUIST_CStr, "tooltip-style"); // TODO Gee: (2004-08-14) // Add a setting for buffer zone //AddSetting(GUIST_int, " @@ -56,8 +58,6 @@ void CText::SetupText() assert(m_GeneratedTexts.size()>=1); - CColor color; - CStr font; if (GUI::GetSetting(this, "font", font) != PS_OK || font.Length()==0) // Use the default if none is specified @@ -66,7 +66,6 @@ void CText::SetupText() CGUIString caption; bool scrollbar; - GUI::GetSetting(this, "textcolor", color); GUI::GetSetting(this, "caption", caption); GUI::GetSetting(this, "scrollbar", scrollbar); diff --git a/source/gui/CTooltip.cpp b/source/gui/CTooltip.cpp new file mode 100644 index 0000000000..54ba8530e1 --- /dev/null +++ b/source/gui/CTooltip.cpp @@ -0,0 +1,140 @@ +#include "precompiled.h" + +#include "CTooltip.h" +#include "CGUI.h" + +CTooltip::CTooltip() +{ + AddSetting(GUIST_float, "buffer-zone"); + AddSetting(GUIST_CGUIString, "caption"); + AddSetting(GUIST_CStr, "font"); + AddSetting(GUIST_CGUISpriteInstance, "sprite"); + AddSetting(GUIST_float, "time"); + AddSetting(GUIST_CColor, "textcolor"); + AddSetting(GUIST_int, "maxwidth"); + AddSetting(GUIST_CPos, "pos"); + AddSetting(GUIST_EVAlign, "anchor"); + + AddSetting(GUIST_CPos, "_mousepos"); + + GUI::SetSetting(this, "time", 0.5f); + GUI::SetSetting(this, "anchor", EVAlign_Bottom); + + // Set up a blank piece of text, to be replaced with a more + // interesting message later + AddText(new SGUIText()); +} + +CTooltip::~CTooltip() +{ +} + +void CTooltip::SetupText() +{ + if (!GetGUI()) + return; + + assert(m_GeneratedTexts.size()==1); + + CStr font; + if (GUI::GetSetting(this, "font", font) != PS_OK || font.Length()==0) + font = "default"; + + float buffer_zone=0.f; + GUI::GetSetting(this, "buffer-zone", buffer_zone); + + CGUIString caption; + GUI::GetSetting(this, "caption", caption); + + float max_width = 500.f; // TODO: max-width setting + + *m_GeneratedTexts[0] = GetGUI()->GenerateText(caption, font, max_width, buffer_zone, this); + + CPos mousepos, pos; + EVAlign anchor; + GUI::GetSetting(this, "_mousepos", mousepos); + GUI::GetSetting(this, "pos", pos); + GUI::GetSetting(this, "anchor", anchor); + + // Position the tooltip relative to the mouse + + CClientArea size; + size.pixel.left = mousepos.x + pos.x; + size.pixel.right = size.pixel.left + m_GeneratedTexts[0]->m_Size.cx; + switch (anchor) + { + case EVAlign_Top: + size.pixel.top = mousepos.y + pos.y; + size.pixel.bottom = size.pixel.top + m_GeneratedTexts[0]->m_Size.cy; + break; + case EVAlign_Bottom: + size.pixel.bottom = mousepos.y + pos.y; + size.pixel.top = size.pixel.bottom - m_GeneratedTexts[0]->m_Size.cy; + break; + case EVAlign_Center: + size.pixel.top = mousepos.y + pos.y - m_GeneratedTexts[0]->m_Size.cy/2.f; + size.pixel.bottom = size.pixel.top + m_GeneratedTexts[0]->m_Size.cy; + break; + default: + debug_warn("Invalid EVAlign!"); + } + + // Adjust it if it's falling off the screen + + extern int g_xres, g_yres; + float screenw = (float)g_xres, screenh = (float)g_yres; + + if (size.pixel.top < 0.f) + size.pixel.bottom -= size.pixel.top, size.pixel.top = 0.f; + else if (size.pixel.bottom > screenh) + size.pixel.top -= (size.pixel.bottom-screenh), size.pixel.bottom = screenh; + else if (size.pixel.left < 0.f) + size.pixel.right -= size.pixel.left, size.pixel.left = 0.f; + else if (size.pixel.right > screenw) + size.pixel.left -= (size.pixel.right-screenw), size.pixel.right = screenw; + + GUI::SetSetting(this, "size", size); + UpdateCachedSize(); +} + +void CTooltip::HandleMessage(const SGUIMessage &Message) +{ + switch (Message.type) + { + case GUIM_SETTINGS_UPDATED: + // Don't update the text when the size changes, because the size is + // changed whenever the text is updated ( => infinite recursion) + if (/*Message.value == "size" ||*/ Message.value == "caption" || + Message.value == "font" || Message.value == "buffer-zone") + { + SetupText(); + } + break; + + case GUIM_LOAD: + SetupText(); + break; + + default: + break; + } +} + +void CTooltip::Draw() +{ + float z = 900.f; // TODO: Find a nicer way of putting the tooltip on top of everything else + + if (GetGUI()) + { + CGUISpriteInstance *sprite; + GUI::GetSettingPointer(this, "sprite", sprite); + + GetGUI()->DrawSprite(*sprite, 0, z, m_CachedActualSize); + + CColor color; + GUI::GetSetting(this, "textcolor", color); + + // Draw text + IGUITextOwner::Draw(0, color, m_CachedActualSize.TopLeft(), z+0.1f); + } +} diff --git a/source/gui/CTooltip.h b/source/gui/CTooltip.h new file mode 100644 index 0000000000..d24cecda8f --- /dev/null +++ b/source/gui/CTooltip.h @@ -0,0 +1,31 @@ +/* +GUI Object - Tooltip + +--Overview-- + +Mostly like CText, but intended for dynamic tooltips + +*/ + +#ifndef CTooltip_H +#define CTooltip_H + +#include "IGUITextOwner.h" + +class CTooltip : public IGUITextOwner +{ + GUI_OBJECT(CTooltip) + +public: + CTooltip(); + virtual ~CTooltip(); + +protected: + void SetupText(); + + virtual void HandleMessage(const SGUIMessage &Message); + + virtual void Draw(); +}; + +#endif diff --git a/source/gui/GUITooltip.cpp b/source/gui/GUITooltip.cpp new file mode 100644 index 0000000000..6995448246 --- /dev/null +++ b/source/gui/GUITooltip.cpp @@ -0,0 +1,209 @@ +#include "precompiled.h" + +#include "GUITooltip.h" +#include "lib/timer.h" +#include "IGUIObject.h" +#include "CGUI.h" + +#include "ps/CLogger.h" + +/* + Tooltips: + When holding the mouse stationary over an object for some amount of time, + the tooltip is displayed. If the mouse moves off that object, the tooltip + disappears. If the mouse re-enters an object within a short time, the new + tooltip is displayed immediately. (This lets you run the mouse across a + series of buttons, without waiting ages for the text to pop up every time.) + + See Visual Studio's toolbar buttons for an example. + + + Implemented as a state machine: + + (where "*" lines are checked constantly, and "<" lines are handled + on entry to that state) + + IN MOTION + * If the mouse stops, check whether it should have a tooltip and move to + 'STATIONARY, NO TOOLTIP' or 'STATIONARY, TOOLIP' + + STATIONARY, NO TOOLTIP + * If the mouse moves, switch to 'IN MOTION' + + STATIONARY, TOOLTIP + < Set target time = now + tooltip time + * If the mouse moves, switch to 'IN MOTION' + * If now > target time, switch to 'SHOWING' + + SHOWING + < Start displaying the tooltip + * If the mouse leaves the object, check whether it has a tooltip + and switch to 'SHOWING' or 'COOLING' + + COOLING (since I can't think of a better name) + < Stop displaying the tooltip + < Set target time = now + cooldown time + * If the mouse has moved and is over a tooltipped object, switch to 'SHOWING' + * If now > target time, switch to 'STATIONARY, NO TOOLTIP' +*/ + +enum +{ + ST_IN_MOTION, + ST_STATIONARY_NO_TOOLTIP, + ST_STATIONARY_TOOLTIP, + ST_SHOWING, + ST_COOLING +}; + +GUITooltip::GUITooltip() +: m_State(ST_IN_MOTION), m_PreviousObject(NULL), m_PreviousTooltipName(NULL) +{ +} + +const double CooldownTime = 0.25; // TODO: Don't hard-code this value + +static bool GetTooltip(IGUIObject* obj, CStr* &style) +{ + if (obj && obj->SettingExists("tooltip-style")) + { + // Use GetSettingPointer to avoid unnecessary string-copying. + // (The tooltip code is only run once per frame, but efficiency + // would be nice anyway.) + if (GUI::GetSettingPointer(obj, "tooltip-style", style) == PS_OK + && style->Length()) + + return true; + } + return false; +} + +// Urgh - this is only a method because it needs to access HandleMessage (which +// is 'protected'), so it needs to be friendable (and so not a static function) +void GUITooltip::ShowTooltip(IGUIObject* obj, CPos pos, CStr& style, CGUI* gui) +{ + IGUIObject* tooltipobj = gui->FindObjectByName(style); + if (! tooltipobj) + { + LOG_ONCE(ERROR, "gui", "Cannot find tooltip object named '%s'", (const char*)style); + return; + } + GUI::SetSetting(tooltipobj, "hidden", false); + + assert(obj); + + // These shouldn't fail: + + CStr text; + if (GUI::GetSetting(obj, "tooltip", text) != PS_OK) + debug_warn("Failed to retrieve tooltip text"); + + if (tooltipobj->SetSetting("caption", text) != PS_OK) + debug_warn("Failed to set tooltip caption"); + + if (GUI::SetSetting(tooltipobj, "_mousepos", pos) != PS_OK) + debug_warn("Failed to set tooltip mouse position"); + + tooltipobj->HandleMessage(SGUIMessage(GUIM_SETTINGS_UPDATED, "caption")); +} + +static void HideTooltip(CStr& style, CGUI* gui) +{ + IGUIObject* tooltipobj = gui->FindObjectByName(style); + if (! tooltipobj) + { + LOG_ONCE(ERROR, "gui", "Cannot find tooltip object named '%s'", (const char*)style); + return; + } + GUI::SetSetting(tooltipobj, "hidden", true); +} + +void GUITooltip::Update(IGUIObject* Nearest, CPos MousePos, CGUI* GUI) +{ + double now = get_time(); + + CStr* style = NULL; + + int nextstate = -1; + + switch (m_State) + { + case ST_IN_MOTION: + if (MousePos == m_PreviousMousePos) + { + if (GetTooltip(Nearest, style)) + nextstate = ST_STATIONARY_TOOLTIP; + else + nextstate = ST_STATIONARY_NO_TOOLTIP; + } + break; + + case ST_STATIONARY_NO_TOOLTIP: + if (MousePos != m_PreviousMousePos) + nextstate = ST_IN_MOTION; + break; + + case ST_STATIONARY_TOOLTIP: + if (MousePos != m_PreviousMousePos) + nextstate = ST_IN_MOTION; + else if (now >= m_Time) + { + // Make sure the tooltip still exists + if (GetTooltip(Nearest, style)) + nextstate = ST_SHOWING; + else + { + // Failed to retrieve style - the object has probably been + // altered, so just restart the process + nextstate = ST_IN_MOTION; + } + } + break; + + case ST_SHOWING: + if (Nearest != m_PreviousObject) + { + if (GetTooltip(Nearest, style)) + nextstate = ST_SHOWING; + else + nextstate = ST_COOLING; + } + break; + + case ST_COOLING: + if (now >= m_Time) + nextstate = ST_IN_MOTION; + else if (Nearest != m_PreviousObject && GetTooltip(Nearest, style)) + nextstate = ST_SHOWING; + break; + } + + if (nextstate != -1) + { + switch (nextstate) + { + case ST_STATIONARY_TOOLTIP: + m_Time = now + 0.5/* TODO: tooltip time */; + break; + + case ST_SHOWING: + // show tooltip + ShowTooltip(Nearest, MousePos, *style, GUI); + m_PreviousTooltipName = *style; + break; + + case ST_COOLING: + // hide the tooltip + HideTooltip(m_PreviousTooltipName, GUI); + m_Time = now + CooldownTime; + break; + } + + m_State = nextstate; + } + + + m_PreviousMousePos = MousePos; + m_PreviousObject = Nearest; + +} \ No newline at end of file diff --git a/source/gui/GUITooltip.h b/source/gui/GUITooltip.h new file mode 100644 index 0000000000..07d8c20533 --- /dev/null +++ b/source/gui/GUITooltip.h @@ -0,0 +1,27 @@ +#ifndef GUITooltip_H +#define GUITooltip_H + +class IGUIObject; +class CGUI; +class CStr; + +#include "Overlay.h" + +class GUITooltip +{ +public: + GUITooltip(); + void Update(IGUIObject* Nearest, CPos MousePos, CGUI* GUI); + +private: + void ShowTooltip(IGUIObject* obj, CPos pos, CStr& style, CGUI* gui); + + int m_State; + + IGUIObject* m_PreviousObject; + CStr m_PreviousTooltipName; + CPos m_PreviousMousePos; + double m_Time; +}; + +#endif // GUITooltip_H diff --git a/source/gui/GUItext.cpp b/source/gui/GUItext.cpp index 5f9bfa1cc1..bd37c49809 100755 --- a/source/gui/GUItext.cpp +++ b/source/gui/GUItext.cpp @@ -299,6 +299,8 @@ void CGUIString::SetValue(const CStrW& str) // Setup parser // TODO Gee: (2004-08-16) Create and store this parser object somewhere to save loading time. + // TODO PT: Extended CParserCache so that the above is possible (since it currently only + // likes one-task parsers) CParser Parser; // I've added the option of an additional parameter. Only used for icons when writing this. Parser.InputTaskType("start", "$ident[_=_$value_[$ident_=_$value_]]"); diff --git a/source/gui/GUItext.h b/source/gui/GUItext.h index f7b63d4e45..aab1b253ef 100755 --- a/source/gui/GUItext.h +++ b/source/gui/GUItext.h @@ -132,7 +132,7 @@ struct SGUIText * List of sprites, or "icons" that should be rendered * along with the text. */ - std::list m_SpriteCalls; // list for consistant mem addresses + std::list m_SpriteCalls; // list for consistent mem addresses // so that we can point to elements. /** @@ -145,7 +145,7 @@ struct SGUIText /** * @author Gustav Larsson * - * String class, substitue for CStr, but that parses + * String class, substitute for CStr, but that parses * the tags and builds up a list of all text that will * be different when outputted. * @@ -287,7 +287,7 @@ public: * @param Feedback contains all info that is generated. * @param DefaultFont Default Font * @param from From character n, - * @param to to chacter n. + * @param to to character n. * @param FirstLine Whether this is the first line of text, to calculate its height correctly * * pObject Only for Error outputting, optional! If NULL diff --git a/source/gui/GUItypes.h b/source/gui/GUItypes.h index 1d63ade1d7..61e576de54 100644 --- a/source/gui/GUItypes.h +++ b/source/gui/GUItypes.h @@ -1,14 +1,68 @@ -// This file is used by all bits of GUI code that need to repeat some code -// for a variety of types (to avoid duplicating the list of types). Just do -// #define TYPE(T) your_code_involving_T; -// #include "GUItypes.h" -// #undef TYPE -// -// If you want to exclude a particular type, define e.g. GUITYPE_IGNORE_CStr +#if 0 +=pod /* (These C++ comments in Perl code are to please my syntax highlighter) -// File generated by: -// perl -e"print qq{#ifndef GUITYPE_IGNORE_$_\nTYPE($_)\n#endif\n} for qw(bool int float CColor CClientArea CGUIString CGUISpriteInstance CStr CStrW EAlign EVAlign)" + +This file is used by all bits of GUI code that need to repeat some code +for a variety of types (to avoid repeating the list of types in half a dozen +places, and to make it much easier to add a new type). Just do + #define TYPE(T) your_code_involving_T; + #include "GUItypes.h" + #undef TYPE +to handle every possible type. +If you want to exclude a particular type, define e.g. GUITYPE_IGNORE_CStr + +To alter this file, adjust the types in the indented list below, then run +"perl GUITypes.h" to regenerate it. (Or if you want to do it manually, make +sure you update the four mentions of each typename in this file.) + + +=cut */ + +my @types = qw( + + + bool + int + float + CColor + CClientArea + CGUIString + CGUISpriteInstance + CStr + CStrW + EAlign + EVAlign + CPos + + +); + +#// Extract everything from this file, above the /********/ line +open IN, $0 or die "Error opening $0: $!"; +my $out = ''; +while () +{ + last if $_ eq "/********/\n"; + $out .= $_; +} +$out .= "/********/\n"; +$out .= "#ifndef GUITYPE_IGNORE_$_\nTYPE($_)\n#endif\n" for @types; + +#// and some minor hacks to make autocompleting things happier: +$out .= "#ifdef PLEASE_DO_NOT_DEFINE_THIS\n// See IGUIObject.h for 'enum EGUISettingType'\nenum {" . (join ',', map "GUIST_$_", @types) . "};\n#endif"; + +#// Overwrite the current program with the newly-generated contents +close IN; +open OUT, ">$0" or die "Error opening >$0: $!"; #// TODO: Find whether it's safe for a program to overwrite itself. (It seems to work, at least on Windows) +print OUT $out; +close OUT; + +__END__ +#endif + + +/********/ #ifndef GUITYPE_IGNORE_bool TYPE(bool) #endif @@ -42,3 +96,10 @@ TYPE(EAlign) #ifndef GUITYPE_IGNORE_EVAlign TYPE(EVAlign) #endif +#ifndef GUITYPE_IGNORE_CPos +TYPE(CPos) +#endif +#ifdef PLEASE_DO_NOT_DEFINE_THIS +// See IGUIObject.h for 'enum EGUISettingType' +enum {GUIST_bool,GUIST_int,GUIST_float,GUIST_CColor,GUIST_CClientArea,GUIST_CGUIString,GUIST_CGUISpriteInstance,GUIST_CStr,GUIST_CStrW,GUIST_EAlign,GUIST_EVAlign,GUIST_CPos}; +#endif \ No newline at end of file diff --git a/source/gui/GUIutil.cpp b/source/gui/GUIutil.cpp index 0273173488..efd29f4d01 100755 --- a/source/gui/GUIutil.cpp +++ b/source/gui/GUIutil.cpp @@ -147,6 +147,19 @@ bool __ParseString(const CStr& Value, CSize &Output) return true; } +template <> +bool __ParseString(const CStr& Value, CPos &Output) +{ + CSize temp; + if (__ParseString(Value, temp)) + { + Output = CPos(temp); + return true; + } + else + return false; +} + template <> bool __ParseString(const CStr &Value, EAlign &Output) { diff --git a/source/gui/IGUIObject.h b/source/gui/IGUIObject.h index 39ecf19384..c0be5e4fcb 100755 --- a/source/gui/IGUIObject.h +++ b/source/gui/IGUIObject.h @@ -31,7 +31,8 @@ gee@pyro.nu //-------------------------------------------------------- // Includes / Compiler directives //-------------------------------------------------------- -#include "GUI.h" +#include "GUIbase.h" +#include "GUItext.h" #include #include #include "input.h" // just for EV_PASS @@ -70,20 +71,12 @@ struct JSObject; * For use of later macros, all names should be GUIST_ followed * by the code name (case sensitive!). */ +#define TYPE(T) GUIST_##T, enum EGUISettingType { - GUIST_bool, - GUIST_int, - GUIST_float, - GUIST_CColor, - GUIST_CClientArea, - GUIST_CGUIString, - GUIST_CStr, - GUIST_CStrW, - GUIST_CGUISpriteInstance, - GUIST_EAlign, - GUIST_EVAlign + #include "GUItypes.h" }; +#undef TYPE /** * @author Gustav Larsson @@ -135,6 +128,7 @@ class IGUIObject friend class CGUI; friend class CInternalCGUIAccessorBase; friend class IGUIScrollBar; + friend class GUITooltip; // Allow getProperty to access things like GetParent() friend JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp); @@ -502,7 +496,7 @@ protected: /** * Settings pool, all an object's settings are located here * If a derived object has got more settings that the base - * settings, it's becasue they have a new version of the + * settings, it's because they have a new version of the * function SetupSettings(). * * @see SetupSettings() diff --git a/source/gui/IGUITextOwner.cpp b/source/gui/IGUITextOwner.cpp index aa21f5a0af..8a65aa0766 100755 --- a/source/gui/IGUITextOwner.cpp +++ b/source/gui/IGUITextOwner.cpp @@ -41,10 +41,12 @@ void IGUITextOwner::HandleMessage(const SGUIMessage &Message) // 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") || - Message.value == CStr("buffer-zone")) + // Also TODO: If several things are changing (e.g. when loading the file), + // only call SetupText once (probably just before it's drawn) + if (Message.value == "size" || Message.value == "z" || + Message.value == "absolute" || Message.value == "caption" || + Message.value == "font" || Message.value == "textcolor" || + Message.value == "buffer-zone") { SetupText(); } diff --git a/source/gui/MiniMap.cpp b/source/gui/MiniMap.cpp index 9402c35052..5eac76abc2 100755 --- a/source/gui/MiniMap.cpp +++ b/source/gui/MiniMap.cpp @@ -31,7 +31,9 @@ CMiniMap::CMiniMap() : m_Handle(0), m_Data(NULL), m_MapSize(0), m_Terrain(0), m_UnitManager(0) { - AddSetting(GUIST_CColor, "fov-wedge-color"); + AddSetting(GUIST_CColor, "fov-wedge-color"); + AddSetting(GUIST_CStr, "tooltip"); + AddSetting(GUIST_CStr, "tooltip-style"); } CMiniMap::~CMiniMap() @@ -189,12 +191,12 @@ void CMiniMap::Destroy() /* * Calefaction * TODO: Speed this up. There has to be some mathematical way to make - * this more effecient. This works for now. + * this more efficient. This works for now. */ CVector2D CMiniMap::GetMapSpaceCoords(CVector3D worldPos) { u32 x = (u32)(worldPos.X / CELL_SIZE); - // Entities Z coordinate is really it's longitutinale coordinate on the terrain + // Entity's Z coordinate is really its longitudinal coordinate on the terrain u32 y = (u32)(worldPos.Z / CELL_SIZE); // Calculate map space scale diff --git a/source/gui/scripting/JSInterface_IGUIObject.cpp b/source/gui/scripting/JSInterface_IGUIObject.cpp index 7feebae196..dd303a8b14 100755 --- a/source/gui/scripting/JSInterface_IGUIObject.cpp +++ b/source/gui/scripting/JSInterface_IGUIObject.cpp @@ -5,6 +5,9 @@ #include "JSInterface_IGUIObject.h" #include "JSInterface_GUITypes.h" +#include "gui/IGUIObject.h" +#include "gui/CGUI.h" + #include "ps/StringConvert.h" JSClass JSI_IGUIObject::JSI_class = { diff --git a/source/gui/scripting/JSInterface_IGUIObject.h b/source/gui/scripting/JSInterface_IGUIObject.h index 0a04fa1439..26d776f60c 100755 --- a/source/gui/scripting/JSInterface_IGUIObject.h +++ b/source/gui/scripting/JSInterface_IGUIObject.h @@ -1,7 +1,6 @@ // $Id$ #include "scripting/ScriptingHost.h" -#include "gui/GUI.h" #ifndef JSI_IGUIOBJECT_INCLUDED #define JSI_IGUIOBJECT_INCLUDED diff --git a/source/i18n/StringBuffer.cpp b/source/i18n/StringBuffer.cpp index e5c986d720..70a4f51cb1 100755 --- a/source/i18n/StringBuffer.cpp +++ b/source/i18n/StringBuffer.cpp @@ -36,7 +36,10 @@ I18n::StringBuffer::operator Str() } if (String.VarCount == 0) - return String.Parts[0]->ToString(Locale, Variables).str(); + if (String.Parts.size()) + return String.Parts[0]->ToString(Locale, Variables).str(); + else + return Str(); Str ret; diff --git a/source/ps/Overlay.cpp b/source/ps/Overlay.cpp index a943a7f28b..f3d388bfea 100755 --- a/source/ps/Overlay.cpp +++ b/source/ps/Overlay.cpp @@ -231,6 +231,10 @@ CPos::CPos() : x(0.f), y(0.f) { } +CPos::CPos(const CSize& s) : x(s.cx), y(s.cy) +{ +} + CPos::CPos(const float &_x, const float &_y) : x(_x), y(_y) { } diff --git a/source/ps/Overlay.h b/source/ps/Overlay.h index 1ff3240332..b96bae057b 100755 --- a/source/ps/Overlay.h +++ b/source/ps/Overlay.h @@ -147,6 +147,7 @@ class CPos { public: CPos(); + CPos(const CSize &pos); CPos(const float &_x, const float &_y); // Operators diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index 4cf25e9bc6..fd76040607 100755 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -15,6 +15,8 @@ #include "Network/Server.h" #include "Network/Client.h" +#include "gui/CGUI.h" + #include "ps/i18n.h" #include "scripting/JSInterface_Entity.h"