1
0
forked from 0ad/0ad

Initial (incomplete) tooltip code

This was SVN commit r1540.
This commit is contained in:
Ykkrosh 2004-12-21 13:37:24 +00:00
parent 6486de894d
commit 659a9ea57a
26 changed files with 638 additions and 104 deletions

View File

@ -134,6 +134,23 @@
cell-id CDATA #IMPLIED cell-id CDATA #IMPLIED
> >
<!--
<tooltip>
-->
<!ATTLIST tooltip
name CDATA #REQUIRED
sprite CDATA #REQUIRED
anchor CDATA #IMPLIED
buffer-zone CDATA #IMPLIED
font CDATA #IMPLIED
maxwidth CDATA #IMPLIED
pos CDATA #IMPLIED
textcolor CDATA #IMPLIED
time CDATA #IMPLIED
>
<!-- <!--
<sprites> <sprites>
--> -->

View File

@ -31,6 +31,8 @@ CButton::CButton()
AddSetting(GUIST_CColor, "textcolor-over"); AddSetting(GUIST_CColor, "textcolor-over");
AddSetting(GUIST_CColor, "textcolor-pressed"); AddSetting(GUIST_CColor, "textcolor-pressed");
AddSetting(GUIST_CColor, "textcolor-disabled"); AddSetting(GUIST_CColor, "textcolor-disabled");
AddSetting(GUIST_CStr, "tooltip");
AddSetting(GUIST_CStr, "tooltip-style");
// Add text // Add text
AddText(new SGUIText()); AddText(new SGUIText());

View File

@ -35,17 +35,19 @@ CCheckBox::CCheckBox()
CStr m_ToolTip; CStr m_ToolTip;
CStr m_ToolTipStyle; CStr m_ToolTipStyle;
*/ */
AddSetting(GUIST_CGUIString, "caption"); AddSetting(GUIST_CGUIString, "caption");
AddSetting(GUIST_bool, "checked"); AddSetting(GUIST_bool, "checked");
AddSetting(GUIST_CGUISpriteInstance,"sprite"); AddSetting(GUIST_CGUISpriteInstance, "sprite");
AddSetting(GUIST_CGUISpriteInstance,"sprite-over"); AddSetting(GUIST_CGUISpriteInstance, "sprite-over");
AddSetting(GUIST_CGUISpriteInstance,"sprite-pressed"); AddSetting(GUIST_CGUISpriteInstance, "sprite-pressed");
AddSetting(GUIST_CGUISpriteInstance,"sprite-disabled"); AddSetting(GUIST_CGUISpriteInstance, "sprite-disabled");
AddSetting(GUIST_CGUISpriteInstance,"sprite2"); AddSetting(GUIST_CGUISpriteInstance, "sprite2");
AddSetting(GUIST_CGUISpriteInstance,"sprite2-over"); AddSetting(GUIST_CGUISpriteInstance, "sprite2-over");
AddSetting(GUIST_CGUISpriteInstance,"sprite2-pressed"); AddSetting(GUIST_CGUISpriteInstance, "sprite2-pressed");
AddSetting(GUIST_CGUISpriteInstance,"sprite2-disabled"); AddSetting(GUIST_CGUISpriteInstance, "sprite2-disabled");
AddSetting(GUIST_int, "square-side"); AddSetting(GUIST_int, "square-side");
AddSetting(GUIST_CStr, "tooltip");
AddSetting(GUIST_CStr, "tooltip-style");
// Add text // Add text
AddText(new SGUIText()); AddText(new SGUIText());

View File

