LibGUI: Add GActionGroup, a way to group a bunch of GActions.

This can be used to make a bunch of actions mutually exclusive.
This patch only implements the exclusivity behavior for buttons.
This commit is contained in:
Andreas Kling 2019-07-09 22:10:03 +02:00
parent 2ae0333f5d
commit 7083a0104a
Notes: sideshowbarker 2024-07-19 13:21:12 +09:00
9 changed files with 97 additions and 6 deletions

View file

@ -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&) {

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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);
}

View file

@ -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 };
};

View file

@ -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();
}

View file

@ -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; }

View file

@ -27,6 +27,7 @@ LIBGUI_OBJS = \
GMenuItem.o \
GApplication.o \
GAction.o \
GActionGroup.o \
GFontDatabase.o \
GToolBar.o \
GTableView.o \