FifeGUI 0.3.0
A C++ GUI library designed for games.
imagebutton.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later OR BSD-3-Clause
2// SPDX-FileCopyrightText: 2004 - 2008 Olof Naessén and Per Larsson
3// SPDX-FileCopyrightText: 2013 - 2026 Fifengine contributors
4
5// Corresponding header include
6#include "fifechan/widgets/imagebutton.hpp"
7
8// Standard library includes
9#include <algorithm>
10#include <string>
11#include <vector>
12
13// Project headers (subdirs before local)
14#include "fifechan/exception.hpp"
15#include "fifechan/font.hpp"
16#include "fifechan/graphics.hpp"
17#include "fifechan/image.hpp"
18
19namespace fcn
20{
21 ImageButton::ImageButton() : mImages(6, static_cast<Image const *>(nullptr)), mOwnedImages(6)
22 {
23 adjustSizeImpl();
24 }
25
26 ImageButton::ImageButton(std::string const & filename) :
27 mImages(6, static_cast<Image const *>(nullptr)), mOwnedImages(6)
28 {
29 setUpImage(filename);
30 }
31
32 ImageButton::ImageButton(Image const * image) : mImages(6, static_cast<Image const *>(nullptr)), mOwnedImages(6)
33 {
34 setUpImage(image);
35 }
36
37 ImageButton::~ImageButton() = default;
38
39 void ImageButton::setImage(std::string const & filename, ImageType type)
40 {
41 mOwnedImages.at(static_cast<size_t>(type)).reset(Image::load(filename));
42 mImages.at(static_cast<size_t>(type)) = mOwnedImages.at(static_cast<size_t>(type)).get();
44 }
45
46 void ImageButton::setImage(Image const * image, ImageType type)
47 {
48 mOwnedImages.at(static_cast<size_t>(type)).reset();
49 mImages.at(static_cast<size_t>(type)) = image;
51 }
52
53 void ImageButton::setUpImage(std::string const & filename)
54 {
55 setImage(filename, ImageType::Up);
56 }
57
58 void ImageButton::setUpImage(Image const * image)
59 {
60 setImage(image, ImageType::Up);
61 }
62
64 {
65 return mImages.at(static_cast<size_t>(ImageType::Up));
66 }
67
68 void ImageButton::setDownImage(std::string const & filename)
69 {
70 setImage(filename, ImageType::Down);
71 }
72
73 void ImageButton::setDownImage(Image const * image)
74 {
75 setImage(image, ImageType::Down);
76 }
77
79 {
80 return mImages.at(static_cast<size_t>(ImageType::Down));
81 }
82
83 void ImageButton::setHoverImage(std::string const & filename)
84 {
85 setImage(filename, ImageType::Hover);
86 }
87
89 {
90 setImage(image, ImageType::Hover);
91 }
92
94 {
95 return mImages.at(static_cast<size_t>(ImageType::Hover));
96 }
97
98 void ImageButton::setInactiveUpImage(std::string const & filename)
99 {
100 setImage(filename, ImageType::Up_Inactive);
101 }
102
104 {
105 setImage(image, ImageType::Up_Inactive);
106 }
107
109 {
110 return mImages.at(static_cast<size_t>(ImageType::Up_Inactive));
111 }
112
113 void ImageButton::setInactiveDownImage(std::string const & filename)
114 {
115 setImage(filename, ImageType::Down_Inactive);
116 }
117
119 {
120 setImage(image, ImageType::Down_Inactive);
121 }
122
124 {
125 return mImages.at(static_cast<size_t>(ImageType::Down_Inactive));
126 }
127
128 void ImageButton::setInactiveHoverImage(std::string const & filename)
129 {
130 setImage(filename, ImageType::Hover_Inactive);
131 }
132
134 {
135 setImage(image, ImageType::Hover_Inactive);
136 }
137
139 {
140 return mImages.at(static_cast<size_t>(ImageType::Hover_Inactive));
141 }
142
143 void ImageButton::resizeToContent([[maybe_unused]] bool recursion)
144 {
146 }
147
149 {
151 }
152
154 {
155 int w = 0;
156 int h = 0;
157 for (unsigned int i = 0; i < 6; ++i) {
158 Image const * img = mImages.at(i);
159 if (img != nullptr) {
160 w = std::max(w, img->getWidth());
161 h = std::max(h, img->getHeight());
162 }
163 }
164 if (!getCaption().empty()) {
165 w = std::max(getFont()->getWidth(getCaption()), w);
166 h = std::max(getFont()->getHeight(), h);
167 }
168 w += (2 * getBorderSize()) + getPaddingLeft() + getPaddingRight();
169 h += (2 * getBorderSize()) + getPaddingTop() + getPaddingBottom();
170 setSize(w, h);
171 }
172
174 {
175 // draw border or frame
176 if (getBorderSize() > 0) {
177 if (isFocused() && (getSelectionMode() & Widget::SelectionMode::Border) == Widget::SelectionMode::Border) {
178 drawSelectionFrame(graphics);
179 } else {
180 drawBorder(graphics);
181 }
182 }
183
184 Rectangle offsetRec(getBorderSize(), getBorderSize(), (2 * getBorderSize()), (2 * getBorderSize()));
185 // fetch the image, down, hover or up
186 Image const * img = !isActive() && (getInactiveUpImage() != nullptr) ? getInactiveUpImage() : getUpImage();
187 if (isPressed()) {
188 offsetRec.x += getDownXOffset();
189 offsetRec.y += getDownYOffset();
190 if (!isActive()) {
191 if (getInactiveDownImage() != nullptr) {
192 img = getInactiveDownImage();
193 }
194 } else {
195 img = (getDownImage() != nullptr) ? getDownImage() : getUpImage();
196 }
197 } else if (mHasMouse) {
198 if (!isActive()) {
199 if (getInactiveHoverImage() != nullptr) {
200 img = getInactiveHoverImage();
201 }
202 } else {
203 img = (getHoverImage() != nullptr) ? getHoverImage() : getUpImage();
204 }
205 }
206 // render foreground image or color rectangle
207 if (img != nullptr) {
208 graphics->drawImage(
209 img, 0, 0, offsetRec.x, offsetRec.y, getWidth() - offsetRec.width, getHeight() - offsetRec.height);
210 } else {
211 Color faceColor = getBaseColor();
212 if (isFocused() &&
213 ((getSelectionMode() & Widget::SelectionMode::Background) == Widget::SelectionMode::Background)) {
214 faceColor = getSelectionColor();
215 }
216 int const alpha = faceColor.a;
217
218 if (isPressed()) {
219 faceColor = faceColor - 0x303030;
220 faceColor.a = alpha;
221 }
222 if (!isActive()) {
223 int const color = static_cast<int>((faceColor.r * 0.3) + (faceColor.g * 0.59) + (faceColor.b * 0.11));
224 faceColor.r = color;
225 faceColor.g = color;
226 faceColor.b = color;
227 }
228
229 graphics->setColor(faceColor);
230 graphics->fillRectangle(
231 offsetRec.x, offsetRec.y, getWidth() - offsetRec.width, getHeight() - offsetRec.height);
232 }
233
234 // render caption if it exits
235 if (!getCaption().empty()) {
236 int textX = 0;
237 int const textY =
238 offsetRec.y + getPaddingTop() +
239 ((getHeight() - offsetRec.height - getPaddingTop() - getPaddingBottom() - getFont()->getHeight()) / 2);
240 switch (getAlignment()) {
241 case Graphics::Alignment::Left:
242 textX = offsetRec.x + getPaddingLeft();
243 break;
244 case Graphics::Alignment::Center:
245 textX = offsetRec.x + getPaddingLeft() +
246 ((getWidth() - offsetRec.width - getPaddingLeft() - getPaddingRight()) / 2);
247 break;
248 case Graphics::Alignment::Right:
249 textX = getWidth() - offsetRec.x - getPaddingRight();
250 break;
251 default:
252 throwException("Unknown alignment.");
253 }
254 // set font and color
255 graphics->setFont(getFont());
256 // Use white for emoji captions to preserve native OT-SVG color font colors
257 // Emoji UTF-8 sequences typically start with 0xF0 (4-byte, U+10000+)
258 // or 0xE2 (3-byte, includes many symbols/emoji like ⭐ U+2B50, ⚙ U+2699)
259 std::string const & cap = getCaption();
260 if (!cap.empty()) {
261 unsigned char const first = static_cast<unsigned char>(cap.at(0));
262 // Check for emoji ranges: 0xF0+ (most emoji) or 0xE2 (common symbol emoji)
263 if (first >= 0xF0 || first == 0xE2) {
264 graphics->setColor(Color(255, 255, 255, 255));
265 } else {
266 graphics->setColor(getForegroundColor());
267 }
268 } else {
269 graphics->setColor(getForegroundColor());
270 }
271 graphics->drawText(getCaption(), textX, textY, getAlignment());
272 }
273 }
274} // namespace fcn
std::string const & getCaption() const
Gets the caption of the button.
Definition button.cpp:52
bool isActive() const
Returns the button state.
Definition button.cpp:62
Graphics::Alignment getAlignment() const
Gets the alignment of the caption.
Definition button.cpp:72
virtual bool isPressed() const
Checks if the button is pressed.
Definition button.cpp:188
bool mHasMouse
True if the mouse is on top of the button, false otherwise.
Definition button.hpp:205
int getDownYOffset() const
Gets the number of pixels the image or text will be offset.
Definition button.cpp:92
int getDownXOffset() const
Gets the number of pixels the image or text will be offset.
Definition button.cpp:82
Color.
Definition color.hpp:58
uint8_t a
Alpha color component (0-255).
Definition color.hpp:350
uint8_t b
Blue color component (0-255).
Definition color.hpp:347
uint8_t g
Green color component (0-255).
Definition color.hpp:344
uint8_t r
Red color component (0-255).
Definition color.hpp:341
virtual int getHeight() const =0
Gets the height of the glyphs in the font.
Abstract interface providing primitive drawing functions (lines, rectangles, etc.).
Definition graphics.hpp:58
virtual void drawImage(Image const *image, int srcX, int srcY, int dstX, int dstY, int width, int height)=0
Draws a part of an image.
void drawText(std::string const &text, int x, int y)
Draws text with a default left alignment.
Definition graphics.hpp:401
virtual void setFont(Font *font)
Sets the font to use when drawing text.
Definition graphics.cpp:91
virtual void setColor(Color const &color)=0
Sets the color to use when drawing.
virtual void fillRectangle(Rectangle const &rectangle)=0
Draws a filled rectangle.
void setImage(std::string const &filename, ImageType type)
Internal helper to set an image for a specific ImageType by filename.
Image const * getInactiveDownImage() const
Gets inactive down image.
void adjustSize() override
Adjust internal size after layout or image changes.
Image const * getUpImage() const
Gets current up image.
void setInactiveUpImage(std::string const &filename)
Sets the up image to display if the button is inactive.
void setDownImage(std::string const &filename)
Sets the down image to display.
Image const * getDownImage() const
Gets current down image.
std::vector< Image const * > mImages
The images to display.
void setInactiveHoverImage(std::string const &filename)
Sets the hover image to display if the button is inactive.
Image const * getInactiveUpImage() const
Gets inactive up image.
void adjustSizeImpl() override
Adjusts the size of the button to fit the caption.
void resizeToContent(bool recursion=true) override
Resize the button to fit its image content.
void setHoverImage(std::string const &filename)
Sets the hover image to display.
std::vector< std::unique_ptr< Image const > > mOwnedImages
Owned images loaded by filename.
ImageType
Types of images used by ImageButton.
void setUpImage(std::string const &filename)
Sets the up image to display.
void setInactiveDownImage(std::string const &filename)
Sets the down image to display if the button is inactive.
Image const * getHoverImage() const
Gets current hover image.
void draw(fcn::Graphics *graphics) override
Draw the button using the provided graphics backend.
Image const * getInactiveHoverImage() const
Gets inactive hover image.
Abstract holder for image data.
Definition image.hpp:34
virtual int getHeight() const =0
Gets the height of the image.
static Image * load(std::string const &filename, bool convertToDisplayFormat=true)
Loads an image by using the class' image loader.
Definition image.cpp:44
virtual int getWidth() const =0
Gets the width of the image.
Represents a rectangular area (X, Y, Width, Height).
Definition rectangle.hpp:22
int width
Holds the width of the rectangle.
int y
Holds the x coordinate of the rectangle.
int x
Holds the x coordinate of the rectangle.
int height
Holds the height of the rectangle.
Color const & getBaseColor() const
Gets the base color.
Definition widget.cpp:742
int getWidth() const
Gets the width of the widget.
Definition widget.cpp:252
virtual bool isFocused() const
Checks if the widget is focused.
Definition widget.cpp:624
unsigned int getPaddingLeft() const
Gets the left padding.
Definition widget.cpp:604
virtual void setSize(int width, int height)
Sets the size of the widget.
Definition widget.cpp:1065
virtual void drawBorder(Graphics *graphics)
Called when a widget have a border.
Definition widget.cpp:156
unsigned int getPaddingTop() const
Gets the top padding.
Definition widget.cpp:574
unsigned int getBorderSize() const
Gets the size of the widget's border.
Definition widget.cpp:474
virtual void drawSelectionFrame(Graphics *graphics)
Called when a widget is "active" and the selection mode is Frame or FrameWithBackground.
Definition widget.cpp:217
unsigned int getPaddingBottom() const
Gets the bottom padding.
Definition widget.cpp:594
Color const & getForegroundColor() const
Gets the foreground color.
Definition widget.cpp:752
SelectionMode getSelectionMode() const
Gets the selection mode.
Definition widget.cpp:802
Font * getFont() const
Gets the font set for the widget.
Definition widget.cpp:1000
int getHeight() const
Gets the height of the widget.
Definition widget.cpp:265
unsigned int getPaddingRight() const
Gets the right padding.
Definition widget.cpp:584
Color const & getSelectionColor() const
Gets the selection color.
Definition widget.cpp:772
Used replacement tokens by configure_file():
void throwException(std::string const &message, std::source_location location=std::source_location::current())
Throw an Exception capturing the current source location.