FifeGUI 0.2.0
A C++ GUI library designed for games.
checkbox.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#include "fifechan/widgets/checkbox.hpp"
6
7#include <algorithm>
8#include <string>
9
10#include "fifechan/exception.hpp"
11#include "fifechan/font.hpp"
12#include "fifechan/graphics.hpp"
13#include "fifechan/image.hpp"
14
15namespace fcn
16{
17
18 namespace
19 {
20 void drawMarkerBrush(Graphics* graphics, int x, int y, int thickness)
21 {
22 int const offset = (thickness - 1) / 2;
23 graphics->fillRectangle(x - offset, y - offset, thickness, thickness);
24 }
25
26 void drawMarkerStroke(Graphics* graphics, Point const & start, Point const & end, int thickness)
27 {
28 int x = start.x;
29 int y = start.y;
30
31 int const deltaX = std::abs(end.x - start.x);
32 int const stepX = (start.x < end.x) ? 1 : -1;
33 int const deltaY = -std::abs(end.y - start.y);
34 int const stepY = (start.y < end.y) ? 1 : -1;
35 int error = deltaX + deltaY;
36
37 while (true) {
38 drawMarkerBrush(graphics, x, y, thickness);
39
40 if ((x == end.x) && (y == end.y)) {
41 break;
42 }
43
44 int const doubledError = 2 * error;
45 if (doubledError >= deltaY) {
46 error += deltaY;
47 x += stepX;
48 }
49 if (doubledError <= deltaX) {
50 error += deltaX;
51 y += stepY;
52 }
53 }
54 }
55
56 int scaleMarkerCoordinate(int origin, int size, int numerator)
57 {
58 return origin + (((size - 1) * numerator) / 16);
59 }
60 } // namespace
61
62 CheckBox::CheckBox()
63 {
65 }
66
67 CheckBox::CheckBox(std::string const & caption, bool selected) : mSelected(selected)
68 {
69 setCaption(caption);
71 }
72
73 CheckBox::~CheckBox()
74 {
76 delete mBackgroundImage;
77 }
78 }
79
80 void CheckBox::draw(Graphics* graphics)
81 {
82 if (mMode == MarkerStyle::Rhombus) {
83 drawRhombus(graphics);
84 } else {
85 drawBox(graphics);
86 }
87
88 if (!getCaption().empty()) {
89 graphics->setFont(getFont());
90 graphics->setColor(getForegroundColor());
91
92 int const h = getHeight() - (2 * getBorderSize()) - getPaddingTop() - getPaddingBottom();
93 int const textX = getBorderSize() + getPaddingLeft() + h;
94 int const textY = getBorderSize() + getPaddingTop() + ((h - getFont()->getHeight()) / 2);
95 graphics->drawText(getCaption(), textX, textY);
96 }
97 }
98
100 {
101 bool const active = isFocused();
102
103 // draw background
104 Rectangle const background(
106 if (mBackgroundImage != nullptr) {
107 graphics->drawImage(
108 mBackgroundImage, 0, 0, background.x, background.y, background.width, background.height);
109 } else {
110 Color faceColor = getBaseColor();
111 if (active &&
112 ((getSelectionMode() & Widget::SelectionMode::Background) == Widget::SelectionMode::Background)) {
113 faceColor = getSelectionColor();
114 }
115 graphics->setColor(faceColor);
116 graphics->fillRectangle(background.x, background.y, background.width, background.height);
117 }
118
119 // rec for inner box
120 int const h = getHeight() - (2 * getBorderSize()) - getPaddingTop() - getPaddingBottom();
122 if (mMode == MarkerStyle::Image) {
123 // draw marker image
124 drawMarkerImage(graphics, rec);
125 // draw border
126 if (getBorderSize() > 0) {
127 if (active && (getSelectionMode() & Widget::SelectionMode::Border) == Widget::SelectionMode::Border) {
128 drawSelectionFrame(graphics);
129 } else {
130 drawBorder(graphics);
131 }
132 }
133 } else {
134 // draw inner box background
135 graphics->setColor(getBackgroundColor());
136 graphics->fillRectangle(rec.x, rec.y, h, h);
137 // draw border
138 if (getBorderSize() > 0) {
139 if (active && (getSelectionMode() & Widget::SelectionMode::Border) == Widget::SelectionMode::Border) {
140 drawSelectionFrame(graphics);
141 } else {
142 drawBorder(graphics);
143 }
144 }
145 Color faceColor = getBaseColor();
146 if (active &&
147 ((getSelectionMode() & Widget::SelectionMode::Background) == Widget::SelectionMode::Background)) {
148 faceColor = getSelectionColor();
149 }
150 // border around the inner box background
151 int const alpha = getBaseColor().a;
152 faceColor.a = alpha;
153 Color highlightColor = faceColor + 0x303030;
154 highlightColor.a = alpha;
155 Color shadowColor = faceColor - 0x303030;
156 shadowColor.a = alpha;
157
158 int const recRight = rec.x + rec.width - 1;
159 int const recBottom = rec.y + rec.height - 1;
160
161 graphics->setColor(shadowColor);
162 graphics->drawLine(rec.x, rec.y, recRight, rec.y);
163 graphics->drawLine(rec.x, rec.y, rec.x, recBottom);
164
165 graphics->setColor(highlightColor);
166 graphics->drawLine(recRight, rec.y, recRight, recBottom);
167 graphics->drawLine(rec.x, recBottom, recRight, recBottom);
168
169 // draws marker
170 if (mSelected) {
171 graphics->setColor(getForegroundColor());
172 switch (mMode) {
173 case MarkerStyle::Checkmark:
174 drawCheckmark(graphics, rec);
175 break;
176 case MarkerStyle::Cross:
177 drawCross(graphics, rec);
178 break;
179 case MarkerStyle::Dot:
180 drawDot(graphics, rec);
181 break;
182 default:
183 throwException("Unknown marker.");
184 }
185 }
186 }
187 }
188
189 void CheckBox::drawCheckmark(Graphics* graphics, Rectangle const & rec)
190 {
191 int const thickness = std::max(1, std::min(rec.width, rec.height) / 6);
192
193 Point const start(scaleMarkerCoordinate(rec.x, rec.width, 3), scaleMarkerCoordinate(rec.y, rec.height, 8));
194 Point const joint(scaleMarkerCoordinate(rec.x, rec.width, 7), scaleMarkerCoordinate(rec.y, rec.height, 12));
195 Point const end(scaleMarkerCoordinate(rec.x, rec.width, 13), scaleMarkerCoordinate(rec.y, rec.height, 4));
196
197 drawMarkerStroke(graphics, start, joint, thickness);
198 drawMarkerStroke(graphics, joint, end, thickness);
199 }
200
201 void CheckBox::drawCross(Graphics* graphics, Rectangle const & rec)
202 {
203 int const thickness = std::max(1, std::min(rec.width, rec.height) / 6);
204
205 Point const topLeft(scaleMarkerCoordinate(rec.x, rec.width, 3), scaleMarkerCoordinate(rec.y, rec.height, 3));
206 Point const bottomRight(
207 scaleMarkerCoordinate(rec.x, rec.width, 13), scaleMarkerCoordinate(rec.y, rec.height, 13));
208 Point const bottomLeft(
209 scaleMarkerCoordinate(rec.x, rec.width, 3), scaleMarkerCoordinate(rec.y, rec.height, 13));
210 Point const topRight(scaleMarkerCoordinate(rec.x, rec.width, 13), scaleMarkerCoordinate(rec.y, rec.height, 3));
211
212 drawMarkerStroke(graphics, topLeft, bottomRight, thickness);
213 drawMarkerStroke(graphics, bottomLeft, topRight, thickness);
214 }
215
216 void CheckBox::drawDot(Graphics* graphics, Rectangle const & rec)
217 {
218 Point const p(rec.x + (rec.width / 2), rec.y + (rec.height / 2));
219
220 int const radius = (rec.width - 3) / 2;
221
222 graphics->drawFillCircle(p, radius);
223 }
224
225 void CheckBox::drawMarkerImage(Graphics* graphics, Rectangle const & rec)
226 {
227 Rectangle rect = rec;
228 Image const * img = nullptr;
229 if (isSelected()) {
230 rect.x += getDownXOffset();
231 rect.y += getDownYOffset();
232 if (!isActive()) {
233 if (getInactiveDownImage() != nullptr) {
234 img = getInactiveDownImage();
235 }
236 } else {
237 img = (getDownImage() != nullptr) ? getDownImage() : getUpImage();
238 }
239 } else if (mHasMouse) {
240 if (!isActive()) {
241 if (getInactiveHoverImage() != nullptr) {
242 img = getInactiveHoverImage();
243 }
244 } else {
245 img = (getHoverImage() != nullptr) ? getHoverImage() : getUpImage();
246 }
247 }
248
249 if (img != nullptr) {
250 graphics->drawImage(img, 0, 0, rect.x, rect.y, std::max(rect.width, img->getWidth()), rect.height);
251 }
252 }
253
255 {
256 // ToDo: Rewrite this part, its only c&p from RadioButton
257 graphics->pushClipArea(Rectangle(1, 1, getWidth() - 1, getHeight() - 1));
258 int h = 0;
259
260 if (getHeight() % 2 == 0) {
261 h = getHeight() - 4;
262 } else {
263 h = getHeight() - 3;
264 }
265
266 int const alpha = getBaseColor().a;
267 Color faceColor = getBaseColor();
268 faceColor.a = alpha;
269 Color highlightColor = faceColor + 0x303030;
270 highlightColor.a = alpha;
271 Color shadowColor = faceColor - 0x303030;
272 shadowColor.a = alpha;
273
274 graphics->setColor(getBackgroundColor());
275
276 int i = 0;
277 int const hh = (h + 1) / 2;
278
279 for (i = 1; i <= hh; ++i) {
280 graphics->drawLine(hh - i + 1, i, hh + i - 1, i);
281 }
282
283 for (i = 1; i < hh; ++i) {
284 graphics->drawLine(hh - i + 1, h - i, hh + i - 1, h - i);
285 }
286
287 graphics->setColor(shadowColor);
288 graphics->drawLine(hh, 0, 0, hh);
289 graphics->drawLine(hh + 1, 1, h - 1, hh - 1);
290
291 graphics->setColor(highlightColor);
292 graphics->drawLine(1, hh + 1, hh, h);
293 graphics->drawLine(hh + 1, h - 1, h, hh);
294
295 graphics->setColor(getForegroundColor());
296
297 int const hhh = hh - 3;
298
299 if (mSelected) {
300 for (i = 0; i < hhh; ++i) {
301 graphics->drawLine(hh - i, 4 + i, hh + i, 4 + i);
302 }
303 for (i = 0; i < hhh; ++i) {
304 graphics->drawLine(hh - i, h - 4 - i, hh + i, h - 4 - i);
305 }
306 }
307 graphics->popClipArea();
308
309 if (isFocused()) {
310 int fh = 0;
311
312 if (getHeight() % 2 == 0) {
313 fh = getHeight() - 4;
314 } else {
315 fh = getHeight() - 3;
316 }
317
318 int const fhh = (fh + 1) / 2;
319
320 graphics->setColor(getSelectionColor());
321 graphics->drawLine(0, fhh + 1, fhh + 1, 0);
322 graphics->drawLine(fhh + 2, 1, fh + 2, fhh + 1);
323 graphics->drawLine(fh + 1, fhh + 2, fhh + 1, fh + 2);
324 graphics->drawLine(fhh + 1, fh + 2, 1, fhh + 2);
325 }
326 }
327
329 {
330 return mSelected;
331 }
332
333 void CheckBox::setSelected(bool selected)
334 {
335 mSelected = selected;
336 }
337
339 {
341 }
342
343 void CheckBox::setBackgroundImage(std::string const & filename)
344 {
346 delete mBackgroundImage;
347 }
348 mBackgroundImage = Image::load(filename);
351 }
352
354 {
356 delete mBackgroundImage;
357 }
358 mBackgroundImage = image;
361 }
362
364 {
365 return mBackgroundImage;
366 }
367
369 {
370 return mMode;
371 }
372
374 {
375 mMode = mode;
376 }
377
379 {
380 Key const key = keyEvent.getKey();
381
382 if (key.getValue() == Key::Enter || key.getValue() == Key::Space) {
384 keyEvent.consume();
386 }
387 }
388
390 {
391 Key const key = keyEvent.getKey();
392
393 if (key.getValue() == Key::Enter || key.getValue() == Key::Space) {
394 keyEvent.consume();
395 }
396 }
397
399 {
400 if (mHasMouse) {
401 mouseEvent.consume();
402 }
403 }
404
406 {
407 if (mHasMouse) {
408 mouseEvent.consume();
409 }
410 }
411
413 {
414 if (mHasMouse && mouseEvent.getButton() == MouseEvent::Button::Left) {
416 mouseEvent.consume();
418 }
419 }
420
422 {
424 }
425
427 {
428 int w = 0;
429 int h = 0;
430 if (mBackgroundImage != nullptr) {
431 w += mBackgroundImage->getWidth() + 2 * getBorderSize();
432 h += mBackgroundImage->getHeight() + 2 * getBorderSize();
433 } else {
434 if (!getCaption().empty()) {
435 w = getFont()->getWidth(getCaption());
436 h = getFont()->getHeight();
437 }
438
439 if (getUpImage() != nullptr) {
440 w += getUpImage()->getWidth();
441 h = std::max(getUpImage()->getHeight(), h);
442 } else {
443 // without image we need extra space for the mark
444 w += h;
445 }
448 }
449 setSize(w, h);
450 }
451} // namespace fcn
std::string const & getCaption() const
Gets the caption of the button.
Definition button.cpp:49
bool isActive() const
Returns the button state.
Definition button.cpp:59
bool mHasMouse
True if the mouse is on top of the button, false otherwise.
Definition button.hpp:201
int getDownYOffset() const
Gets the number of pixels the image or text will be offset.
Definition button.cpp:89
int getDownXOffset() const
Gets the number of pixels the image or text will be offset.
Definition button.cpp:79
void setCaption(std::string const &caption)
Sets the caption of the button.
Definition button.cpp:43
void drawMarkerImage(Graphics *graphics, Rectangle const &rec)
Draws the marker image.
Definition checkbox.cpp:225
void drawCheckmark(Graphics *graphics, Rectangle const &rec)
Draws the checkmark.
Definition checkbox.cpp:189
void setBackgroundImage(std::string const &filename)
Sets the background image to display, that includes the caption region.
Definition checkbox.cpp:343
void keyPressed(KeyEvent &keyEvent) override
Called if a key is pressed when the widget has keyboard focus.
Definition checkbox.cpp:378
Image const * getBackgroundImage() const
Gets background image.
Definition checkbox.cpp:363
MarkerStyle getMarkerStyle() const
Gets the marker mode of the check box.
Definition checkbox.cpp:368
virtual void setSelected(bool selected)
Sets the check box to be selected or not.
Definition checkbox.cpp:333
void keyReleased(KeyEvent &keyEvent) override
Called if a key is released when the widget has keyboard focus.
Definition checkbox.cpp:389
MarkerStyle mMode
Holds the marker style of the check box.
Definition checkbox.hpp:216
void mouseClicked(MouseEvent &mouseEvent) override
Called when a mouse button is pressed and released (clicked) on the widget area.
Definition checkbox.cpp:412
void draw(Graphics *graphics) override
Draws the widget.
Definition checkbox.cpp:80
Image const * mBackgroundImage
Holds the background image, that includes the caption region.
Definition checkbox.hpp:195
bool mSelected
True if the check box is selected, false otherwise.
Definition checkbox.hpp:211
virtual void drawBox(Graphics *graphics)
Draws the box of the check box.
Definition checkbox.cpp:99
virtual void toggleSelected()
Toggles the check box between being selected and not being selected.
Definition checkbox.cpp:338
void drawRhombus(Graphics *graphics)
Draws the rhombus.
Definition checkbox.cpp:254
bool mInternalBackgroundImage
True if the background image was loaded internally, false otherwise.
Definition checkbox.hpp:206
void drawCross(Graphics *graphics, Rectangle const &rec)
Draws the cross.
Definition checkbox.cpp:201
void adjustSize() override
Resizes the widget's size to fit the content exactly.
Definition checkbox.cpp:421
void mousePressed(MouseEvent &mouseEvent) override
Called when a mouse button has been pressed on the widget area.
Definition checkbox.cpp:398
MarkerStyle
Marker style.
Definition checkbox.hpp:33
void adjustSizeImpl() override
Adjusts the size of the checkbox to fit the caption.
Definition checkbox.cpp:426
void mouseReleased(MouseEvent &mouseEvent) override
Called when a mouse button has been released on the widget area.
Definition checkbox.cpp:405
void setMarkerStyle(MarkerStyle mode)
Set the marker style of the check box.
Definition checkbox.cpp:373
virtual bool isSelected() const
Checks if the check box is selected.
Definition checkbox.cpp:328
void drawDot(Graphics *graphics, Rectangle const &rec)
Draws the dot.
Definition checkbox.cpp:216
Color.
Definition color.hpp:56
uint8_t a
Alpha color component (0-255).
Definition color.hpp:322
virtual int getWidth(std::string const &text) const =0
Gets the width of a string.
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:57
virtual void popClipArea()
Removes the top most clip area from the stack.
Definition graphics.cpp:55
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:362
virtual bool pushClipArea(Rectangle area)
Pushes a clip area onto the stack.
Definition graphics.cpp:18
virtual void setFont(Font *font)
Sets the font to use when drawing text.
Definition graphics.cpp:79
virtual void drawLine(int x1, int y1, int x2, int y2)=0
Draws a line.
virtual void drawFillCircle(Point const &p, unsigned int radius)=0
Draws a filled circle.
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.
Image const * getInactiveDownImage() const
Gets inactive down image.
Image const * getUpImage() const
Gets current up image.
Image const * getDownImage() const
Gets current down image.
Image const * getHoverImage() const
Gets current hover image.
Image const * getInactiveHoverImage() const
Gets inactive hover image.
Abstract holder for image data.
Definition image.hpp:32
static Image * load(std::string const &filename, bool convertToDisplayFormat=true)
Loads an image by using the class' image loader.
Definition image.cpp:31
virtual int getWidth() const =0
Gets the width of the image.
void consume()
Marks the event as consumed.
Represents a key event.
Definition keyevent.hpp:22
Key const & getKey() const
Gets the key of the event.
Definition keyevent.cpp:39
Represents a keyboard key or character code.
Definition key.hpp:20
int getValue() const
Gets the value of the key.
Definition key.cpp:28
Represents a mouse event.
MouseEvent::Button getButton() const
Gets the button of the mouse event.
Represents a 2D coordinate (X, Y).
Definition point.hpp:29
Represents a rectangular area (X, Y, Width, Height).
Definition rectangle.hpp:20
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:596
int getWidth() const
Gets the width of the widget.
Definition widget.cpp:170
virtual bool isFocused() const
Checks if the widget is focused.
Definition widget.cpp:497
unsigned int getPaddingLeft() const
Gets the left padding.
Definition widget.cpp:477
void setSize(int width, int height)
Sets the size of the widget.
Definition widget.cpp:855
Color const & getBackgroundColor() const
Gets the background color.
Definition widget.cpp:616
virtual void drawBorder(Graphics *graphics)
Called when a widget have a border.
Definition widget.cpp:111
unsigned int getPaddingTop() const
Gets the top padding.
Definition widget.cpp:447
unsigned int getBorderSize() const
Gets the size of the widget's border.
Definition widget.cpp:381
virtual void drawSelectionFrame(Graphics *graphics)
Called when a widget is "active" and the selection mode is Frame or FrameWithBackground.
Definition widget.cpp:135
unsigned int getPaddingBottom() const
Gets the bottom padding.
Definition widget.cpp:467
Color const & getForegroundColor() const
Gets the foreground color.
Definition widget.cpp:606
SelectionMode getSelectionMode() const
Gets the selection mode.
Definition widget.cpp:656
Font * getFont() const
Gets the font set for the widget.
Definition widget.cpp:796
void distributeActionEvent()
Distributes an action event to all action listeners of the widget.
Definition widget.cpp:1113
int getHeight() const
Gets the height of the widget.
Definition widget.cpp:183
unsigned int getPaddingRight() const
Gets the right padding.
Definition widget.cpp:457
Color const & getSelectionColor() const
Gets the selection color.
Definition widget.cpp:626