@ -22,6 +22,7 @@ gee@pyro.nu
#include "CRadioButton.h" #include "CRadioButton.h"
#include "CInput.h" #include "CInput.h"
#include "CProgressBar.h" #include "CProgressBar.h"
#include "CTooltip.h"
#include "MiniMap.h" #include "MiniMap.h"
#include "ps/Xeromyces.h" #include "ps/Xeromyces.h"
@ -183,8 +184,9 @@ int CGUI::HandleEvent(const SDL_Event* ev)
else else
if (ev->type == SDL_MOUSEBUTTONUP) if (ev->type == SDL_MOUSEBUTTONUP)
{ {
if (ev->button.button == SDL_BUTTON_LEFT) switch (ev->button.button)
{ {
case SDL_BUTTON_LEFT:
if (pNearest) if (pNearest)
{ {
pNearest->HandleMessage(SGUIMessage(GUIM_MOUSE_RELEASE_LEFT)); pNearest->HandleMessage(SGUIMessage(GUIM_MOUSE_RELEASE_LEFT));
@ -192,6 +194,7 @@ int CGUI::HandleEvent(const SDL_Event* ev)
ret = EV_HANDLED; ret = EV_HANDLED;
} }
break;
} }
// Reset all states on all visible objects // Reset all states on all visible objects
@ -249,6 +252,16 @@ void CGUI::TickObjects()
CStr action = "tick"; CStr action = "tick";
GUI<CStr>::RecurseObject(0, m_BaseObject, GUI<CStr>::RecurseObject(0, m_BaseObject,
&IGUIObject::ScriptEvent, action); &IGUIObject::ScriptEvent, action);
// Also update tooltips:
// TODO: Efficiency
IGUIObject* pNearest = NULL;
GUI<IGUIObject*>::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 // this won't be exact because we're assuming the line_height
// will be as our preliminary calculation said. But that may change, // 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 // 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 // this problem out, and it is very unlikely to happen noticeably if one
// stuctures his text in a stylistically pure fashion. Even if not, it // structures his text in a stylistically pure fashion. Even if not, it
// is still quite unlikely it will happen. // is still quite unlikely it will happen.
// Loop through left and right side, from and to. // Loop through left and right side, from and to.
for (int j=0; j<2; ++j) 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) const CPos &pos, const float &z)
{ {
// TODO Gee: All these really necessary? Some // 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, // the opposite value at the end of the functions,
// some things won't be drawn correctly. // some things won't be drawn correctly.
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
@ -1054,7 +1067,15 @@ void CGUI::Xeromyces_ReadRootSetup(XMBElement Element, CXeromyces* pFile)
{ {
Xeromyces_ReadIcon(child, 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)); CStr argStyle (attributes.getNamedItem(attr_style));
if (m_Styles.count(CStr("default")) == 1) if (m_Styles.count("default") == 1)
object->LoadStyle(*this, CStr("default")); object->LoadStyle(*this, "default");
if (argStyle.Length()) if (argStyle.Length())
{ {
@ -1134,7 +1155,7 @@ void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObjec
XMBAttribute attr = attributes.item(i); XMBAttribute attr = attributes.item(i);
// If value is "null", then it is equivalent as never being entered // If value is "null", then it is equivalent as never being entered
if ((CStr)attr.Value == (CStr)"null") if ((CStr)attr.Value == "null")
continue; continue;
// Ignore "type" and "style", we've already checked it // 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) if (attr.Name == attr_z)
ManuallySetZ = true; 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 // Try setting the value
if (object->SetSetting(pFile->getAttributeString(attr.Name), (CStr)attr.Value) != PS_OK) 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 // Attempt to register the hotkey tag, if one was provided
if( hotkeyTag.Length() ) if (hotkeyTag.Length())
hotkeyRegisterGUIObject( object->GetName(), hotkeyTag ); hotkeyRegisterGUIObject(object->GetName(), hotkeyTag);
CStrW caption (Element.getText()); CStrW caption (Element.getText());
if (caption.Length()) 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 // Get name, we know it exists because of DTD requirements
name = Element.getAttributes().getNamedItem( pFile->getAttributeID("name") ); 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) // Read Children (the images)
// //
@ -1404,7 +1387,7 @@ void CGUI::Xeromyces_ReadSprite(XMBElement Element, CXeromyces* pFile)
} }
else 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 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 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) 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 else
{ {
debug_warn("Oops"); // DTD shouldn't allow this debug_warn("Invalid data - DTD shouldn't allow this");
} }
} }
m_Icons[name] = icon; 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; i<attributes.Count; ++i)
{
XMBAttribute attr = attributes.item(i);
CStr attr_name (pFile->getAttributeString(attr.Name));
CStr attr_value (attr.Value);
if (attr_name == "name")
{
object->SetName(attr_value);
}
else
{
object->SetSetting(attr_name, attr_value);
}
}
AddObject(object);
}

View File

@ -25,6 +25,7 @@ ERROR_TYPE(GUI, JSOpenFailed);
//-------------------------------------------------------- //--------------------------------------------------------
#include "GUI.h" #include "GUI.h"
#include "GUITooltip.h"
#include "Singleton.h" #include "Singleton.h"
#include "input.h" // JW: grr, classes suck in this case :P #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_ReadIcon(XMBElement Element, CXeromyces* pFile);
void Xeromyces_ReadTooltip(XMBElement Element, CXeromyces* pFile);
//@} //@}
private: private:
@ -511,6 +514,8 @@ private:
// TODO Gee: Used? // TODO Gee: Used?
int16_t m_Errors; int16_t m_Errors;
GUITooltip m_Tooltip;
//@} //@}
//-------------------------------------------------------- //--------------------------------------------------------
/** @name Objects */ /** @name Objects */

