6#include "fifechan/widget.hpp"
17#include "fifechan/defaultfont.hpp"
18#include "fifechan/events/actionevent.hpp"
19#include "fifechan/events/dragevent.hpp"
20#include "fifechan/events/event.hpp"
21#include "fifechan/exception.hpp"
22#include "fifechan/focushandler.hpp"
23#include "fifechan/graphics.hpp"
24#include "fifechan/listeners/actionlistener.hpp"
25#include "fifechan/listeners/deathlistener.hpp"
26#include "fifechan/listeners/droptargetlistener.hpp"
27#include "fifechan/listeners/keylistener.hpp"
28#include "fifechan/listeners/mouselistener.hpp"
29#include "fifechan/listeners/visibilityeventhandler.hpp"
30#include "fifechan/listeners/widgetlistener.hpp"
31#include "fifechan/rectangle.hpp"
32#include "fifechan/size.hpp"
38 std::list<Widget*>& widgetInstancesRegistry()
40 static std::list<Widget*> instances;
54 widgetInstancesRegistry().push_back(
this);
75 std::list<Widget*>::const_iterator childrenIter;
76 for (childrenIter =
mChildren.begin(); childrenIter !=
mChildren.end(); ++childrenIter) {
77 (*childrenIter)->_setParent(
nullptr);
82 std::list<DeathListener*>::const_iterator deathIter;
84 Event
const event(
this);
85 (*deathIter)->death(event);
91 Event
const event(
this);
110 if (modalMouse ==
this) {
114 if (modalFocus ==
this) {
122 widgetInstancesRegistry().remove(
this);
124 }
catch (fcn::Exception
const & e) {
125 std::cerr <<
"Exception caught in Widget destructor: " << e.
what() <<
'\n';
126 }
catch (std::exception
const & e) {
127 std::cerr <<
"Exception caught in Widget destructor: " << e.what() <<
'\n';
129 std::cerr <<
"Unknown exception caught in Widget destructor" <<
'\n';
136 Color highlightColor;
141 highlightColor = outlineColor + 0x303030;
142 highlightColor.
a = alpha;
143 shadowColor = outlineColor - 0x303030;
144 shadowColor.
a = alpha;
148 graphics->
drawLine(i, i, width - i, i);
149 graphics->
drawLine(i, i + 1, i, height - i - 1);
151 graphics->
drawLine(width - i, i + 1, width - i, height - i);
152 graphics->
drawLine(i, height - i, width - i - 1, height - i);
164 Color highlightColor;
169 highlightColor = borderColor + 0x303030;
170 highlightColor.
a = alpha;
171 shadowColor = borderColor - 0x303030;
172 shadowColor.
a = alpha;
177 if (style == BORDER_STYLE_FLAT) {
179 if ((sides & Widget::BORDER_TOP) != 0U) {
181 graphics->
drawLine(i, i, width - i, i);
183 if ((sides & Widget::BORDER_LEFT) != 0U) {
185 graphics->
drawLine(i, i + 1, i, height - i - 1);
187 if ((sides & Widget::BORDER_RIGHT) != 0U) {
189 graphics->
drawLine(width - i, i + 1, width - i, height - i);
191 if ((sides & Widget::BORDER_BOTTOM) != 0U) {
193 graphics->
drawLine(i, height - i, width - i - 1, height - i);
197 if ((sides & Widget::BORDER_TOP) != 0U) {
199 graphics->
drawLine(i, i, width - i, i);
201 if ((sides & Widget::BORDER_LEFT) != 0U) {
203 graphics->
drawLine(i, i + 1, i, height - i - 1);
205 if ((sides & Widget::BORDER_RIGHT) != 0U) {
207 graphics->
drawLine(width - i, i + 1, width - i, height - i);
209 if ((sides & Widget::BORDER_BOTTOM) != 0U) {
211 graphics->
drawLine(i, height - i, width - i - 1, height - i);
227 graphics->
drawLine(i, i, width - i, i);
228 graphics->
drawLine(i, i + 1, i, height - i - 1);
229 graphics->
drawLine(width - i, i + 1, width - i, height - i);
230 graphics->
drawLine(i, height - i, width - i - 1, height - i);
247 newDimension.
width = width;
260 newDimension.
height = height;
333 for (; currChild != endChildren; ++currChild) {
334 (*currChild)->distributeAncestorMovedEvent(
this);
341 unsigned int childs = 0;
344 for (; currChild != endChildren; ++currChild) {
352 unsigned int childs = 0;
355 for (; currChild != endChildren; ++currChild) {
356 if ((*currChild)->isVisible()) {
414 int const minWidth =
mMinSize.getWidth();
415 int const minHeight =
mMinSize.getHeight();
416 int const maxWidth =
mMaxSize.getWidth();
417 int const maxHeight =
mMaxSize.getHeight();
421 mDimension.width = std::max(std::min(currWidth, maxWidth), minWidth);
422 mDimension.height = std::max(std::min(currHeight, maxHeight), minHeight);
448 while ((widget->
getParent() !=
nullptr) && top) {
663 throwException(
"No focus handler is set (did you add the widget to the GUI?)");
696 if (visibilityEventHandler !=
nullptr) {
704 for (; currChild != endChildren; ++currChild) {
705 (*currChild)->distributeAncestorShownEvent(
this);
708 if (visibilityEventHandler !=
nullptr) {
716 for (; currChild != endChildren; ++currChild) {
717 (*currChild)->distributeAncestorHiddenEvent(
this);
820 if (focusHandler !=
nullptr) {
821 focusHandler->
add(
this);
830 std::list<Widget*>::const_iterator iter;
833 (*iter)->_setFocusHandler(focusHandler);
931 bool accepted =
false;
933 if (listener !=
nullptr && listener->dragEntered(event)) {
943 if (listener !=
nullptr) {
944 listener->dragExited(event);
952 if (listener !=
nullptr) {
953 listener->dragHovered(event);
961 if (listener !=
nullptr) {
962 listener->dragDropped(event);
1015 assert(
"Global font must not be null" && font !=
nullptr);
1018 std::list<Widget*>::iterator iter;
1019 for (iter = widgetInstancesRegistry().begin(); iter != widgetInstancesRegistry().end(); ++iter) {
1020 if ((*iter)->mCurrentFont ==
nullptr) {
1021 (*iter)->fontChanged();
1039 auto iter = std::ranges::find_if(widgetInstancesRegistry(), [widget](
Widget const * w) {
1042 return iter != widgetInstancesRegistry().end();
1068 newDimension.
width = width;
1069 newDimension.
height = height;
1087 throwException(
"No focus handler is set (did you add the widget to the GUI?)");
1096 throwException(
"No focus handler is set (did you add the widget to the GUI?)");
1105 throwException(
"No focus handler is set (did you add the widget to the GUI?)");
1118 throwException(
"No focus handler is set (did you add the widget to the GUI?)");
1139 std::list<Widget*>::reverse_iterator iter;
1141 Widget* widget = (*iter);
1168 return {0, 0, 0, 0};
1180 std::list<Widget*>::const_iterator iter;
1202 std::list<WidgetListener*>::const_iterator iter;
1204 Event const event(
this);
1205 (*iter)->widgetResized(event);
1211 std::list<WidgetListener*>::const_iterator iter;
1213 Event const event(
this);
1214 (*iter)->widgetMoved(event);
1220 std::list<WidgetListener*>::const_iterator iter;
1222 Event const event(
this);
1223 (*iter)->widgetHidden(event);
1231 Event const event(ancestor);
1233 for (; currWidgetListener != endWidgetListeners; ++currWidgetListener) {
1234 (*currWidgetListener)->ancestorMoved(event);
1238 auto const endChildren(
mChildren.end());
1240 for (; currChild != endChildren; ++currChild) {
1241 (*currChild)->distributeAncestorMovedEvent(ancestor);
1254 Event const event(ancestor);
1256 for (; currWidgetListener != endWidgetListeners; ++currWidgetListener) {
1257 (*currWidgetListener)->ancestorHidden(event);
1261 auto const endChildren(
mChildren.end());
1263 for (; currChild != endChildren; ++currChild) {
1264 (*currChild)->distributeAncestorHiddenEvent(ancestor);
1277 Event const event(ancestor);
1279 for (; currWidgetListener != endWidgetListeners; ++currWidgetListener) {
1280 (*currWidgetListener)->ancestorShown(event);
1284 auto const endChildren(
mChildren.end());
1286 for (; currChild != endChildren; ++currChild) {
1287 (*currChild)->distributeAncestorShownEvent(ancestor);
1293 std::list<ActionListener*>::const_iterator iter;
1296 (*iter)->action(actionEvent);
1302 std::list<WidgetListener*>::const_iterator iter;
1304 Event const event(
this);
1305 (*iter)->widgetShown(event);
1312 mParent->showWidgetPart(
this, rectangle);
1325 while (parent !=
nullptr) {
1335 std::list<Widget*> result;
1337 std::ranges::copy_if(
mChildren, std::back_inserter(result), [&](
auto const & widget) {
1348 std::list<Widget*>::const_iterator iter;
1350 Widget const * widget = (*iter);
1360 std::list<Widget*>::const_iterator iter;
1362 Widget* widget = (*iter);
1364 if (widget->
getId() ==
id) {
1370 if (child !=
nullptr) {
1382 area.
x += widget->
getX();
1383 area.
y += widget->
getY();
1404 std::list<Widget*>::const_iterator iter;
1406 Widget* widget = (*iter);
1424 auto it = std::ranges::find(
mChildren, widget);
1426 if (it == std::ranges::end(
mChildren)) {
1466 std::list<Widget*>::iterator iter;
1467 iter = std::ranges::find(
mChildren, widget);
1479 std::list<Widget*>::iterator iter;
1480 iter = std::ranges::find(
mChildren, widget);
1496 auto focused = std::ranges::find_if(
mChildren, [](
auto* w) {
1497 return w->isFocused();
1500 auto next = (focused == std::ranges::end(
mChildren)) ? std::ranges::begin(
mChildren) : std::next(focused);
1502 auto it = std::ranges::find_if(next, std::ranges::end(
mChildren), [](
auto* w) {
1503 return w->isFocusable();
1506 if (it == std::ranges::end(
mChildren)) {
1507 it = std::ranges::find_if(std::ranges::begin(
mChildren), next, [](
auto* w) {
1508 return w->isFocusable();
1513 (*it)->requestFocus();
1523 auto rev = std::ranges::reverse_view(
mChildren);
1525 auto focused = std::ranges::find_if(rev, [](
auto* w) {
1526 return w->isFocused();
1529 auto next = (focused == std::ranges::end(rev)) ? std::ranges::begin(rev) : std::next(focused);
1531 auto rit = std::ranges::find_if(next, std::ranges::end(rev), [](
auto* w) {
1532 return w->isFocusable();
1535 if (rit == std::ranges::end(rev)) {
1536 rit = std::ranges::find_if(std::ranges::begin(rev), next, [](
auto* w) {
1537 return w->isFocusable();
1542 (*rit)->requestFocus();
1570 if (widget->isVisible() && childrenArea.
isIntersecting(widget->getDimension())) {
1571 widget->_draw(graphics);
1583 std::list<Widget*>::const_iterator iter;
1641 if (ancestor ==
nullptr) {
1644 Widget const * current =
this;
1645 while (current !=
nullptr) {
1646 if (current == ancestor) {
Represents an action trigger (e.g., button click).
Interface for listening to action events from widgets.
uint8_t a
Alpha color component (0-255).
Interface for listening to widget destruction events.
A basic font implementation capable only of drawing rectangles (placeholder).
Drag and drop event type container.
Listener interface for widgets that accept dragged payloads.
Base class for all GUI event objects.
char const * what() const noexcept override
Returns a pointer to a null-terminated string with a description of the exception.
Manages focus navigation and assignment among widgets within a Gui instance.
virtual void add(Widget *widget)
Adds a widget to by handles by the focus handler.
Interface for listening to focus gain/loss events.
Abstract interface for font rendering.
Abstract interface providing primitive drawing functions (lines, rectangles, etc.).
virtual void popClipArea()
Removes the top most clip area from the stack.
virtual bool pushClipArea(Rectangle area)
Pushes a clip area onto the stack.
virtual void drawLine(int x1, int y1, int x2, int y2)=0
Draws a line.
virtual void setColor(Color const &color)=0
Sets the color to use when drawing.
Interface for listening to keyboard events.
Represents a mouse event.
int getX() const
Gets the x coordinate of the mouse event.
int getY() const
Gets the y coordinate of the mouse event.
Interface for listening to mouse events.
Represents a rectangular area (X, Y, Width, Height).
bool isContaining(int x, int y) const
Checks the rectangle contains a point.
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.
bool isIntersecting(Rectangle const &rectangle) const
Checks if another rectangle intersects with the rectangle.
Represents dimensions defined by width and height.
Handles changes in widget visibility states.
void widgetHidden(Event const &e) override
Informs gui that a widget was hidden.
void widgetShown(Event const &e) override
Informs gui that a widget was shown.
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.