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