View File

@ -19,6 +19,8 @@ CImage::CImage()
{ {
AddSetting(GUIST_CGUISpriteInstance, "sprite"); AddSetting(GUIST_CGUISpriteInstance, "sprite");
AddSetting(GUIST_int, "cell-id"); AddSetting(GUIST_int, "cell-id");
AddSetting(GUIST_CStr, "tooltip");
AddSetting(GUIST_CStr, "tooltip-style");
} }
CImage::~CImage() CImage::~CImage()

View File

@ -33,6 +33,8 @@ CInput::CInput() : m_iBufferPos(0)
AddSetting(GUIST_CGUISpriteInstance, "sprite"); AddSetting(GUIST_CGUISpriteInstance, "sprite");
AddSetting(GUIST_int, "cell-id"); AddSetting(GUIST_int, "cell-id");
AddSetting(GUIST_CColor, "textcolor"); AddSetting(GUIST_CColor, "textcolor");
AddSetting(GUIST_CStr, "tooltip");
AddSetting(GUIST_CStr, "tooltip-style");
// TODO Gee: (2004-08-14) // TODO Gee: (2004-08-14)
// Add a setting for buffer zone // Add a setting for buffer zone
//AddSetting(GUIST_int, " //AddSetting(GUIST_int, "

View File

@ -20,6 +20,8 @@ CProgressBar::CProgressBar()
AddSetting(GUIST_CGUISpriteInstance, "sprite-background"); AddSetting(GUIST_CGUISpriteInstance, "sprite-background");
AddSetting(GUIST_CGUISpriteInstance, "sprite-bar"); AddSetting(GUIST_CGUISpriteInstance, "sprite-bar");
AddSetting(GUIST_float, "caption"); // aka value from 0 to 100 AddSetting(GUIST_float, "caption"); // aka value from 0 to 100
AddSetting(GUIST_CStr, "tooltip");
AddSetting(GUIST_CStr, "tooltip-style");
} }
CProgressBar::~CProgressBar() CProgressBar::~CProgressBar()

View File

@ -28,6 +28,8 @@ CText::CText()
AddSetting(GUIST_CGUISpriteInstance, "sprite"); AddSetting(GUIST_CGUISpriteInstance, "sprite");
AddSetting(GUIST_int, "cell-id"); AddSetting(GUIST_int, "cell-id");
AddSetting(GUIST_CColor, "textcolor"); AddSetting(GUIST_CColor, "textcolor");
AddSetting(GUIST_CStr, "tooltip");
AddSetting(GUIST_CStr, "tooltip-style");
// TODO Gee: (2004-08-14) // TODO Gee: (2004-08-14)
// Add a setting for buffer zone // Add a setting for buffer zone
//AddSetting(GUIST_int, " //AddSetting(GUIST_int, "
@ -56,8 +58,6 @@ void CText::SetupText()
assert(m_GeneratedTexts.size()>=1); assert(m_GeneratedTexts.size()>=1);
CColor color;
CStr font; CStr font;
if (GUI<CStr>::GetSetting(this, "font", font) != PS_OK || font.Length()==0) if (GUI<CStr>::GetSetting(this, "font", font) != PS_OK || font.Length()==0)
// Use the default if none is specified // Use the default if none is specified
@ -66,7 +66,6 @@ void CText::SetupText()
CGUIString caption; CGUIString caption;
bool scrollbar; bool scrollbar;
GUI<CColor>::GetSetting(this, "textcolor", color);
GUI<CGUIString>::GetSetting(this, "caption", caption); GUI<CGUIString>::GetSetting(this, "caption", caption);
GUI<bool>::GetSetting(this, "scrollbar", scrollbar); GUI<bool>::GetSetting(this, "scrollbar", scrollbar);

140
source/gui/CTooltip.cpp Normal file
View File

