FifeGUI 0.2.0
A C++ GUI library designed for games.
tooltip.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later OR BSD-3-Clause
2// SPDX-FileCopyrightText: 2026 Fifengine contributors
3
4// Corresponding header include
5#include "fifechan/widgets/tooltip.hpp"
6
7// Standard library includes
8#include <algorithm>
9#include <string>
10
11// Project headers (subdirs before local)
12#include "fifechan/graphics.hpp"
13
14namespace fcn
15{
16
18 {
19 // Tooltips should not draw a container background.
20 // They only render their own background, then
21 // let child widgets (like a Label) draw the text.
22 setOpaque(false);
23 }
24
25 void Tooltip::setSpec(TooltipSpec const & spec)
26 {
27 mSpec = spec;
28 }
29
31 {
32 return mSpec;
33 }
34
36 {
37 mWidgetId = id;
38 }
39
41 {
42 return mWidgetId;
43 }
44
46 {
47 mIsHovering = true;
48 mHoverTimer = 0;
49 }
50
52 {
53 mIsHovering = false;
54 mHoverTimer = 0;
55 mIsExtended = false;
56 }
57
59 {
60 return mIsHovering;
61 }
62
63 void Tooltip::update(int deltaMs, int modifierState)
64 {
65 mModifierState = modifierState;
66
67 if (mIsHovering) {
68 mHoverTimer += deltaMs;
69
70 // Check if we should show extended content (ALT key)
71 bool const altPressed = (mModifierState & 0x100) != 0; // KMOD_ALT
72 mIsExtended = mSpec.modifierBehavior.enabled && altPressed;
73
75 }
76 }
77
79 {
80 if (!mIsHovering) {
81 mCurrentContent.clear();
82 return;
83 }
84
85 // Generate normal content first, then extended content if active.
86 generateNormalContent();
87
88 if (mIsExtended) {
89 generateExtendedContent();
90 }
91 }
92
93 std::string const & Tooltip::getCurrentContent() const
94 {
95 return mCurrentContent;
96 }
97
99 {
100 return mIsExtended;
101 }
102
103 void Tooltip::generateNormalContent()
104 {
105 if (mSpec.content) {
106 mCurrentContent = mSpec.content(mWidgetId);
107 } else {
108 mCurrentContent.clear();
109 }
110 }
111
112 void Tooltip::generateExtendedContent()
113 {
114 if (!mSpec.modifierBehavior.modifiedContent) {
115 return;
116 }
117
118 std::string modified = mSpec.modifierBehavior.modifiedContent(mWidgetId);
119
120 // TODO: consider a more robust way to combine normal and modified content
121 // If modified begins with the normal content, strip the duplicate prefix and
122 // any leading newlines so the extended text appears underneath.
123 if (!mCurrentContent.empty() && !modified.empty()) {
124 if (modified.rfind(mCurrentContent, 0) == 0) { // modified starts with normal
125 modified.erase(0, mCurrentContent.size());
126 while (!modified.empty() && (modified.front() == '\n' || modified.front() == '\r')) {
127 modified.erase(modified.begin());
128 }
129 }
130 }
131
132 if (mCurrentContent.empty()) {
133 mCurrentContent = modified;
134 } else if (!modified.empty()) {
135 mCurrentContent = mCurrentContent + "\n" + modified;
136 }
137 }
138
139 void Tooltip::draw(Graphics* graphics)
140 {
141 if (!mIsHovering || mHoverTimer < mSpec.delayMs) {
142 return; // Don't render if not ready
143 }
144
145 if (mCurrentContent.empty()) {
146 return;
147 }
148
149 // Render: draw background + border relative to this widget (graphics is relative)
150 Rectangle const dim(0, 0, getWidth(), getHeight());
151
152 // Choose background color to indicate extended view
153 if (mIsExtended) {
154 graphics->setColor(Color(60, 40, 80, 230));
155 } else {
156 graphics->setColor(Color(40, 40, 60, 230));
157 }
158 graphics->fillRectangle(dim);
159
160 graphics->setColor(Color(150, 150, 150));
161 graphics->drawRectangle(dim);
162
163 // Draw child widgets (e.g., Label)
164 // they will render text within this widget's coordinate space
165 Container::draw(graphics);
166 }
167
169 {
170 // While the tooltip is not hovered long enough or not in delay,
171 // do not expose the children area, so Widget::_draw() will skip
172 // drawing children.
173 // Once ready, fall back to the normal container children area.
174 if (!mIsHovering || mHoverTimer < mSpec.delayMs) {
175 return {0, 0, 0, 0};
176 }
178 }
179
180} // namespace fcn
Color.
Definition color.hpp:58
void draw(Graphics *graphics) override
Draws the widget.
Definition container.cpp:25
Rectangle getChildrenArea() override
Gets the area of the widget occupied by the widget's children.
virtual void setOpaque(bool opaque)
Sets the container to be opaque or not.
Definition container.cpp:82
Abstract interface providing primitive drawing functions (lines, rectangles, etc.).
Definition graphics.hpp:58
virtual void setColor(Color const &color)=0
Sets the color to use when drawing.
virtual void drawRectangle(Rectangle const &rectangle)=0
Draws a simple, non-filled rectangle with a one pixel width.
virtual void fillRectangle(Rectangle const &rectangle)=0
Draws a filled rectangle.
Represents a rectangular area (X, Y, Width, Height).
Definition rectangle.hpp:22
Rectangle getChildrenArea() override
Compute the children area for layout.
Definition tooltip.cpp:168
int getWidgetId() const
Get the widget id this tooltip is attached to.
Definition tooltip.cpp:40
void setSpec(TooltipSpec const &spec)
Set the tooltip specification describing content and behavior.
Definition tooltip.cpp:25
Tooltip()
Constructor.
Definition tooltip.cpp:17
void update(int deltaMs, int modifierState)
Periodic update to advance timers and compute modifier state.
Definition tooltip.cpp:63
void draw(Graphics *graphics) override
Draw the tooltip.
Definition tooltip.cpp:139
void setWidgetId(int id)
Attach this tooltip to a widget id.
Definition tooltip.cpp:35
std::string const & getCurrentContent() const
Get the currently generated content string.
Definition tooltip.cpp:93
TooltipSpec const & getSpec() const
Get the current tooltip specification.
Definition tooltip.cpp:30
void endHover()
End hover tracking for the attached widget.
Definition tooltip.cpp:51
void generateContent()
Generate tooltip content based on mSpec and widget id.
Definition tooltip.cpp:78
void startHover()
Begin hover tracking for the attached widget.
Definition tooltip.cpp:45
bool isHovering() const
Query whether the tooltip is currently hovering.
Definition tooltip.cpp:58
bool isExtendedView() const
True if the tooltip is showing extended (modifier) content.
Definition tooltip.cpp:98
int getWidth() const
Gets the width of the widget.
Definition widget.cpp:251
int getHeight() const
Gets the height of the widget.
Definition widget.cpp:264
Used replacement tokens by configure_file():
Tooltip specification (data + behavior).
Definition tooltip.hpp:61
std::function< std::string(int widgetId)> content
Function that generates tooltip content for a widget id.
Definition tooltip.hpp:65