Added drag and drop functionality for Widgets

This commit is contained in:
OmniaX-Dev 2026-04-06 14:39:51 +02:00
parent 260c7054bc
commit d4b4df1e51
17 changed files with 630 additions and 369 deletions

View file

@ -1,3 +1,2 @@
CompileFlags: CompileFlags:
CompilationDatabase: bin CompilationDatabase: bin
Add: ["--target=x86_64-w64-mingw32"]

View file

@ -89,11 +89,13 @@ list(APPEND OGFX_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/RawTextInput.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/RawTextInput.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/Window.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/Window.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/WindowOutputHandler.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/WindowOutputHandler.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/WidgetManager.cpp
# gui/widgets # gui/widgets
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Widget.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Widget.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Containers.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Containers.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Label.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Label.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/RootWidget.cpp
# render # render
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/render/BasicRenderer.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/render/BasicRenderer.cpp

View file

@ -42,11 +42,6 @@ window.backgroundColor = Color(rgba(120, 120, 120, 255))
borderColor = Color(#208080FF) borderColor = Color(#208080FF)
} }
% (@testLabel2 label:pressed [mouseButton=left or mouseButton=right]) {
% ...
(@testLabel2 label:pressed) { (@testLabel2 label:pressed) {
showBackground = true showBackground = true
} }

View file

@ -8,7 +8,6 @@ Add theme caching
Implement mouse scroll callback Implement mouse scroll callback
Implement a way to determine on what widget (in the hierarchy chain) and event must stop Implement a way to determine on what widget (in the hierarchy chain) and event must stop
Implement margin for widgets Implement margin for widgets
Implement conditional statements for stylesheet rules
Implement following widgets: Implement following widgets:

View file

@ -1 +1 @@
2049 2050

View file

@ -78,12 +78,28 @@ namespace ogfx
eKeyEvent eventType; eKeyEvent eventType;
WindowCore& parentWindow; WindowCore& parentWindow;
}; };
class DropEventData : public ostd::BaseObject
{
public: enum class eDropType { None = 0, File, Text, InApp };
public:
inline DropEventData(WindowCore& parent, eDropType type) : parentWindow(parent), dropType(type)
{
setTypeName("ogfx::DropEventData");
validate();
}
public:
eDropType dropType;
WindowCore& parentWindow;
ostd::String textOrFilePath { "" };
ostd::BaseObject* userObject { nullptr };
};
namespace gui namespace gui
{ {
class Event class Event
{ {
public: public:
inline Event(WindowCore& _window) : window(_window) { } inline Event(WindowCore& _window) : window(_window), drop(window, DropEventData::eDropType::None) { }
inline void handle(void) { m_handled = true; } inline void handle(void) { m_handled = true; }
inline bool isHandled(void) const { return m_handled; } inline bool isHandled(void) const { return m_handled; }
@ -92,6 +108,8 @@ namespace ogfx
WindowResizedData* windowResized { nullptr }; WindowResizedData* windowResized { nullptr };
MouseEventData* mouse { nullptr }; MouseEventData* mouse { nullptr };
KeyEventData* keyboard { nullptr }; KeyEventData* keyboard { nullptr };
DropEventData drop;
uint32_t __original_signal_id { 0 };
private: private:
bool m_handled { false }; bool m_handled { false };

View file

@ -0,0 +1,317 @@
/*
OmniaFramework - A collection of useful functionality
Copyright (C) 2025 OmniaX-Dev
This file is part of OmniaFramework.
OmniaFramework is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OmniaFramework is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
*/
#include "WidgetManager.hpp"
#include "widgets/Widget.hpp"
#include "../render/BasicRenderer.hpp"
#include "../utils/Keycodes.hpp"
namespace ogfx
{
namespace gui
{
WidgetManager::WidgetManager(WindowCore& window, Widget& owner) : m_window(window), m_owner(owner)
{
//
}
bool WidgetManager::hasWidget(Widget& widget)
{
bool found = std::ranges::find(m_widgetList, &widget) != m_widgetList.end();
return found && widget.isValid();
}
bool WidgetManager::requestFocus(Widget& widget)
{
if (!hasWidget(widget)) return false;
if (&widget == m_focused) return true;
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
if (w->m_focused)
{
w->m_focused = false;
w->onFocusLost(Event(m_window));
w->setThemeQualifier("focused", false);
}
else
w->m_focused = false;
}
widget.m_focused = true;
widget.onFocusGained(Event(m_window));
widget.setThemeQualifier("focused", true);
m_focused = &widget;
return true;
}
bool WidgetManager::addWidget(Widget& widget)
{
if (hasWidget(widget)) return false;
widget.m_parent = &m_owner;
m_widgetList.push_back(&widget);
std::ranges::sort(m_widgetList, {}, [](Widget* w) {
return w->m_zIndex;
});
return true;
}
Widget* WidgetManager::focusNext(void)
{
if (m_widgetList.empty())
return nullptr;
Widget* next = nullptr;
Widget* smallest = nullptr;
int32_t currentTabIndex = (m_focused != nullptr ? m_focused->m_tabIndex : std::numeric_limits<int32_t>::max());
for (Widget* w : m_widgetList)
{
int tab_i = w->m_tabIndex;
if (tab_i < 0) continue;
if (!smallest || tab_i < smallest->m_tabIndex)
smallest = w;
if (tab_i > currentTabIndex)
{
if (!next || tab_i < next->m_tabIndex)
next = w;
}
}
Widget* w = next ? next : smallest;
requestFocus(*w);
return w;
}
void WidgetManager::draw(ogfx::BasicRenderer2D& gfx)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
gfx.pushClippingRect({ w->getGlobalPosition(), w->getSize() }, true);
w->__draw(gfx);
gfx.popClippingRect();
}
}
void WidgetManager::update(void)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
w->__update();
}
}
void WidgetManager::onThemeApplied(const ostd::Stylesheet& theme)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
w->__applyTheme(theme, true);
}
}
void WidgetManager::onMousePressed(const Event& event)
{
for (int32_t i = m_widgetList.size() - 1; i >= 0; i--)
{
Widget* w = m_widgetList[i];
if (w == nullptr) continue;
if (w->isInvalid()) continue;
if (!w->contains(event.mouse->position_x, event.mouse->position_y, true))
continue;
w->__onMousePressed(event);
m_mousePressedOnWidget = w;
if (event.isHandled() || w->m_stopEvents)
break;
}
}
void WidgetManager::onMouseReleased(const Event& event)
{
if (m_mousePressedOnWidget != nullptr)
{
event.mouse->mousePressedOnWidget = m_mousePressedOnWidget;
m_mousePressedOnWidget->__onMouseReleased(event);
// processDragAndDrop(m_mousePressedOnWidget, event);
}
for (int32_t i = m_widgetList.size() - 1; i >= 0; i--)
{
Widget* w = m_widgetList[i];
if (w == nullptr) continue;
if (w->isInvalid()) continue;
if (w == m_mousePressedOnWidget) continue;
event.mouse->mousePressedOnWidget = m_mousePressedOnWidget;
w->__onMouseReleased(event);
processDragAndDrop(w, event);
// requestFocus(*w);
if (w->isMouseInside() && w->m_stopEvents)
break;
}
m_mousePressedOnWidget = nullptr;
}
void WidgetManager::onMouseMoved(const Event& event)
{
for (int32_t i = m_widgetList.size() - 1; i >= 0; i--)
{
Widget* w = m_widgetList[i];
if (w == nullptr) continue;
if (w->isInvalid()) continue;
if (!w->contains(event.mouse->position_x, event.mouse->position_y, true))
{
if (w->m_mouseInside)
{
w->m_mouseInside = false;
w->__onMouseExited(event);
}
continue;
}
if (!w->m_mouseInside)
{
w->m_mouseInside = true;
w->__onMouseEntered(event);
}
else
{
if (w->m_pressedButton != ogfx::MouseEventData::eButton::None)
w->__onMouseDragged(event);
else
w->__onMouseMoved(event);
}
if (event.isHandled() || w->m_stopEvents)
{
bool mouseOut = false;
for (int32_t j = i - 1; j >= 0; j--)
{
Widget* ww = m_widgetList[j];
if (ww->m_mouseInside)
{
ww->m_mouseInside = false;
ww->__onMouseExited(event);
}
}
break;
}
}
}
void WidgetManager::onMouseDragged(const Event& event)
{
for (int32_t i = m_widgetList.size() - 1; i >= 0; i--)
{
Widget* w = m_widgetList[i];
if (w == nullptr) continue;
if (w->isInvalid()) continue;
if (!w->contains(event.mouse->position_x, event.mouse->position_y, true))
continue;
w->__onMouseDragged(event);
if (event.isHandled())
break;
}
}
void WidgetManager::onKeyPressed(const Event& event)
{
if (!m_focused) return;
m_focused->__onKeyPressed(event);
}
void WidgetManager::onKeyReleased(const Event& event)
{
if (!m_focused) return;
m_focused->__onKeyReleased(event);
if (m_tabNavigationEnabled && event.keyboard->keyCode == KeyCode::Tab)
focusNext();
}
void WidgetManager::onTextEntered(const Event& event)
{
if (!m_focused) return;
m_focused->__onTextEntered(event);
}
void WidgetManager::onWindowClosed(const Event& event)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
w->__onWindowClosed(event);
if (event.isHandled())
break;
}
}
void WidgetManager::onWindowResized(const Event& event)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
w->__onWindowResized(event);
if (event.isHandled())
break;
}
}
void WidgetManager::onWindowFocused(const Event& event)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
w->__onWindowFocused(event);
if (event.isHandled())
break;
}
}
void WidgetManager::onWindowFocusLost(const Event& event)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
w->__onWindowFocusLost(event);
if (event.isHandled())
break;
}
}
void WidgetManager::processDragAndDrop(Widget* widget, const Event& event)
{
if (widget == nullptr) return;
if (!widget->isDragAndDropEnabled()) return;
if (!widget->isMouseInside()) return;
if (Widget::s_dragAndDropData != nullptr)
{
widget->__onDragAndDrop(event);
Widget::clearDragAndDropData();
}
auto& const_cast_event = const_cast<Event&>(event);
// if (event.__original_signal_id == ostd::BuiltinSignals::TextDragAndDropped)
}
}
}

