Changeset View
Changeset View
Standalone View
Standalone View
source/gui/GUITooltip.cpp
Show All 14 Lines | |||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | ||||
*/ | */ | ||||
#include "precompiled.h" | #include "precompiled.h" | ||||
#include "GUITooltip.h" | #include "GUITooltip.h" | ||||
#include "gui/CGUI.h" | #include "gui/CGUI.h" | ||||
#include "gui/ObjectBases/IGUIObject.h" | #include "gui/ObjectTypes/CTooltip.h" | ||||
#include "lib/timer.h" | #include "lib/timer.h" | ||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
/* | /* | ||||
Tooltips: | Tooltips: | ||||
When holding the mouse stationary over an object for some amount of time, | 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 | 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 | disappears. If the mouse re-enters an object within a short time, the new | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
: m_State(ST_IN_MOTION), m_PreviousObject(nullptr), m_PreviousTooltipName() | : m_State(ST_IN_MOTION), m_PreviousObject(nullptr), m_PreviousTooltipName() | ||||
{ | { | ||||
} | } | ||||
const double CooldownTime = 0.25; // TODO: Don't hard-code this value | const double CooldownTime = 0.25; // TODO: Don't hard-code this value | ||||
bool GUITooltip::GetTooltip(IGUIObject* obj, CStr& style) | bool GUITooltip::GetTooltip(IGUIObject* obj, CStr& style) | ||||
{ | { | ||||
if (obj && obj->SettingExists("_icon_tooltip_style") && obj->MouseOverIcon()) | if (obj && !obj->GetTooltip().empty()) | ||||
{ | { | ||||
style = obj->GetSetting<CStr>("_icon_tooltip_style"); | style = obj->GetTooltipStyle().empty() ? "default" : obj->GetTooltipStyle(); | ||||
if (!obj->GetSetting<CStrW>("_icon_tooltip").empty()) | |||||
{ | |||||
if (style.empty()) | |||||
style = "default"; | |||||
m_IsIconTooltip = true; | |||||
return true; | return true; | ||||
} | } | ||||
} | |||||
if (obj && obj->SettingExists("tooltip_style")) | |||||
{ | |||||
style = obj->GetSetting<CStr>("tooltip_style"); | |||||
if (!obj->GetSetting<CStrW>("tooltip").empty()) | |||||
{ | |||||
if (style.empty()) | |||||
style = "default"; | |||||
m_IsIconTooltip = false; | |||||
return true; | |||||
} | |||||
} | |||||
return false; | return false; | ||||
} | } | ||||
void GUITooltip::ShowTooltip(IGUIObject* obj, const CVector2D& pos, const CStr& style, CGUI& pGUI) | void GUITooltip::ShowTooltip(IGUIObject* obj, const CVector2D& pos, const CStr& style, CGUI& pGUI) | ||||
{ | { | ||||
ENSURE(obj); | ENSURE(obj); | ||||
if (style.empty()) | if (style.empty()) | ||||
return; | return; | ||||
// Must be a CTooltip* | // Must be a CTooltip* | ||||
IGUIObject* tooltipobj = pGUI.FindObjectByName("__tooltip_" + style); | CTooltip* tooltipobj = static_cast<CTooltip*>(pGUI.FindObjectByName("__tooltip_" + style)); | ||||
if (!tooltipobj || !tooltipobj->SettingExists("use_object")) | if (!tooltipobj || !tooltipobj->SettingExists("use_object")) | ||||
{ | { | ||||
LOGERROR("Cannot find tooltip named '%s'", style.c_str()); | LOGERROR("Cannot find tooltip named '%s'", style.c_str()); | ||||
return; | return; | ||||
} | } | ||||
IGUIObject* usedobj; // object actually used to display the tooltip in | IGUIObject* usedobj; // object actually used to display the tooltip in. | ||||
const CStr& usedObjectName = tooltipobj->GetSetting<CStr>("use_object"); | const CStr& usedObjectName = tooltipobj->GetUsedObject(); | ||||
if (usedObjectName.empty()) | if (usedObjectName.empty()) | ||||
{ | { | ||||
usedobj = tooltipobj; | usedobj = tooltipobj; | ||||
tooltipobj->SetMousePos(pos); | |||||
if (usedobj->SettingExists("_mousepos")) | |||||
{ | |||||
usedobj->SetSetting<CVector2D>("_mousepos", pos, true); | |||||
} | |||||
else | |||||
{ | |||||
LOGERROR("Object '%s' used by tooltip '%s' isn't a tooltip object!", usedObjectName.c_str(), style.c_str()); | |||||
return; | |||||
} | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
usedobj = pGUI.FindObjectByName(usedObjectName); | usedobj = pGUI.FindObjectByName(usedObjectName); | ||||
if (!usedobj) | if (!usedobj) | ||||
{ | { | ||||
LOGERROR("Cannot find object named '%s' used by tooltip '%s'", usedObjectName.c_str(), style.c_str()); | LOGERROR("Cannot find object named '%s' used by tooltip '%s'", usedObjectName.c_str(), style.c_str()); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
if (usedobj->SettingExists("caption")) | if (usedobj->SettingExists("caption")) | ||||
{ | { | ||||
const CStrW& text = obj->GetSetting<CStrW>(m_IsIconTooltip ? "_icon_tooltip" : "tooltip"); | const CStrW& text = obj->GetTooltip(); | ||||
usedobj->SetSettingFromString("caption", text, true); | usedobj->SetSettingFromString("caption", text, true); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
LOGERROR("Object '%s' used by tooltip '%s' must have a caption setting!", usedobj->GetPresentableName().c_str(), style.c_str()); | LOGERROR("Object '%s' used by tooltip '%s' must have a caption setting!", usedobj->GetPresentableName().c_str(), style.c_str()); | ||||
return; | return; | ||||
} | } | ||||
// Every IGUIObject has a "hidden" setting | usedobj->SetHidden(false); | ||||
usedobj->SetSetting<bool>("hidden", false, true); | |||||
} | } | ||||
void GUITooltip::HideTooltip(const CStr& style, CGUI& pGUI) | void GUITooltip::HideTooltip(const CStr& style, CGUI& pGUI) | ||||
{ | { | ||||
if (style.empty()) | if (style.empty()) | ||||
return; | return; | ||||
// Must be a CTooltip* | // Must be a CTooltip* | ||||
IGUIObject* tooltipobj = pGUI.FindObjectByName("__tooltip_" + style); | CTooltip* tooltipobj = static_cast<CTooltip*>(pGUI.FindObjectByName("__tooltip_" + style)); | ||||
if (!tooltipobj || !tooltipobj->SettingExists("use_object") || !tooltipobj->SettingExists("hide_object")) | if (!tooltipobj || !tooltipobj->SettingExists("use_object") || !tooltipobj->SettingExists("hide_object")) | ||||
{ | { | ||||
LOGERROR("Cannot find tooltip named '%s' or it is not a tooltip", style.c_str()); | LOGERROR("Cannot find tooltip named '%s' or it is not a tooltip", style.c_str()); | ||||
return; | return; | ||||
} | } | ||||
const CStr& usedObjectName = tooltipobj->GetUsedObject(); | |||||
const CStr& usedObjectName = tooltipobj->GetSetting<CStr>("use_object"); | |||||
if (!usedObjectName.empty()) | if (!usedObjectName.empty()) | ||||
{ | { | ||||
IGUIObject* usedobj = pGUI.FindObjectByName(usedObjectName); | IGUIObject* usedobj = pGUI.FindObjectByName(usedObjectName); | ||||
if (usedobj && usedobj->SettingExists("caption")) | if (usedobj && usedobj->SettingExists("caption")) | ||||
{ | { | ||||
usedobj->SetSettingFromString("caption", L"", true); | usedobj->SetSettingFromString("caption", L"", true); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
LOGERROR("Object named '%s' used by tooltip '%s' does not exist or does not have a caption setting!", usedObjectName.c_str(), style.c_str()); | LOGERROR("Object named '%s' used by tooltip '%s' does not exist or does not have a caption setting!", usedObjectName.c_str(), style.c_str()); | ||||
return; | return; | ||||
} | } | ||||
if (tooltipobj->GetSetting<bool>("hide_object")) | if (tooltipobj->ShouldHideObject()) | ||||
// Every IGUIObject has a "hidden" setting | usedobj->SetHidden(true); | ||||
usedobj->SetSetting<bool>("hidden", true, true); | |||||
} | } | ||||
else | else | ||||
tooltipobj->SetSetting<bool>("hidden", true, true); | tooltipobj->SetHidden(true); | ||||
} | } | ||||
static i32 GetTooltipDelay(const CStr& style, CGUI& pGUI) | static i32 GetTooltipDelay(const CStr& style, CGUI& pGUI) | ||||
{ | { | ||||
// Must be a CTooltip* | // Must be a CTooltip* | ||||
IGUIObject* tooltipobj = pGUI.FindObjectByName("__tooltip_" + style); | CTooltip* tooltipobj = static_cast<CTooltip*>(pGUI.FindObjectByName("__tooltip_" + style)); | ||||
if (!tooltipobj) | if (!tooltipobj) | ||||
{ | { | ||||
LOGERROR("Cannot find tooltip object named '%s'", style.c_str()); | LOGERROR("Cannot find tooltip object named '%s'", style.c_str()); | ||||
return 500; | return 500; | ||||
} | } | ||||
return tooltipobj->GetSetting<i32>("delay"); | return tooltipobj->GetTooltipDelay(); | ||||
} | } | ||||
void GUITooltip::Update(IGUIObject* Nearest, const CVector2D& MousePos, CGUI& GUI) | void GUITooltip::Update(IGUIObject* Nearest, const CVector2D& MousePos, CGUI& GUI) | ||||
{ | { | ||||
// Called once per frame, so efficiency isn't vital | // Called once per frame, so efficiency isn't vital | ||||
double now = timer_Time(); | double now = timer_Time(); | ||||
CStr style; | CStr style; | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | else if (now >= m_Time) | ||||
// Failed to retrieve style - the object has probably been | // Failed to retrieve style - the object has probably been | ||||
// altered, so just restart the process | // altered, so just restart the process | ||||
nextstate = ST_IN_MOTION; | nextstate = ST_IN_MOTION; | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case ST_SHOWING: | case ST_SHOWING: | ||||
// Handle special case of icon tooltips | |||||
if (Nearest == m_PreviousObject && (!m_IsIconTooltip || Nearest->MouseOverIcon())) | |||||
{ | |||||
// Still showing the same object's tooltip, but the text might have changed | |||||
if (GetTooltip(Nearest, style)) | |||||
ShowTooltip(Nearest, MousePos, style, GUI); | |||||
} | |||||
else | |||||
{ | |||||
// Mouse moved onto a new object | // Mouse moved onto a new object | ||||
if (GetTooltip(Nearest, style)) | if (GetTooltip(Nearest, style)) | ||||
{ | { | ||||
CStr style_old; | CStr style_old; | ||||
// If we're displaying a tooltip with no delay, then we want to | // If we're displaying a tooltip with no delay, then we want to | ||||
// reset so that other object that should have delay can't | // reset so that other object that should have delay can't | ||||
// "ride this tail", it have to wait. | // "ride this tail", it have to wait. | ||||
// Notice that this doesn't apply to when you go from one delay=0 | // Notice that this doesn't apply to when you go from one delay=0 | ||||
// to another delay=0 | // to another delay=0 | ||||
if (GetTooltip(m_PreviousObject, style_old) && GetTooltipDelay(style_old, GUI) == 0 && | if (GetTooltip(m_PreviousObject, style_old) && GetTooltipDelay(style_old, GUI) == 0 && | ||||
GetTooltipDelay(style, GUI) != 0) | GetTooltipDelay(style, GUI) != 0) | ||||
{ | { | ||||
HideTooltip(m_PreviousTooltipName, GUI); | HideTooltip(m_PreviousTooltipName, GUI); | ||||
nextstate = ST_IN_MOTION; | nextstate = ST_IN_MOTION; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
// Hide old scrollbar | // Hide old scrollbar | ||||
HideTooltip(m_PreviousTooltipName, GUI); | HideTooltip(m_PreviousTooltipName, GUI); | ||||
nextstate = ST_SHOWING; | nextstate = ST_SHOWING; | ||||
} | } | ||||
} | } | ||||
else | else | ||||
nextstate = ST_COOLING; | nextstate = ST_COOLING; | ||||
} | |||||
break; | break; | ||||
case ST_COOLING: | case ST_COOLING: | ||||
if (GetTooltip(Nearest, style)) | if (GetTooltip(Nearest, style)) | ||||
nextstate = ST_SHOWING; | nextstate = ST_SHOWING; | ||||
else if (now >= m_Time) | else if (now >= m_Time) | ||||
nextstate = ST_IN_MOTION; | nextstate = ST_IN_MOTION; | ||||
break; | break; | ||||
Show All 28 Lines |
Wildfire Games · Phabricator