summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Applications/FileManager/main.cpp10
-rw-r--r--Libraries/LibGUI/GAbstractButton.h3
-rw-r--r--Libraries/LibGUI/GAction.cpp17
-rw-r--r--Libraries/LibGUI/GAction.h5
-rw-r--r--Libraries/LibGUI/GActionGroup.cpp14
-rw-r--r--Libraries/LibGUI/GActionGroup.h35
-rw-r--r--Libraries/LibGUI/GButton.cpp17
-rw-r--r--Libraries/LibGUI/GButton.h1
-rw-r--r--Libraries/LibGUI/Makefile1
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 \