@ -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<float>::SetSetting(this, "time", 0.5f);
GUI<EVAlign>::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<CStr>::GetSetting(this, "font", font) != PS_OK || font.Length()==0)
font = "default";
float buffer_zone=0.f;
GUI<float>::GetSetting(this, "buffer-zone", buffer_zone);
CGUIString caption;
GUI<CGUIString>::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<CPos>::GetSetting(this, "_mousepos", mousepos);
GUI<CPos>::GetSetting(this, "pos", pos);
GUI<EVAlign>::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<CClientArea>::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<CGUISpriteInstance>::GetSettingPointer(this, "sprite", sprite);
GetGUI()->DrawSprite(*sprite, 0, z, m_CachedActualSize);
CColor color;
GUI<CColor>::GetSetting(this, "textcolor", color);
// Draw text
IGUITextOwner::Draw(0, color, m_CachedActualSize.TopLeft(), z+0.1f);
}
}

31
source/gui/CTooltip.h Normal file
View File

@ -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

209
source/gui/GUITooltip.cpp Normal file
View File

@ -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<CStr>::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<bool>::SetSetting(tooltipobj, "hidden", false);
assert(obj);
// These shouldn't fail:
CStr text;
if (GUI<CStr>::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<CPos>::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<bool>::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;
}

27
source/gui/GUITooltip.h Normal file
View File

@ -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

View File

@ -299,6 +299,8 @@ void CGUIString::SetValue(const CStrW& str)
// Setup parser // Setup parser
// TODO Gee: (2004-08-16) Create and store this parser object somewhere to save loading time. // 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; CParser Parser;
// I've added the option of an additional parameter. Only used for icons when writing this. // I've added the option of an additional parameter. Only used for icons when writing this.
Parser.InputTaskType("start", "$ident[_=_$value_[$ident_=_$value_]]"); Parser.InputTaskType("start", "$ident[_=_$value_[$ident_=_$value_]]");

View File

