diff --git a/CMakeLists.txt b/CMakeLists.txt
index e9f0852..acd06ea 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -86,6 +86,7 @@ list(APPEND OGFX_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/WidgetManager.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/ContextMenu.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/MenuBar.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/ToolBar.cpp
# gui/widgets
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Widget.cpp
diff --git a/extra/DefaultTheme.oss b/extra/DefaultTheme.oss
index 02cc12b..1f479ed 100644
--- a/extra/DefaultTheme.oss
+++ b/extra/DefaultTheme.oss
@@ -308,3 +308,7 @@ const $accentColorDark = #6B0A1DFF
borderColor = #400000FF
}
% =====================
+(@tool_button button) {
+ fontSize = 18
+ padding = rect(10, 0, 10, 0)
+}
diff --git a/other/TODO.txt b/other/TODO.txt
index b0e15aa..8591493 100644
--- a/other/TODO.txt
+++ b/other/TODO.txt
@@ -35,6 +35,8 @@ FIX: Optimize ListView
FIX: Padding for ListView items
Add icons to ListView
FIX: Limit FPS even when continuous events happen
+Add gradient to listbox selection
+Add gradient to menubar background and selection
diff --git a/src/ogfx/gui/MenuBar.cpp b/src/ogfx/gui/MenuBar.cpp
index b47f503..d8504e5 100644
--- a/src/ogfx/gui/MenuBar.cpp
+++ b/src/ogfx/gui/MenuBar.cpp
@@ -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 .
+*/
+
#include "MenuBar.hpp"
#include "../render/BasicRenderer.hpp"
#include "Window.hpp"
diff --git a/src/ogfx/gui/MenuBar.hpp b/src/ogfx/gui/MenuBar.hpp
index af093c3..34d8fef 100644
--- a/src/ogfx/gui/MenuBar.hpp
+++ b/src/ogfx/gui/MenuBar.hpp
@@ -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 .
+*/
+
#pragma once
#include
diff --git a/src/ogfx/gui/ToolBar.cpp b/src/ogfx/gui/ToolBar.cpp
new file mode 100644
index 0000000..84b466f
--- /dev/null
+++ b/src/ogfx/gui/ToolBar.cpp
@@ -0,0 +1,102 @@
+/*
+ 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 .
+*/
+
+#include "ToolBar.hpp"
+#include "../render/BasicRenderer.hpp"
+#include "Window.hpp"
+
+namespace ogfx
+{
+ namespace gui
+ {
+ ToolBar::ToolBar(Window& window) : Widget({ 0, 0, 0, 0 }, window)
+ {
+ create();
+ }
+
+ ToolBar& ToolBar::create(void)
+ {
+ setRootChild();
+ setStylesheetCategoryName("toolbar");
+ setTypeName("ogfx::gui::widgets::ToolBar");
+ auto& win = cast(getWindow());
+ setSize(win.getWindowWidth(), m_height);
+ if (win.isMenuBarVisible())
+ setPosition(0, win.getMenuBar().getHeight());
+ else
+ setPosition(0, 0);
+ return *this;
+ }
+
+ void ToolBar::onWindowResized(const Event& event)
+ {
+ auto& win = cast(getWindow());
+ setSize(win.getWindowWidth(), m_height);
+ f32 offset_y = 0;
+ if (win.getMenuBar().isVisible())
+ offset_y += win.getMenuBar().geth();
+ sety(offset_y);
+ }
+
+ void ToolBar::applyTheme(const ostd::Stylesheet& theme)
+ {
+ auto& win = cast(getWindow());
+ setHeight(theme.get("toolbar.height", getHeight(), {}, {}));
+ setItemPadding(theme.get("toolbar.itemPadding", getItemPadding(), {}, {}));
+ setFontSize(theme.get("toolbar.fontSize", getFontSize(), {}, {}));
+ setBackgroundColor(theme.get("toolbar.backgroundColor", getBackgroundColor(), {}, {}));
+ setTextColor(theme.get("toolbar.textColor", getTextColor(), {}, {}));
+ setBorderColor(theme.get("toolbar.borderColor", getBorderColor(), {}, {}));
+ setSize(win.getWindowWidth(), m_height);
+ }
+
+ void ToolBar::onDraw(BasicRenderer2D& gfx)
+ {
+ if (!m_visible) return;
+
+ gfx.fillRect(*this, m_backgroundColor);
+
+ // Bottom border line
+ gfx.drawLine({ { getx(), gety() + m_height }, { getx() + getw(), gety() + m_height } }, m_borderColor);
+ }
+
+ void ToolBar::onUpdate(void)
+ {
+ if (!m_visible) return;
+ }
+
+ void ToolBar::onMousePressed(const Event& event)
+ {
+ if (!m_visible) return;
+
+ Vec2 mousePos { event.mouse->position_x, event.mouse->position_y };
+
+ // event.handle();
+ }
+
+ void ToolBar::onMouseMoved(const Event& event)
+ {
+ if (!m_visible) return;
+
+ Vec2 mousePos { event.mouse->position_x, event.mouse->position_y };
+
+ }
+ }
+}
diff --git a/src/ogfx/gui/ToolBar.hpp b/src/ogfx/gui/ToolBar.hpp
new file mode 100644
index 0000000..634c255
--- /dev/null
+++ b/src/ogfx/gui/ToolBar.hpp
@@ -0,0 +1,64 @@
+/*
+ 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 .
+*/
+
+#pragma once
+
+#include
+
+namespace ogfx
+{
+ namespace gui
+ {
+ class Window;
+ class ToolBar : public Widget
+ {
+ public:
+ ToolBar(Window& window);
+ ToolBar& create(void);
+ void onWindowResized(const Event& event) override;
+ void applyTheme(const ostd::Stylesheet& theme) override;
+ void onDraw(BasicRenderer2D& gfx) override;
+ void onUpdate(void) override;
+ void onMousePressed(const Event& event) override;
+ void onMouseMoved(const Event& event) override;
+
+ inline bool isVisible(void) const { return m_visible; }
+ inline void show(bool v = true) { m_visible = v; }
+ inline void hide(void) { show(false); }
+
+ OSTD_PARAM_GETSET(f32, Height, m_height);
+ OSTD_PARAM_GETSET(Rectangle, ItemPadding, m_itemPadding);
+ OSTD_PARAM_GETSET(i32, FontSize, m_fontSize);
+ OSTD_PARAM_GETSET(Color, BackgroundColor, m_backgroundColor);
+ OSTD_PARAM_GETSET(Color, TextColor, m_textColor);
+ OSTD_PARAM_GETSET(Color, BorderColor, m_borderColor);
+
+ private:
+ bool m_visible { true };
+
+ f32 m_height { 26 };
+ Rectangle m_itemPadding { 0, 0, 0, 0 };
+ i32 m_fontSize { 16 };
+ Color m_backgroundColor { "#6B0A1DFF" };
+ Color m_textColor { "#F16A85FF" };
+ Color m_borderColor { "#400000FF" };
+ };
+ }
+}
diff --git a/src/ogfx/gui/Window.cpp b/src/ogfx/gui/Window.cpp
index 5599689..1637bc6 100644
--- a/src/ogfx/gui/Window.cpp
+++ b/src/ogfx/gui/Window.cpp
@@ -829,8 +829,11 @@ namespace ogfx
m_guiTheme = &theme;
m_rootWidget.__applyTheme(theme, true);
m_rootWidget.reloadTheme(true);
+ m_toolbar.__applyTheme(theme, true);
+ m_toolbar.reloadTheme(true);
m_cmenu.applyTheme(theme);
m_menubar.applyTheme(theme);
+ m_toolbar.applyTheme(theme);
}
void Window::__on_window_init(i32 width, i32 height, const String& title)
@@ -874,6 +877,8 @@ namespace ogfx
onRedraw(m_gfx);
if (m_menubar.isVisible())
m_menubar.draw(m_gfx);
+ m_toolbar.__update();
+ m_toolbar.__draw(m_gfx);
if (m_cmenu.isVisible())
{
stopTooltipTimer();
@@ -900,11 +905,13 @@ namespace ogfx
{
evt.__original_signal_id = ostd::BuiltinSignals::WindowClosed;
m_rootWidget.__onWindowClosed(evt);
+ m_toolbar.__onWindowClosed(evt);
}
else if (signal.ID == ostd::BuiltinSignals::WindowFocused)
{
evt.__original_signal_id = ostd::BuiltinSignals::WindowFocused;
m_rootWidget.__onWindowFocused(evt);
+ m_toolbar.__onWindowFocused(evt);
}
else if (signal.ID == ostd::BuiltinSignals::WindowLostFocus)
{
@@ -912,6 +919,7 @@ namespace ogfx
m_cmenu.hide();
evt.__original_signal_id = ostd::BuiltinSignals::WindowLostFocus;
m_rootWidget.__onWindowFocusLost(evt);
+ m_toolbar.__onWindowFocusLost(evt);
}
else if (signal.ID == ostd::BuiltinSignals::FileDragAndDropped)
{
@@ -939,6 +947,9 @@ namespace ogfx
evt.__original_signal_id = ostd::BuiltinSignals::WindowResized;
if (m_menubar.isVisible())
m_menubar.onWindowResized(evt);
+ if (m_toolbar.isVisible())
+ m_toolbar.onWindowResized(evt);
+ m_toolbar.__onWindowResized(evt);
m_rootWidget.__onWindowResized(evt);
}
else if (signal.ID == ostd::BuiltinSignals::MouseMoved)
@@ -949,6 +960,9 @@ namespace ogfx
m_menubar.onMouseMoved(evt);
if (m_cmenu.isVisible())
m_cmenu.onMouseMoved(evt);
+ if (m_toolbar.isVisible())
+ m_toolbar.onMouseMoved(evt);
+ m_toolbar.__onMouseMoved(evt);
m_rootWidget.__onMouseMoved(evt);
}
else if (signal.ID == ostd::BuiltinSignals::MouseScrolled)
@@ -957,6 +971,7 @@ namespace ogfx
evt.__original_signal_id = ostd::BuiltinSignals::MouseScrolled;
if (m_cmenu.isVisible())
m_cmenu.onMouseScrolled(evt);
+ m_toolbar.__onMouseScrolled(evt);
m_rootWidget.__onMouseScrolled(evt);
}
else if (signal.ID == ostd::BuiltinSignals::MousePressed)
@@ -967,6 +982,9 @@ namespace ogfx
m_cmenu.onMousePressed(evt);
if (m_menubar.isVisible())
m_menubar.onMousePressed(evt);
+ if (m_toolbar.isVisible())
+ m_toolbar.onMousePressed(evt);
+ m_toolbar.__onMousePressed(evt);
m_rootWidget.__onMousePressed(evt);
}
else if (signal.ID == ostd::BuiltinSignals::MouseReleased)
@@ -975,18 +993,21 @@ namespace ogfx
evt.__original_signal_id = ostd::BuiltinSignals::MouseReleased;
if (m_cmenu.isVisible())
m_cmenu.onMouseReleased(evt);
+ m_toolbar.__onMouseReleased(evt);
m_rootWidget.__onMouseReleased(evt);
}
else if (signal.ID == ostd::BuiltinSignals::KeyPressed)
{
evt.keyboard = &(ogfx::KeyEventData&)signal.userData;
evt.__original_signal_id = ostd::BuiltinSignals::KeyPressed;
+ m_toolbar.__onKeyPressed(evt);
m_rootWidget.__onKeyPressed(evt);
}
else if (signal.ID == ostd::BuiltinSignals::KeyReleased)
{
evt.keyboard = &(ogfx::KeyEventData&)signal.userData;
evt.__original_signal_id = ostd::BuiltinSignals::KeyReleased;
+ m_toolbar.__onKeyReleased(evt);
m_rootWidget.__onKeyReleased(evt);
if (evt.keyboard->keyCode == KeyCode::Escape)
close();
@@ -995,6 +1016,7 @@ namespace ogfx
{
evt.keyboard = &(ogfx::KeyEventData&)signal.userData;
evt.__original_signal_id = ostd::BuiltinSignals::TextEntered;
+ m_toolbar.__onTextEntered(evt);
m_rootWidget.__onTextEntered(evt);
}
onSignal(signal);
diff --git a/src/ogfx/gui/Window.hpp b/src/ogfx/gui/Window.hpp
index 5a7ecd9..d804a6d 100644
--- a/src/ogfx/gui/Window.hpp
+++ b/src/ogfx/gui/Window.hpp
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
namespace ogfx
{
@@ -274,8 +275,10 @@ namespace ogfx
inline void showContextMenu(const Vec2& pos) { m_cmenu.show(pos); }
inline void setContextMenu(const ContextMenu::Instance& instance) { m_cmenu.setInstance(instance); }
inline bool isContextMenuVisible(void) const { return m_cmenu.isVisible(); }
+ inline bool isMenuBarVisible(void) const { return m_menubar.isVisible(); }
inline void hideContextMenu(void) { m_cmenu.hide(); }
inline MenuBar& getMenuBar(void) { return m_menubar; }
+ inline ToolBar& getToolBar(void) { return m_toolbar; }
inline virtual void onInitialize(void) { }
inline virtual void onDestroy(void) { }
@@ -302,6 +305,7 @@ namespace ogfx
ostd::StepTimer::TimePoint m_lastFrameTime;
ContextMenu m_cmenu { *this };
MenuBar m_menubar { *this };
+ ToolBar m_toolbar { *this };
friend class widgets::RootWidget;
};
diff --git a/src/ogfx/gui/widgets/Button.cpp b/src/ogfx/gui/widgets/Button.cpp
index 76457dd..ee74388 100644
--- a/src/ogfx/gui/widgets/Button.cpp
+++ b/src/ogfx/gui/widgets/Button.cpp
@@ -73,6 +73,7 @@ namespace ogfx
void Button::setText(const String& text)
{
m_text = text;
+ m_textChanged = true;
__update_size();
}
@@ -107,6 +108,11 @@ namespace ogfx
void Button::__update_size(void)
{
m_realIconSize = getIconSize().propy(getGlobalContentBounds().getSize().y);
+ if (!isAutoSizeEnabled())
+ {
+ m_textChanged = false;
+ return;
+ }
auto size = getWindow().getGFX().getStringDimensions(getText(), getFontSize());
size.x += getPadding().left();
size.x += getPadding().right();
diff --git a/src/ogfx/gui/widgets/Button.hpp b/src/ogfx/gui/widgets/Button.hpp
index bf2eac1..c1c6bcb 100644
--- a/src/ogfx/gui/widgets/Button.hpp
+++ b/src/ogfx/gui/widgets/Button.hpp
@@ -45,6 +45,7 @@ namespace ogfx
inline String getText(void) const { return m_text; }
inline Image& getIcon(void) { return m_icon; }
OSTD_BOOL_PARAM_GETSET_E(Animated, m_animated);
+ OSTD_BOOL_PARAM_GETSET_E(AutoSize, m_autoSize);
OSTD_BOOL_PARAM_GETSET_E(Icon, m_showIcon);
OSTD_PARAM_GETSET(ostd::AnimationData, AnimationData, m_animData);
OSTD_PARAM_GETSET(Vec2, IconSize, m_iconSize);
@@ -57,6 +58,7 @@ namespace ogfx
bool m_textChanged { true };
Image m_icon;
Vec2 m_realIconSize { 0, 0 };
+ bool m_autoSize { true };
bool m_showIcon { false };
ostd::AnimationData m_animData;
diff --git a/src/ogfx/gui/widgets/RootWidget.cpp b/src/ogfx/gui/widgets/RootWidget.cpp
index 254ae48..01aa130 100644
--- a/src/ogfx/gui/widgets/RootWidget.cpp
+++ b/src/ogfx/gui/widgets/RootWidget.cpp
@@ -42,6 +42,8 @@ namespace ogfx
f32 offset_y = 0;
if (win.m_menubar.isVisible())
offset_y += win.m_menubar.geth();
+ if (win.m_toolbar.isVisible())
+ offset_y += win.m_toolbar.geth();
sety(offset_y);
setSize(cast(event.windowResized->new_width), cast(event.windowResized->new_height) - offset_y);
}
diff --git a/src/test/GuiTest.cpp b/src/test/GuiTest.cpp
index 0460c83..c99ef01 100644
--- a/src/test/GuiTest.cpp
+++ b/src/test/GuiTest.cpp
@@ -163,7 +163,12 @@ class Window : public ogfx::gui::Window
m_panel2.addWidget(m_label3);
m_panel2.addWidget(m_panel1, { 400, 50 });
m_panel2.addWidget(m_label1, { 0, 500 });
- m_panel2.addWidget(m_btn1, { 0, 300 });
+ // m_panel2.addWidget(m_btn1, { 0, 300 });
+ m_btn1.addThemeID("tool_button");
+ m_btn1.seth(26);
+ m_btn1.setText(" ");
+ m_btn1.disableAutoSize();
+ getToolBar().addWidget(m_btn1, { 0, 0 });
m_panel2.addWidget(m_img, { 20, 50 });
addWidget(m_tabs, { 0, 0 });