Iteration on functionality of ContextMenu and UtilityBar. Multi-nested menus are now supported.

This commit is contained in:
2025-05-01 13:26:59 -05:00
parent abe4371f00
commit 672429f736
4 changed files with 65 additions and 48 deletions

View File

@@ -14,24 +14,22 @@
#include <JUI/Widgets/TextButton.hpp>
#include "ListLayout.hpp"
#include "Separator.hpp"
#include "JUI/Mixins/Pinnable.hpp"
#include "JUI/Mixins/TextStyleInterface.hpp"
namespace JUI {
class ContextMenu;
/// TODO: Observe and design all the base interfaces for various style categories.
class TextStyleInterface {
public:
virtual ~TextStyleInterface() = default;
// TODO: Move to NestableMenu.hpp after resolving circular dependency.
virtual JGL::Font Font() const = 0;
virtual int TextSize() const = 0;
virtual Color4 TextColor() const = 0;
virtual bool WordWrap() const = 0;
virtual void Font(const JGL::Font& value) = 0;
virtual void TextSize(int value) = 0;
virtual void TextColor(const Color4& color) = 0;
/// An abstract class that defines the interface for nestable menus - menu objects that contain similar sub-menus.
class NestableMenu {
virtual ContextMenu* AddSubmenu(const std::string& text) = 0;
virtual TextButton* AddButton(const std::string& text) = 0;
virtual TextButton* AddButton(const std::string& text, const std::function<void()>& callback) = 0;
virtual Separator* AddSeparator() = 0;
};
class RectStyleInterface {
@@ -48,21 +46,16 @@ namespace JUI {
};
class PaddingStyleInterface {
};
class MarginStyleInterface {
};
/// A vertically-descending list menu of button objects, which supports sub-menus much like class UtilityBar.
/// @see UtilityBar
class ContextMenu : public Rect, public Pinnable {
class ContextMenu : public Rect, public Pinnable, public NestableMenu {
public:
Event<> PresumeMouseFocusLost;
// TODO: Work in progress.
void PropogateTextSize(int value) {
for (auto* child : children) {
TextStyleInterface* textual = dynamic_cast<TextStyleInterface *>(child);
@@ -86,20 +79,10 @@ namespace JUI {
void SetFont(const JGL::Font& use_my_font);
TextButton* AddButton(const std::string &name);
TextButton* AddButton(const std::string& name, const std::function<void()> &callback) {
auto* btn = AddButton(name);
// TODO: Is this memory safe at all?
btn->OnClickEvent += [&, callback] (auto a, auto b) mutable {
callback();
};
return btn;
}
ContextMenu* AddSubmenu(const std::string& name);
TextButton* AddButton(const std::string &name) override;
TextButton* AddButton(const std::string& name, const std::function<void()> &callback) override;
Separator* AddSeparator() override;
ContextMenu* AddSubmenu(const std::string& name) override;
/// Sets whether the widget will automatically hide itself when the mouse leaves its bounding box.

View File

@@ -19,10 +19,11 @@ namespace JUI
/// A horizontal toolbar widget that is designed to be used at the top of windows, and subwindow widgets.
/// Convenience functions are provided for adding tool buttons and sub-menus.
/// @see class ContextMenu
class UtilityBar : public Rect
class UtilityBar : public Rect, public NestableMenu
{
public:
UtilityBar();
@@ -30,16 +31,13 @@ namespace JUI
explicit UtilityBar(Widget* parent);
/// Adds a new 'Submenu', which consists of a labeled button, which opens a contextual-submenu
ContextMenu* AddSubmenu(const std::string& name);
ContextMenu* AddSubmenu(const std::string& name) override;
TextButton* AddButton(const std::string& name);
TextButton* AddButton(const std::string& name, const std::function<void()>& callback) {
auto* button = AddButton(name);
TextButton* AddButton(const std::string& name) override;
TextButton* AddButton(const std::string& name, const std::function<void()>& callback) override;
button->OnClickEvent += [&, callback] (auto a, auto b) mutable { callback();};
return button;
}
Separator* AddSeparator() override;
protected:
//std::vector<TextButton*> buttons;

View File

@@ -48,6 +48,22 @@ namespace JUI {
return line_item;
}
TextButton * ContextMenu::AddButton(const std::string &name, const std::function<void()> &callback) {
auto* btn = AddButton(name);
// TODO: Is this memory safe at all?
btn->OnClickEvent += [this, btn, callback] (auto a, auto b) mutable {
if (this->IsVisible() && btn->IsMouseInside())
callback();
};
return btn;
}
Separator * ContextMenu::AddSeparator() {
return new Separator(layout);
}
ContextMenu * ContextMenu::AddSubmenu(const std::string &name) {
auto* btn = AddButton(name);
@@ -56,15 +72,19 @@ namespace JUI {
auto* submenu = new JUI::ContextMenu(btn);
submenu->AnchorPoint({0, 0});
submenu->Position({100_percent, 0_percent});
submenu->Visible(false);
btn->OnClickEvent += [this, submenu] (auto a, auto b) mutable {
this->Pin();
submenu->Visible(true);
if (this->IsVisible()) {
this->Pin();
submenu->Visible(true);
}
};
submenu->MouseExit += [this, submenu] (auto _) {
if (!submenu->Pinned())
this->Unpin();
if (!submenu->Pinned())
this->Unpin();
};
return submenu;

View File

@@ -29,10 +29,11 @@ namespace JUI {
//submenu->AnchorPoint({0, 1});
// TODO: Fix AnchorPoint behavior!!
submenu->Position({0_percent, 100_percent});
submenu->Visible(true);
submenu->Visible(false);
btn->OnClickEvent += [submenu] (auto a, auto b) mutable {
submenu->Visible(true);
btn->OnClickEvent += [this, submenu] (auto a, auto b) mutable {
if (this->IsVisible())
submenu->Visible(true);
};
@@ -55,4 +56,19 @@ namespace JUI {
return btn;
}
TextButton * UtilityBar::AddButton(const std::string &name, const std::function<void()> &callback) {
auto* button = AddButton(name);
button->OnClickEvent += [this, button, callback] (auto a, auto b) mutable {
if (this->IsVisible() && button->IsMouseInside())
callback();
};
return button;
}
Separator * UtilityBar::AddSeparator() {
return new Separator(layout);
}
}