@ -132,7 +132,7 @@ struct SGUIText
* List of sprites, or "icons" that should be rendered * List of sprites, or "icons" that should be rendered
* along with the text. * along with the text.
*/ */
std::list<SSpriteCall> m_SpriteCalls; // list for consistant mem addresses std::list<SSpriteCall> m_SpriteCalls; // list for consistent mem addresses
// so that we can point to elements. // so that we can point to elements.
/** /**
@ -145,7 +145,7 @@ struct SGUIText
/** /**
* @author Gustav Larsson * @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 * the tags and builds up a list of all text that will
* be different when outputted. * be different when outputted.
* *
@ -287,7 +287,7 @@ public:
* @param Feedback contains all info that is generated. * @param Feedback contains all info that is generated.
* @param DefaultFont Default Font * @param DefaultFont Default Font
* @param from From character n, * @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 * @param FirstLine Whether this is the first line of text, to calculate its height correctly
* *
* pObject Only for Error outputting, optional! If NULL * pObject Only for Error outputting, optional! If NULL

View File

@ -1,14 +1,68 @@
// This file is used by all bits of GUI code that need to repeat some code #if 0
// for a variety of types (to avoid duplicating the list of types). Just do =pod /* (These C++ comments in Perl code are to please my syntax highlighter)
// #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
// 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 (<IN>)
{
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 #ifndef GUITYPE_IGNORE_bool
TYPE(bool) TYPE(bool)
#endif #endif
@ -42,3 +96,10 @@ TYPE(EAlign)
#ifndef GUITYPE_IGNORE_EVAlign #ifndef GUITYPE_IGNORE_EVAlign
TYPE(EVAlign) TYPE(EVAlign)
#endif #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

View File

@ -147,6 +147,19 @@ bool __ParseString<CSize>(const CStr& Value, CSize &Output)
return true; return true;
} }
template <>
bool __ParseString<CPos>(const CStr& Value, CPos &Output)
{
CSize temp;
if (__ParseString<CSize>(Value, temp))
{
Output = CPos(temp);
return true;
}
else
return false;
}
template <> template <>
bool __ParseString<EAlign>(const CStr &Value, EAlign &Output) bool __ParseString<EAlign>(const CStr &Value, EAlign &Output)
{ {

View File

@ -31,7 +31,8 @@ gee@pyro.nu
//-------------------------------------------------------- //--------------------------------------------------------
// Includes / Compiler directives // Includes / Compiler directives
//-------------------------------------------------------- //--------------------------------------------------------
#include "GUI.h" #include "GUIbase.h"
#include "GUItext.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include "input.h" // just for EV_PASS #include "input.h" // just for EV_PASS
@ -70,20 +71,12 @@ struct JSObject;
* For use of later macros, all names should be GUIST_ followed * For use of later macros, all names should be GUIST_ followed
* by the code name (case sensitive!). * by the code name (case sensitive!).
*/ */
#define TYPE(T) GUIST_##T,
enum EGUISettingType enum EGUISettingType
{ {
GUIST_bool, #include "GUItypes.h"
GUIST_int,
GUIST_float,
GUIST_CColor,
GUIST_CClientArea,
GUIST_CGUIString,
GUIST_CStr,
GUIST_CStrW,
GUIST_CGUISpriteInstance,
GUIST_EAlign,
GUIST_EVAlign
}; };
#undef TYPE
/** /**
* @author Gustav Larsson * @author Gustav Larsson
@ -135,6 +128,7 @@ class IGUIObject
friend class CGUI; friend class CGUI;
friend class CInternalCGUIAccessorBase; friend class CInternalCGUIAccessorBase;
friend class IGUIScrollBar; friend class IGUIScrollBar;
friend class GUITooltip;
// Allow getProperty to access things like GetParent() // Allow getProperty to access things like GetParent()
friend JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp); 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 * Settings pool, all an object's settings are located here
* If a derived object has got more settings that the base * 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(). * function SetupSettings().
* *
* @see SetupSettings() * @see SetupSettings()

View File

@ -41,10 +41,12 @@ void IGUITextOwner::HandleMessage(const SGUIMessage &Message)
// these. Although that is not certain, but one will have to manually // these. Although that is not certain, but one will have to manually
// change it and disregard this function. // change it and disregard this function.
// TODO Gee: (2004-09-07) Make sure this is all options that can affect the text. // 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") || // Also TODO: If several things are changing (e.g. when loading the file),
Message.value == CStr("absolute") || Message.value == CStr("caption") || // only call SetupText once (probably just before it's drawn)
Message.value == CStr("font") || Message.value == CStr("textcolor") || if (Message.value == "size" || Message.value == "z" ||
Message.value == CStr("buffer-zone")) Message.value == "absolute" || Message.value == "caption" ||
Message.value == "font" || Message.value == "textcolor" ||
Message.value == "buffer-zone")
{ {
SetupText(); SetupText();
} }

View File

@ -31,7 +31,9 @@ CMiniMap::CMiniMap()
: m_Handle(0), m_Data(NULL), m_MapSize(0), m_Terrain(0), : m_Handle(0), m_Data(NULL), m_MapSize(0), m_Terrain(0),
m_UnitManager(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() CMiniMap::~CMiniMap()
@ -189,12 +191,12 @@ void CMiniMap::Destroy()
/* /*
* Calefaction * Calefaction
* TODO: Speed this up. There has to be some mathematical way to make * 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) CVector2D CMiniMap::GetMapSpaceCoords(CVector3D worldPos)
{ {
u32 x = (u32)(worldPos.X / CELL_SIZE); 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); u32 y = (u32)(worldPos.Z / CELL_SIZE);
// Calculate map space scale // Calculate map space scale

View File

@ -5,6 +5,9 @@
#include "JSInterface_IGUIObject.h" #include "JSInterface_IGUIObject.h"
#include "JSInterface_GUITypes.h" #include "JSInterface_GUITypes.h"
#include "gui/IGUIObject.h"
#include "gui/CGUI.h"
#include "ps/StringConvert.h" #include "ps/StringConvert.h"
JSClass JSI_IGUIObject::JSI_class = { JSClass JSI_IGUIObject::JSI_class = {

View File

@ -1,7 +1,6 @@
// $Id$ // $Id$
#include "scripting/ScriptingHost.h" #include "scripting/ScriptingHost.h"
#include "gui/GUI.h"
#ifndef JSI_IGUIOBJECT_INCLUDED #ifndef JSI_IGUIOBJECT_INCLUDED
#define JSI_IGUIOBJECT_INCLUDED #define JSI_IGUIOBJECT_INCLUDED

View File

@ -36,7 +36,10 @@ I18n::StringBuffer::operator Str()
} }
if (String.VarCount == 0) 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; Str ret;

View File

@ -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) CPos::CPos(const float &_x, const float &_y) : x(_x), y(_y)
{ {
} }

View File

@ -147,6 +147,7 @@ class CPos
{ {
public: public:
CPos(); CPos();
CPos(const CSize &pos);
CPos(const float &_x, const float &_y); CPos(const float &_x, const float &_y);
// Operators // Operators

View File

@ -15,6 +15,8 @@
#include "Network/Server.h" #include "Network/Server.h"
#include "Network/Client.h" #include "Network/Client.h"
#include "gui/CGUI.h"
#include "ps/i18n.h" #include "ps/i18n.h"
#include "scripting/JSInterface_Entity.h" #include "scripting/JSInterface_Entity.h"