View file

@ -0,0 +1,76 @@
/*
OmniaFramework - A collection of useful functionality
Copyright (C) 2025 OmniaX-Dev
This file is part of OmniaFramework.
OmniaFramework is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OmniaFramework is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <ostd/string/String.hpp>
namespace ostd
{
class Stylesheet;
}
namespace ogfx
{
class BasicRenderer2D;
class WindowCore;
namespace gui
{
class Event;
class Widget;
class WidgetManager
{
public:
WidgetManager(WindowCore& window, Widget& owner);
bool hasWidget(Widget& widget);
bool requestFocus(Widget& widget);
bool addWidget(Widget& widget);
Widget* focusNext(void);
void draw(ogfx::BasicRenderer2D& gfx);
void update(void);
void onThemeApplied(const ostd::Stylesheet& theme);
void onMousePressed(const Event& event);
void onMouseReleased(const Event& event);
void onMouseMoved(const Event& event);
void onMouseDragged(const Event& event);
void onKeyPressed(const Event& event);
void onKeyReleased(const Event& event);
void onTextEntered(const Event& event);
void onWindowClosed(const Event& event);
void onWindowResized(const Event& event);
void onWindowFocused(const Event& event);
void onWindowFocusLost(const Event& event);
inline int32_t widgetCount(void) const { return m_widgetList.size(); }
inline WindowCore& getWindow(void) { return m_window; }
private:
void processDragAndDrop(Widget* widget, const Event& event);
private:
WindowCore& m_window;
Widget& m_owner;
std::vector<Widget*> m_widgetList;
Widget* m_focused { nullptr };
bool m_tabNavigationEnabled { true };
Widget* m_mousePressedOnWidget { nullptr };
};
}
}

View file

@ -21,6 +21,7 @@
#include "Window.hpp" #include "Window.hpp"
#include "../../ostd/utils/Time.hpp" #include "../../ostd/utils/Time.hpp"
#include "utils/Keycodes.hpp" #include "utils/Keycodes.hpp"
#include <SDL3/SDL_events.h>
namespace ogfx namespace ogfx
{ {
@ -336,6 +337,18 @@ namespace ogfx
{ {
close(); close();
} }
else if (event.type == SDL_EVENT_DROP_FILE)
{
DropEventData ded(*this, DropEventData::eDropType::File);
ded.textOrFilePath = event.drop.data;
ostd::SignalHandler::emitSignal(ostd::BuiltinSignals::FileDragAndDropped, ostd::Signal::Priority::RealTime, ded);
}
else if (event.type == SDL_EVENT_DROP_TEXT)
{
DropEventData ded(*this, DropEventData::eDropType::Text);
ded.textOrFilePath = event.drop.data;
ostd::SignalHandler::emitSignal(ostd::BuiltinSignals::FileDragAndDropped, ostd::Signal::Priority::RealTime, ded);
}
else if (event.type == SDL_EVENT_WINDOW_FOCUS_GAINED) else if (event.type == SDL_EVENT_WINDOW_FOCUS_GAINED)
{ {
ostd::SignalHandler::emitSignal(ostd::BuiltinSignals::WindowFocused, ostd::Signal::Priority::RealTime, *this); ostd::SignalHandler::emitSignal(ostd::BuiltinSignals::WindowFocused, ostd::Signal::Priority::RealTime, *this);
@ -497,46 +510,74 @@ namespace ogfx
void Window::__on_signal(ostd::Signal& signal) void Window::__on_signal(ostd::Signal& signal)
{ {
Event evt(*this); Event evt(*this);
evt.__original_signal_id = ostd::BuiltinSignals::NoSignal;
if (signal.ID == ostd::BuiltinSignals::WindowClosed) if (signal.ID == ostd::BuiltinSignals::WindowClosed)
{ {
evt.__original_signal_id = ostd::BuiltinSignals::WindowClosed;
m_rootWidget.__onWindowClosed(evt); m_rootWidget.__onWindowClosed(evt);
} }
else if (signal.ID == ostd::BuiltinSignals::WindowFocused) else if (signal.ID == ostd::BuiltinSignals::WindowFocused)
{ {
m_rootWidget.__onWIndowFocused(evt); evt.__original_signal_id = ostd::BuiltinSignals::WindowFocused;
m_rootWidget.__onWindowFocused(evt);
} }
else if (signal.ID == ostd::BuiltinSignals::WindowLostFocus) else if (signal.ID == ostd::BuiltinSignals::WindowLostFocus)
{ {
evt.__original_signal_id = ostd::BuiltinSignals::WindowLostFocus;
m_rootWidget.__onWindowFocusLost(evt); m_rootWidget.__onWindowFocusLost(evt);
} }
else if (signal.ID == ostd::BuiltinSignals::FileDragAndDropped)
{
auto& ud = (ogfx::DropEventData&)signal.userData;
evt.drop.dropType = ud.dropType;
evt.drop.userObject = ud.userObject;
evt.drop.textOrFilePath = ud.textOrFilePath;
evt.__original_signal_id = ostd::BuiltinSignals::FileDragAndDropped;
m_rootWidget.__onDragAndDrop(evt);
}
else if (signal.ID == ostd::BuiltinSignals::TextDragAndDropped)
{
auto& ud = (ogfx::DropEventData&)signal.userData;
evt.drop.dropType = ud.dropType;
evt.drop.userObject = ud.userObject;
evt.drop.textOrFilePath = ud.textOrFilePath;
evt.__original_signal_id = ostd::BuiltinSignals::TextDragAndDropped;
m_rootWidget.__onDragAndDrop(evt);
}
else if (signal.ID == ostd::BuiltinSignals::WindowResized) else if (signal.ID == ostd::BuiltinSignals::WindowResized)
{ {
evt.windowResized = &(ogfx::WindowResizedData&)signal.userData; evt.windowResized = &(ogfx::WindowResizedData&)signal.userData;
evt.__original_signal_id = ostd::BuiltinSignals::WindowResized;
m_rootWidget.__onWindowResized(evt); m_rootWidget.__onWindowResized(evt);
} }
else if (signal.ID == ostd::BuiltinSignals::MouseMoved) else if (signal.ID == ostd::BuiltinSignals::MouseMoved)
{ {
evt.mouse = &(ogfx::MouseEventData&)signal.userData; evt.mouse = &(ogfx::MouseEventData&)signal.userData;
evt.__original_signal_id = ostd::BuiltinSignals::MouseMoved;
m_rootWidget.__onMouseMoved(evt); m_rootWidget.__onMouseMoved(evt);
} }
else if (signal.ID == ostd::BuiltinSignals::MousePressed) else if (signal.ID == ostd::BuiltinSignals::MousePressed)
{ {
evt.mouse = &(ogfx::MouseEventData&)signal.userData; evt.mouse = &(ogfx::MouseEventData&)signal.userData;
evt.__original_signal_id = ostd::BuiltinSignals::MousePressed;
m_rootWidget.__onMousePressed(evt); m_rootWidget.__onMousePressed(evt);
} }
else if (signal.ID == ostd::BuiltinSignals::MouseReleased) else if (signal.ID == ostd::BuiltinSignals::MouseReleased)
{ {
evt.mouse = &(ogfx::MouseEventData&)signal.userData; evt.mouse = &(ogfx::MouseEventData&)signal.userData;
evt.__original_signal_id = ostd::BuiltinSignals::MouseReleased;
m_rootWidget.__onMouseReleased(evt); m_rootWidget.__onMouseReleased(evt);
} }
else if (signal.ID == ostd::BuiltinSignals::KeyPressed) else if (signal.ID == ostd::BuiltinSignals::KeyPressed)
{ {
evt.keyboard = &(ogfx::KeyEventData&)signal.userData; evt.keyboard = &(ogfx::KeyEventData&)signal.userData;
evt.__original_signal_id = ostd::BuiltinSignals::KeyPressed;
m_rootWidget.__onKeyPressed(evt); m_rootWidget.__onKeyPressed(evt);
} }
else if (signal.ID == ostd::BuiltinSignals::KeyReleased) else if (signal.ID == ostd::BuiltinSignals::KeyReleased)
{ {
evt.keyboard = &(ogfx::KeyEventData&)signal.userData; evt.keyboard = &(ogfx::KeyEventData&)signal.userData;
evt.__original_signal_id = ostd::BuiltinSignals::KeyReleased;
m_rootWidget.__onKeyReleased(evt); m_rootWidget.__onKeyReleased(evt);
if (evt.keyboard->keyCode == KeyCode::Escape) if (evt.keyboard->keyCode == KeyCode::Escape)
close(); close();
@ -544,6 +585,7 @@ namespace ogfx
else if (signal.ID == ostd::BuiltinSignals::TextEntered) else if (signal.ID == ostd::BuiltinSignals::TextEntered)
{ {
evt.keyboard = &(ogfx::KeyEventData&)signal.userData; evt.keyboard = &(ogfx::KeyEventData&)signal.userData;
evt.__original_signal_id = ostd::BuiltinSignals::TextEntered;
m_rootWidget.__onTextEntered(evt); m_rootWidget.__onTextEntered(evt);
} }
onSignal(signal); onSignal(signal);

View file

@ -26,6 +26,7 @@
#include <ostd/io/IOHandlers.hpp> #include <ostd/io/IOHandlers.hpp>
#include <ogfx/gui/Events.hpp> #include <ogfx/gui/Events.hpp>
#include <ogfx/gui/widgets/Widget.hpp> #include <ogfx/gui/widgets/Widget.hpp>
#include <ogfx/gui/widgets/RootWidget.hpp>
#include <ogfx/render/BasicRenderer.hpp> #include <ogfx/render/BasicRenderer.hpp>
#include <ogfx/gui/WindowOutputHandler.hpp> #include <ogfx/gui/WindowOutputHandler.hpp>

View file

@ -0,0 +1,55 @@
/*
OmniaFramework - A collection of useful functionality
Copyright (C) 2025 OmniaX-Dev
This file is part of OmniaFramework.
OmniaFramework is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OmniaFramework is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
*/
#include "RootWidget.hpp"
#include "../../render/BasicRenderer.hpp"
#include "../Window.hpp"
namespace ogfx
{
namespace gui
{
namespace widgets
{
RootWidget::RootWidget(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window)
{
disableDrawBox();
m_rootChild = true;
setSize(static_cast<float>(window.getWindowWidth()), static_cast<float>(window.getWindowHeight()));
setTypeName("ogfx::gui::widgets::RootWidget");
}
void RootWidget::onWindowResized(const Event& event)
{
setSize(static_cast<float>(event.windowResized->new_width), static_cast<float>(event.windowResized->new_height));
}
void RootWidget::applyTheme(const ostd::Stylesheet& theme)
{
m_color = getThemeValue<ostd::Color>(theme, "window.backgroundColor", getWindow().getClearColor());
}
void RootWidget::onDraw(ogfx::BasicRenderer2D& gfx)
{
gfx.fillRect({ 0, 0, static_cast<float>(getWindow().getWindowWidth()), static_cast<float>(getWindow().getWindowHeight()) }, m_color);
}
}
}
}

