diff options
-rw-r--r-- | Applications/FileManager/main.cpp | 10 | ||||
-rw-r--r-- | Libraries/LibGUI/GAbstractButton.h | 3 | ||||
-rw-r--r-- | Libraries/LibGUI/GAction.cpp | 17 | ||||
-rw-r--r-- | Libraries/LibGUI/GAction.h | 5 | ||||
-rw-r--r-- | Libraries/LibGUI/GActionGroup.cpp | 14 | ||||
-rw-r--r-- | Libraries/LibGUI/GActionGroup.h | 35 | ||||
-rw-r--r-- | Libraries/LibGUI/GButton.cpp | 17 | ||||
-rw-r--r-- | Libraries/LibGUI/GButton.h | 1 | ||||
-rw-r--r-- | Libraries/LibGUI/Makefile | 1 |
9 files changed, 97 insertions, 6 deletions
diff --git a/Applications/FileManager/main.cpp b/Applications/FileManager/main.cpp index 4817444b17..a52efdc268 100644 --- a/Applications/FileManager/main.cpp +++ b/Applications/FileManager/main.cpp @@ -2,6 +2,7 @@ #include <AK/FileSystemPath.h> #include <LibCore/CUserInfo.h> #include <LibGUI/GAction.h> +#include <LibGUI/GActionGroup.h> #include <LibGUI/GApplication.h> #include <LibGUI/GBoxLayout.h> #include <LibGUI/GFileSystemModel.h> @@ -108,18 +109,21 @@ int main(int argc, char** argv) view_as_table_action = GAction::create("Table view", { Mod_Ctrl, KeyCode::Key_L }, GraphicsBitmap::load_from_file("/res/icons/16x16/table-view.png"), [&](const GAction&) { directory_view->set_view_mode(DirectoryView::ViewMode::List); - view_as_icons_action->set_checked(false); view_as_table_action->set_checked(true); }); view_as_table_action->set_checkable(true); - view_as_table_action->set_checked(false); view_as_icons_action = GAction::create("Icon view", { Mod_Ctrl, KeyCode::Key_I }, GraphicsBitmap::load_from_file("/res/icons/16x16/icon-view.png"), [&](const GAction&) { directory_view->set_view_mode(DirectoryView::ViewMode::Icon); - view_as_table_action->set_checked(false); view_as_icons_action->set_checked(true); }); view_as_icons_action->set_checkable(true); + + auto view_type_action_group = make<GActionGroup>(); + view_type_action_group->set_exclusive(true); + view_type_action_group->add_action(*view_as_table_action); + view_type_action_group->add_action(*view_as_icons_action); + view_as_icons_action->set_checked(true); auto copy_action = GAction::create("Copy", GraphicsBitmap::load_from_file("/res/icons/16x16/edit-copy.png"), [](const GAction&) { diff --git a/Libraries/LibGUI/GAbstractButton.h b/Libraries/LibGUI/GAbstractButton.h index 269a7ea834..9618422682 100644 --- a/Libraries/LibGUI/GAbstractButton.h +++ b/Libraries/LibGUI/GAbstractButton.h @@ -29,7 +29,8 @@ public: virtual void click() = 0; virtual const char* class_name() const override { return "GAbstractButton"; } virtual bool accepts_focus() const override { return true; } - virtual bool supports_keyboard_activation() const { return true; } + virtual bool supports_keyboard_activation() const override { return true; } + virtual bool is_uncheckable() const { return true; } protected: explicit GAbstractButton(GWidget* parent); diff --git a/Libraries/LibGUI/GAction.cpp b/Libraries/LibGUI/GAction.cpp index 530f553a87..b655c67f58 100644 --- a/Libraries/LibGUI/GAction.cpp +++ b/Libraries/LibGUI/GAction.cpp @@ -1,4 +1,5 @@ #include <LibGUI/GAction.h> +#include <LibGUI/GActionGroup.h> #include <LibGUI/GApplication.h> #include <LibGUI/GButton.h> #include <LibGUI/GMenuItem.h> @@ -105,6 +106,17 @@ void GAction::set_checked(bool checked) if (m_checked == checked) return; m_checked = checked; + + if (m_checked && m_action_group) { + m_action_group->for_each_action([this](auto& other_action) { + if (this == &other_action) + return IterationDecision::Continue; + if (other_action.is_checkable()) + other_action.set_checked(false); + return IterationDecision::Continue; + }); + } + for_each_toolbar_button([checked](GButton& button) { button.set_checked(checked); }); @@ -112,3 +124,8 @@ void GAction::set_checked(bool checked) item.set_checked(checked); }); } + +void GAction::set_group(Badge<GActionGroup>, GActionGroup* group) +{ + m_action_group = group ? group->make_weak_ptr() : nullptr; +} diff --git a/Libraries/LibGUI/GAction.h b/Libraries/LibGUI/GAction.h index 021f4fa4c9..867c41e213 100644 --- a/Libraries/LibGUI/GAction.h +++ b/Libraries/LibGUI/GAction.h @@ -11,6 +11,7 @@ #include <LibGUI/GShortcut.h> #include <SharedGraphics/GraphicsBitmap.h> +class GActionGroup; class GButton; class GMenuItem; class GWidget; @@ -70,6 +71,9 @@ public: void register_menu_item(Badge<GMenuItem>, GMenuItem&); void unregister_menu_item(Badge<GMenuItem>, GMenuItem&); + const GActionGroup* group() const { return m_action_group.ptr(); } + void set_group(Badge<GActionGroup>, GActionGroup*); + private: GAction(const StringView& text, Function<void(GAction&)> = nullptr, GWidget* = nullptr); GAction(const StringView& text, const GShortcut&, Function<void(GAction&)> = nullptr, GWidget* = nullptr); @@ -92,4 +96,5 @@ private: HashTable<GButton*> m_buttons; HashTable<GMenuItem*> m_menu_items; WeakPtr<GWidget> m_widget; + WeakPtr<GActionGroup> m_action_group; }; diff --git a/Libraries/LibGUI/GActionGroup.cpp b/Libraries/LibGUI/GActionGroup.cpp new file mode 100644 index 0000000000..d7c327e28b --- /dev/null +++ b/Libraries/LibGUI/GActionGroup.cpp @@ -0,0 +1,14 @@ +#include <LibGUI/GAction.h> +#include <LibGUI/GActionGroup.h> + +void GActionGroup::add_action(GAction& action) +{ + action.set_group({}, this); + m_actions.set(&action); +} + +void GActionGroup::remove_action(GAction& action) +{ + action.set_group({}, nullptr); + m_actions.remove(&action); +} diff --git a/Libraries/LibGUI/GActionGroup.h b/Libraries/LibGUI/GActionGroup.h new file mode 100644 index 0000000000..e1fdca77d3 --- /dev/null +++ b/Libraries/LibGUI/GActionGroup.h @@ -0,0 +1,35 @@ +#pragma once + +#include <AK/HashTable.h> +#include <AK/Weakable.h> + +class GAction; + +class GActionGroup : public Weakable<GActionGroup> { +public: + GActionGroup() {} + ~GActionGroup() {} + + void add_action(GAction&); + void remove_action(GAction&); + + bool is_exclusive() const { return m_exclusive; } + void set_exclusive(bool exclusive) { m_exclusive = exclusive; } + + bool is_unchecking_allowed() const { return m_unchecking_allowed; } + void set_unchecking_allowed(bool unchecking_allowed) { m_unchecking_allowed = unchecking_allowed; } + + template<typename C> + void for_each_action(C callback) + { + for (auto& it : m_actions) { + if (callback(*it) == IterationDecision::Break) + break; + } + } + +private: + HashTable<GAction*> m_actions; + bool m_exclusive { false }; + bool m_unchecking_allowed { false }; +}; diff --git a/Libraries/LibGUI/GButton.cpp b/Libraries/LibGUI/GButton.cpp index 364ab4677c..3274d4992f 100644 --- a/Libraries/LibGUI/GButton.cpp +++ b/Libraries/LibGUI/GButton.cpp @@ -1,7 +1,8 @@ -#include "GButton.h" #include <AK/StringBuilder.h> #include <Kernel/KeyCode.h> #include <LibGUI/GAction.h> +#include <LibGUI/GActionGroup.h> +#include <LibGUI/GButton.h> #include <LibGUI/GPainter.h> #include <SharedGraphics/StylePainter.h> @@ -60,8 +61,11 @@ void GButton::click() { if (!is_enabled()) return; - if (is_checkable()) + if (is_checkable()) { + if (is_checked() && !is_uncheckable()) + return; set_checked(!is_checked()); + } if (on_click) on_click(*this); } @@ -88,3 +92,12 @@ void GButton::set_icon(RefPtr<GraphicsBitmap>&& icon) m_icon = move(icon); update(); } + +bool GButton::is_uncheckable() const +{ + if (!m_action) + return true; + if (!m_action->group()) + return true; + return m_action->group()->is_unchecking_allowed(); +} diff --git a/Libraries/LibGUI/GButton.h b/Libraries/LibGUI/GButton.h index c3e1b0c1ff..acd7d7298c 100644 --- a/Libraries/LibGUI/GButton.h +++ b/Libraries/LibGUI/GButton.h @@ -34,6 +34,7 @@ public: virtual const char* class_name() const override { return "GButton"; } virtual bool accepts_focus() const override { return m_focusable; } virtual bool supports_keyboard_activation() const override; + virtual bool is_uncheckable() const override; void set_focusable(bool b) { m_focusable = b; } diff --git a/Libraries/LibGUI/Makefile b/Libraries/LibGUI/Makefile index 33c1f4fdbc..7589e77b91 100644 --- a/Libraries/LibGUI/Makefile +++ b/Libraries/LibGUI/Makefile @@ -27,6 +27,7 @@ LIBGUI_OBJS = \ GMenuItem.o \ GApplication.o \ GAction.o \ + GActionGroup.o \ GFontDatabase.o \ GToolBar.o \ GTableView.o \ |