View file

@ -0,0 +1,44 @@
/*
OmniaFramework - A collection of useful functionality
Copyright (C) 2025 OmniaX-Dev
This file is part of OmniaFramework.
OmniaFramework is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OmniaFramework is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <ogfx/gui/widgets/Widget.hpp>
namespace ogfx
{
namespace gui
{
namespace widgets
{
class RootWidget : public Widget
{
public:
RootWidget(WindowCore& window);
void onWindowResized(const Event& event) override;
void applyTheme(const ostd::Stylesheet& theme) override;
void onDraw(ogfx::BasicRenderer2D& gfx) override;
private:
ostd::Color m_color { ostd::Colors::Transparent };
};
}
}
}

View file

@ -21,7 +21,6 @@
#include "Widget.hpp" #include "Widget.hpp"
#include "gui/Events.hpp" #include "gui/Events.hpp"
#include "io/Memory.hpp" #include "io/Memory.hpp"
#include "utils/Keycodes.hpp"
#include "../..//render/BasicRenderer.hpp" #include "../..//render/BasicRenderer.hpp"
#include "../Window.hpp" #include "../Window.hpp"
@ -29,273 +28,6 @@ namespace ogfx
{ {
namespace gui namespace gui
{ {
WidgetManager::WidgetManager(WindowCore& window, Widget& owner) : m_window(window), m_owner(owner)
{
//
}
bool WidgetManager::hasWidget(Widget& widget)
{
bool found = std::ranges::find(m_widgetList, &widget) != m_widgetList.end();
return found && widget.isValid();
}
bool WidgetManager::requestFocus(Widget& widget)
{
if (!hasWidget(widget)) return false;
if (&widget == m_focused) return true;
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
if (w->m_focused)
{
w->m_focused = false;
w->onFocusLost(Event(m_window));
w->setThemeQualifier("focused", true);
}
else
w->m_focused = false;
}
widget.m_focused = true;
widget.onFocusGained(Event(m_window));
widget.setThemeQualifier("focused", true);
m_focused = &widget;
return true;
}
bool WidgetManager::addWidget(Widget& widget)
{
if (hasWidget(widget)) return false;
widget.m_parent = &m_owner;
m_widgetList.push_back(&widget);
std::ranges::sort(m_widgetList, {}, [](Widget* w) {
return w->m_zIndex;
});
return true;
}
Widget* WidgetManager::focusNext(void)
{
if (m_widgetList.empty())
return nullptr;
Widget* next = nullptr;
Widget* smallest = nullptr;
int32_t currentTabIndex = (m_focused != nullptr ? m_focused->m_tabIndex : std::numeric_limits<int32_t>::max());
for (Widget* w : m_widgetList)
{
int tab_i = w->m_tabIndex;
if (tab_i < 0) continue;
if (!smallest || tab_i < smallest->m_tabIndex)
smallest = w;
if (tab_i > currentTabIndex)
{
if (!next || tab_i < next->m_tabIndex)
next = w;
}
}
Widget* w = next ? next : smallest;
requestFocus(*w);
return w;
}
void WidgetManager::draw(ogfx::BasicRenderer2D& gfx)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
gfx.pushClippingRect({ w->getGlobalPosition(), w->getSize() }, true);
w->__draw(gfx);
gfx.popClippingRect();
}
}
void WidgetManager::update(void)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
w->__update();
}
}
void WidgetManager::onThemeApplied(const ostd::Stylesheet& theme)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
w->__applyTheme(theme, true);
}
}
void WidgetManager::onMousePressed(const Event& event)
{
for (int32_t i = m_widgetList.size() - 1; i >= 0; i--)
{
Widget* w = m_widgetList[i];
if (w == nullptr) continue;
if (w->isInvalid()) continue;
if (!w->contains(event.mouse->position_x, event.mouse->position_y, true))
continue;
w->__onMousePressed(event);
m_mousePressedOnWidget = w;
if (event.isHandled() || w->m_stopEvents)
break;
}
}
void WidgetManager::onMouseReleased(const Event& event)
{
for (int32_t i = m_widgetList.size() - 1; i >= 0; i--)
{
Widget* w = m_widgetList[i];
if (w == nullptr) continue;
if (w->isInvalid()) continue;
event.mouse->mousePressedOnWidget = m_mousePressedOnWidget;
w->__onMouseReleased(event);
requestFocus(*w);
m_mousePressedOnWidget = nullptr;
if (event.isHandled())
break;
}
}
void WidgetManager::onMouseMoved(const Event& event)
{
for (int32_t i = m_widgetList.size() - 1; i >= 0; i--)
{
Widget* w = m_widgetList[i];
if (w == nullptr) continue;
if (w->isInvalid()) continue;
if (!w->contains(event.mouse->position_x, event.mouse->position_y, true))
{
if (w->m_mouseInside)
{
w->m_mouseInside = false;
w->__onMouseExited(event);
}
continue;
}
if (!w->m_mouseInside)
{
w->m_mouseInside = true;
w->__onMouseEntered(event);
}
else
{
if (w->m_pressedButton != ogfx::MouseEventData::eButton::None)
w->__onMouseDragged(event);
else
w->__onMouseMoved(event);
}
if (event.isHandled() || w->m_stopEvents)
{
bool mouseOut = false;
for (int32_t j = i - 1; j >= 0; j--)
{
Widget* ww = m_widgetList[j];
if (ww->m_mouseInside)
{
ww->m_mouseInside = false;
ww->__onMouseExited(event);
}
}
break;
}
}
}
void WidgetManager::onMouseDragged(const Event& event)
{
for (int32_t i = m_widgetList.size() - 1; i >= 0; i--)
{
Widget* w = m_widgetList[i];
if (w == nullptr) continue;
if (w->isInvalid()) continue;
if (!w->contains(event.mouse->position_x, event.mouse->position_y, true))
continue;
w->__onMouseDragged(event);
if (event.isHandled())
break;
}
}
void WidgetManager::onKeyPressed(const Event& event)
{
if (!m_focused) return;
m_focused->__onKeyPressed(event);
}
void WidgetManager::onKeyReleased(const Event& event)
{
if (!m_focused) return;
m_focused->__onKeyReleased(event);
if (m_tabNavigationEnabled && event.keyboard->keyCode == KeyCode::Tab)
focusNext();
}
void WidgetManager::onTextEntered(const Event& event)
{
if (!m_focused) return;
m_focused->__onTextEntered(event);
}
void WidgetManager::onWindowClosed(const Event& event)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
w->__onWindowClosed(event);
if (event.isHandled())
break;
}
}
void WidgetManager::onWindowResized(const Event& event)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
w->__onWindowResized(event);
if (event.isHandled())
break;
}
}
void WidgetManager::onWindowFocused(const Event& event)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
w->__onWIndowFocused(event);
if (event.isHandled())
break;
}
}
void WidgetManager::onWindowFocusLost(const Event& event)
{
for (auto& w : m_widgetList)
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
w->__onWindowFocusLost(event);
if (event.isHandled())
break;
}
}
Widget::Widget(const ostd::Rectangle& bounds, WindowCore& window) : Rectangle(bounds), m_widgets(window, *this) Widget::Widget(const ostd::Rectangle& bounds, WindowCore& window) : Rectangle(bounds), m_widgets(window, *this)
{ {
m_window = &window; m_window = &window;
@ -403,7 +135,7 @@ namespace ogfx
} }
} }
bool Widget::getThemeQualifier(const ostd::String& qualifier) bool Widget::getThemeQualifier(const ostd::String& qualifier) const
{ {
for (auto& [name, state] : m_qualifierList) for (auto& [name, state] : m_qualifierList)
{ {
@ -473,6 +205,18 @@ namespace ogfx
} }
} }
void Widget::__onDragAndDrop(const Event& event)
{
// if (hasChildren())
// m_widgets.onMouseReleased(event);
if (!event.isHandled())
{
if (callback_onDragAndDrop)
callback_onDragAndDrop(event);
onDragAndDrop(event);
}
}
void Widget::__onMouseMoved(const Event& event) void Widget::__onMouseMoved(const Event& event)
{ {
if (hasChildren()) if (hasChildren())
@ -574,7 +318,7 @@ namespace ogfx
} }
} }
void Widget::__onWIndowFocused(const Event& event) void Widget::__onWindowFocused(const Event& event)
{ {
if (hasChildren()) if (hasChildren())
m_widgets.onWindowFocused(event); m_widgets.onWindowFocused(event);
@ -604,33 +348,5 @@ namespace ogfx
m_widgets.onThemeApplied(theme); m_widgets.onThemeApplied(theme);
applyTheme(theme); applyTheme(theme);
} }
namespace widgets
{
RootWidget::RootWidget(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window)
{
disableDrawBox();
m_rootChild = true;
setSize(static_cast<float>(window.getWindowWidth()), static_cast<float>(window.getWindowHeight()));
setTypeName("ogfx::gui::widgets::RootWidget");
}
void RootWidget::onWindowResized(const Event& event)
{
setSize(static_cast<float>(event.windowResized->new_width), static_cast<float>(event.windowResized->new_height));
}
void RootWidget::applyTheme(const ostd::Stylesheet& theme)
{
m_color = getThemeValue<ostd::Color>(theme, "window.backgroundColor", getWindow().getClearColor());
}
void RootWidget::onDraw(ogfx::BasicRenderer2D& gfx)
{
gfx.fillRect({ 0, 0, static_cast<float>(getWindow().getWindowWidth()), static_cast<float>(getWindow().getWindowHeight()) }, m_color);
}
}
} }
} }

View file

@ -21,56 +21,16 @@
#pragma once #pragma once
#include <ogfx/gui/Events.hpp> #include <ogfx/gui/Events.hpp>
#include <ogfx/gui/WidgetManager.hpp>
#include <ostd/data/BaseObject.hpp> #include <ostd/data/BaseObject.hpp>
#include <ostd/math/Geometry.hpp> #include <ostd/math/Geometry.hpp>
#include <ostd/data/Color.hpp>
#include <ostd/io/Stylesheet.hpp> #include <ostd/io/Stylesheet.hpp>
#include <ostd/utils/Time.hpp>
#include <functional> #include <functional>
namespace ogfx namespace ogfx
{ {
class BasicRenderer2D;
class WindowCore;
namespace gui namespace gui
{ {
class Event;
class Widget;
class WidgetManager
{
public:
WidgetManager(WindowCore& window, Widget& owner);
bool hasWidget(Widget& widget);
bool requestFocus(Widget& widget);
bool addWidget(Widget& widget);
Widget* focusNext(void);
void draw(ogfx::BasicRenderer2D& gfx);
void update(void);
void onThemeApplied(const ostd::Stylesheet& theme);
void onMousePressed(const Event& event);
void onMouseReleased(const Event& event);
void onMouseMoved(const Event& event);
void onMouseDragged(const Event& event);
void onKeyPressed(const Event& event);
void onKeyReleased(const Event& event);
void onTextEntered(const Event& event);
void onWindowClosed(const Event& event);
void onWindowResized(const Event& event);
void onWindowFocused(const Event& event);
void onWindowFocusLost(const Event& event);
inline int32_t widgetCount(void) const { return m_widgetList.size(); }
inline WindowCore& getWindow(void) { return m_window; }
private:
WindowCore& m_window;
Widget& m_owner;
std::vector<Widget*> m_widgetList;
Widget* m_focused { nullptr };
bool m_tabNavigationEnabled { true };
Widget* m_mousePressedOnWidget { nullptr };
};
class Widget : public ostd::BaseObject, public ostd::Rectangle class Widget : public ostd::BaseObject, public ostd::Rectangle
{ {
private: struct ThemeOverride private: struct ThemeOverride
@ -95,7 +55,7 @@ namespace ogfx
void addThemeOverride(const ostd::String& fullKey, ostd::Stylesheet::TypeVariant value, bool propagate = true); void addThemeOverride(const ostd::String& fullKey, ostd::Stylesheet::TypeVariant value, bool propagate = true);
void reloadTheme(void); void reloadTheme(void);
void setThemeQualifier(const ostd::String& qualifier, bool value = true); void setThemeQualifier(const ostd::String& qualifier, bool value = true);
bool getThemeQualifier(const ostd::String& qualifier); bool getThemeQualifier(const ostd::String& qualifier) const;
bool addThemeID(const ostd::String& id); bool addThemeID(const ostd::String& id);
bool removeThemeID(const ostd::String& id); bool removeThemeID(const ostd::String& id);
inline const ostd::Stylesheet::QualifierList& getThemeQualifierList(void) const { return m_qualifierList; } inline const ostd::Stylesheet::QualifierList& getThemeQualifierList(void) const { return m_qualifierList; }
@ -106,6 +66,7 @@ namespace ogfx
inline virtual void onMousePressed(const Event& event) { } inline virtual void onMousePressed(const Event& event) { }
inline virtual void onMouseReleased(const Event& event) { } inline virtual void onMouseReleased(const Event& event) { }
inline virtual void onMouseMoved(const Event& event) { } inline virtual void onMouseMoved(const Event& event) { }
inline virtual void onDragAndDrop(const Event& event) { }
inline virtual void onMouseEntered(const Event& event) { } inline virtual void onMouseEntered(const Event& event) { }
inline virtual void onMouseExited(const Event& event) { } inline virtual void onMouseExited(const Event& event) { }
inline virtual void onMouseDragged(const Event& event) { } inline virtual void onMouseDragged(const Event& event) { }
@ -123,6 +84,7 @@ namespace ogfx
void __update(void); void __update(void);
void __onMousePressed(const Event& event); void __onMousePressed(const Event& event);
void __onMouseReleased(const Event& event); void __onMouseReleased(const Event& event);
void __onDragAndDrop(const Event& event);
void __onMouseMoved(const Event& event); void __onMouseMoved(const Event& event);
void __onMouseEntered(const Event& event); void __onMouseEntered(const Event& event);
void __onMouseExited(const Event& event); void __onMouseExited(const Event& event);
@ -132,13 +94,14 @@ namespace ogfx
void __onTextEntered(const Event& event); void __onTextEntered(const Event& event);
void __onWindowClosed(const Event& event); void __onWindowClosed(const Event& event);
void __onWindowResized(const Event& event); void __onWindowResized(const Event& event);
void __onWIndowFocused(const Event& event); void __onWindowFocused(const Event& event);
void __onWindowFocusLost(const Event& event); void __onWindowFocusLost(const Event& event);
void __applyTheme(const ostd::Stylesheet& theme, bool propagate); void __applyTheme(const ostd::Stylesheet& theme, bool propagate);
inline virtual void setMousePressedCallback(EventCallback callback) { callback_onMousePressed = callback; } inline virtual void setMousePressedCallback(EventCallback callback) { callback_onMousePressed = callback; }
inline virtual void setMouseReleasedCallback(EventCallback callback) { callback_onMouseReleased = callback; } inline virtual void setMouseReleasedCallback(EventCallback callback) { callback_onMouseReleased = callback; }
inline virtual void setMouseMovedCallback(EventCallback callback) { callback_onMouseMoved = callback; } inline virtual void setMouseMovedCallback(EventCallback callback) { callback_onMouseMoved = callback; }
inline virtual void setDragAndDropCallback(EventCallback callback) { callback_onDragAndDrop = callback; }
inline virtual void setMouseEnteredCallback(EventCallback callback) { callback_onMouseEntered = callback; } inline virtual void setMouseEnteredCallback(EventCallback callback) { callback_onMouseEntered = callback; }
inline virtual void setMouseExitedCallback(EventCallback callback) { callback_onMouseExited = callback; } inline virtual void setMouseExitedCallback(EventCallback callback) { callback_onMouseExited = callback; }
inline virtual void setMouseDraggedCallback(EventCallback callback) { callback_onMouseDragged = callback; } inline virtual void setMouseDraggedCallback(EventCallback callback) { callback_onMouseDragged = callback; }
@ -147,7 +110,7 @@ namespace ogfx
inline virtual void setTextEnteredCallback(EventCallback callback) { callback_onTextEntered = callback; } inline virtual void setTextEnteredCallback(EventCallback callback) { callback_onTextEntered = callback; }
inline virtual void setWindowClosedCallback(EventCallback callback) { callback_onWindowClosed = callback; } inline virtual void setWindowClosedCallback(EventCallback callback) { callback_onWindowClosed = callback; }
inline virtual void setWindowResizedCallback(EventCallback callback) { callback_onWindowResized = callback; } inline virtual void setWindowResizedCallback(EventCallback callback) { callback_onWindowResized = callback; }
inline virtual void setWIndowFocusedCallback(EventCallback callback) { callback_onWindowFocused = callback; } inline virtual void setWindowFocusedCallback(EventCallback callback) { callback_onWindowFocused = callback; }
inline virtual void setWindowFocusLostCallback(EventCallback callback) { callback_onWindowFocusLost = callback; } inline virtual void setWindowFocusLostCallback(EventCallback callback) { callback_onWindowFocusLost = callback; }
inline bool hasChildren(void) const { return m_allowChildren && m_widgets.widgetCount() > 0; } inline bool hasChildren(void) const { return m_allowChildren && m_widgets.widgetCount() > 0; }
@ -168,8 +131,11 @@ namespace ogfx
inline bool isFocusEnabled(void) const { return m_allowFocus; } inline bool isFocusEnabled(void) const { return m_allowFocus; }
inline void enableFocus(bool enable = true) { m_allowFocus = enable; } inline void enableFocus(bool enable = true) { m_allowFocus = enable; }
inline void disableFocus(void) { enableFocus(false); } inline void disableFocus(void) { enableFocus(false); }
inline void disabble(void) { enable(false); } inline void disable(void) { enable(false); }
inline void enableStopEvents(bool enable = true) { m_stopEvents = enable; } inline void enableStopEvents(bool enable = true) { m_stopEvents = enable; }
inline bool isDragAndDropEnabled(void) const { return m_acceptDragAndDrop; }
inline void enableDragAndDrop(bool enable = true) { m_acceptDragAndDrop = enable; }
inline void disableDragAndDrop(void) { enableDragAndDrop(false); }
template<typename T> template<typename T>
inline T getThemeValue(const ostd::Stylesheet &theme, const ostd::String& key, const T& fallback) inline T getThemeValue(const ostd::Stylesheet &theme, const ostd::String& key, const T& fallback)
@ -177,6 +143,10 @@ namespace ogfx
return theme.get<T>(key, fallback, getThemeIDList(), getThemeQualifierList()); return theme.get<T>(key, fallback, getThemeIDList(), getThemeQualifierList());
} }
inline static void setDragAndDropData(ostd::BaseObject& data) { s_dragAndDropData = &data; }
inline static void clearDragAndDropData(void) { s_dragAndDropData = nullptr; }
inline static ostd::BaseObject* getDragAndDropData(void) { return s_dragAndDropData; }
protected: protected:
inline void disableChildren(void) { m_allowChildren = false; } inline void disableChildren(void) { m_allowChildren = false; }
inline void disableDrawBox(void) { m_drawBox = false; } inline void disableDrawBox(void) { m_drawBox = false; }
@ -194,6 +164,7 @@ namespace ogfx
EventCallback callback_onMousePressed { nullptr }; EventCallback callback_onMousePressed { nullptr };
EventCallback callback_onMouseReleased { nullptr }; EventCallback callback_onMouseReleased { nullptr };
EventCallback callback_onDragAndDrop { nullptr };
EventCallback callback_onMouseMoved { nullptr }; EventCallback callback_onMouseMoved { nullptr };
EventCallback callback_onMouseEntered { nullptr }; EventCallback callback_onMouseEntered { nullptr };
EventCallback callback_onMouseExited { nullptr }; EventCallback callback_onMouseExited { nullptr };
@ -219,6 +190,7 @@ namespace ogfx
bool m_enabled { true }; bool m_enabled { true };
bool m_stopEvents { true }; bool m_stopEvents { true };
bool m_clipContents { true }; bool m_clipContents { true };
bool m_acceptDragAndDrop { false };
MouseEventData::eButton m_pressedButton { MouseEventData::eButton::None }; MouseEventData::eButton m_pressedButton { MouseEventData::eButton::None };
std::vector<ostd::String> m_themeIDList; std::vector<ostd::String> m_themeIDList;
@ -236,21 +208,9 @@ namespace ogfx
ostd::Rectangle m_padding { 0, 0, 0, 0 }; ostd::Rectangle m_padding { 0, 0, 0, 0 };
inline static ostd::BaseObject* s_dragAndDropData { nullptr };
friend class WidgetManager; friend class WidgetManager;
}; };
namespace widgets
{
class RootWidget : public Widget
{
public:
RootWidget(WindowCore& window);
void onWindowResized(const Event& event) override;
void applyTheme(const ostd::Stylesheet& theme) override;
void onDraw(ogfx::BasicRenderer2D& gfx) override;
private:
ostd::Color m_color { ostd::Colors::Transparent };
};
}
} }
} }

View file

@ -1,3 +1,23 @@
/*
OmniaFramework - A collection of useful functionality
Copyright (C) 2025 OmniaX-Dev
This file is part of OmniaFramework.
OmniaFramework is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OmniaFramework is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
*/
#include "Logic.hpp" #include "Logic.hpp"
#include "../string/String.hpp" #include "../string/String.hpp"
#ifndef __APPLE__ #ifndef __APPLE__

View file

@ -41,6 +41,8 @@ namespace ostd
inline static constexpr uint32_t TextEntered = 0x0007; inline static constexpr uint32_t TextEntered = 0x0007;
inline static constexpr uint32_t OnGuiEvent = 0x2001; inline static constexpr uint32_t OnGuiEvent = 0x2001;
inline static constexpr uint32_t FileDragAndDropped = 0x2002;
inline static constexpr uint32_t TextDragAndDropped = 0x2003;
inline static constexpr uint32_t BeforeSDLShutdown = 0x3001; inline static constexpr uint32_t BeforeSDLShutdown = 0x3001;

View file

@ -30,7 +30,7 @@ class Window : public ogfx::gui::Window
inline void onInitialize(void) override inline void onInitialize(void) override
{ {
m_panel1.setSize(300, 140); m_panel1.setSize(300, 140);
m_panel1.setPosition(200, 150); m_panel1.setPosition(350, 50);
m_panel1.setMousePressedCallback([&](const ogfx::gui::Event& event) -> void { m_panel1.setMousePressedCallback([&](const ogfx::gui::Event& event) -> void {
pos = { event.mouse->position_x, event.mouse->position_y }; pos = { event.mouse->position_x, event.mouse->position_y };
}); });
@ -43,6 +43,13 @@ class Window : public ogfx::gui::Window
m_panel2.setSize(300, 140); m_panel2.setSize(300, 140);
m_panel2.setPosition(130, 200); m_panel2.setPosition(130, 200);
m_panel2.setMousePressedCallback([&](const ogfx::gui::Event& event) -> void {
ogfx::gui::Widget::setDragAndDropData(m_label3);
setCursor(eCursor::Move);
});
m_panel2.setMouseReleasedCallback([&](const ogfx::gui::Event& event) -> void {
setCursor(eCursor::Default);
});
m_label1.setPosition(100, 200); m_label1.setPosition(100, 200);
m_label1.setText("Hello World!"); m_label1.setText("Hello World!");
@ -57,6 +64,14 @@ class Window : public ogfx::gui::Window
m_label2.setText("Ciccia Bella!"); m_label2.setText("Ciccia Bella!");
m_label2.addThemeID("testLabel"); m_label2.addThemeID("testLabel");
m_label2.addThemeID("testLabel2"); m_label2.addThemeID("testLabel2");
m_label2.enableDragAndDrop();
m_label2.setDragAndDropCallback([&](const ogfx::gui::Event& event) -> void {
std::cout << "DROP\n";
if (auto data = ogfx::gui::Widget::getDragAndDropData())
{
std::cout << static_cast<ogfx::gui::widgets::Label&>(*data).getText() << "!\n";
}
});
m_panel1.addChild(m_label2); m_panel1.addChild(m_label2);
m_label1.addThemeOverride("@:pressed.label.textColor", ostd::Colors::Crimson); m_label1.addThemeOverride("@:pressed.label.textColor", ostd::Colors::Crimson);