mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 10:38:11 +00:00
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:
parent
2ae0333f5d
commit
7083a0104a
9 changed files with 97 additions and 6 deletions
|
@ -2,6 +2,7 @@
|
||||||
#include <AK/FileSystemPath.h>
|
#include <AK/FileSystemPath.h>
|
||||||
#include <LibCore/CUserInfo.h>
|
#include <LibCore/CUserInfo.h>
|
||||||
#include <LibGUI/GAction.h>
|
#include <LibGUI/GAction.h>
|
||||||
|
#include <LibGUI/GActionGroup.h>
|
||||||
#include <LibGUI/GApplication.h>
|
#include <LibGUI/GApplication.h>
|
||||||
#include <LibGUI/GBoxLayout.h>
|
#include <LibGUI/GBoxLayout.h>
|
||||||
#include <LibGUI/GFileSystemModel.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&) {
|
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);
|
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_checked(true);
|
||||||
});
|
});
|
||||||
view_as_table_action->set_checkable(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&) {
|
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);
|
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_checked(true);
|
||||||
});
|
});
|
||||||
view_as_icons_action->set_checkable(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);
|
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&) {
|
auto copy_action = GAction::create("Copy", GraphicsBitmap::load_from_file("/res/icons/16x16/edit-copy.png"), [](const GAction&) {
|
||||||
|
|
|
@ -29,7 +29,8 @@ public:
|
||||||
virtual void click() = 0;
|
virtual void click() = 0;
|
||||||
virtual const char* class_name() const override { return "GAbstractButton"; }
|
virtual const char* class_name() const override { return "GAbstractButton"; }
|
||||||
virtual bool accepts_focus() const override { return true; }
|
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:
|
protected:
|
||||||
explicit GAbstractButton(GWidget* parent);
|
explicit GAbstractButton(GWidget* parent);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <LibGUI/GAction.h>
|
#include <LibGUI/GAction.h>
|
||||||
|
#include <LibGUI/GActionGroup.h>
|
||||||
#include <LibGUI/GApplication.h>
|
#include <LibGUI/GApplication.h>
|
||||||
#include <LibGUI/GButton.h>
|
#include <LibGUI/GButton.h>
|
||||||
#include <LibGUI/GMenuItem.h>
|
#include <LibGUI/GMenuItem.h>
|
||||||
|
@ -105,6 +106,17 @@ void GAction::set_checked(bool checked)
|
||||||
if (m_checked == checked)
|
if (m_checked == checked)
|
||||||
return;
|
return;
|
||||||
m_checked = checked;
|
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) {
|
for_each_toolbar_button([checked](GButton& button) {
|
||||||
button.set_checked(checked);
|
button.set_checked(checked);
|
||||||
});
|
});
|
||||||
|
@ -112,3 +124,8 @@ void GAction::set_checked(bool checked)
|
||||||
item.set_checked(checked);
|
item.set_checked(checked);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GAction::set_group(Badge<GActionGroup>, GActionGroup* group)
|
||||||
|
{
|
||||||
|
m_action_group = group ? group->make_weak_ptr() : nullptr;
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <LibGUI/GShortcut.h>
|
#include <LibGUI/GShortcut.h>
|
||||||
#include <SharedGraphics/GraphicsBitmap.h>
|
#include <SharedGraphics/GraphicsBitmap.h>
|
||||||
|
|
||||||
|
class GActionGroup;
|
||||||
class GButton;
|
class GButton;
|
||||||
class GMenuItem;
|
class GMenuItem;
|
||||||
class GWidget;
|
class GWidget;
|
||||||
|
@ -70,6 +71,9 @@ public:
|
||||||
void register_menu_item(Badge<GMenuItem>, GMenuItem&);
|
void register_menu_item(Badge<GMenuItem>, GMenuItem&);
|
||||||
void unregister_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:
|
private:
|
||||||
GAction(const StringView& text, Function<void(GAction&)> = nullptr, GWidget* = nullptr);
|
GAction(const StringView& text, Function<void(GAction&)> = nullptr, GWidget* = nullptr);
|
||||||
GAction(const StringView& text, const GShortcut&, 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<GButton*> m_buttons;
|
||||||
HashTable<GMenuItem*> m_menu_items;
|
HashTable<GMenuItem*> m_menu_items;
|
||||||
WeakPtr<GWidget> m_widget;
|
WeakPtr<GWidget> m_widget;
|
||||||
|
WeakPtr<GActionGroup> m_action_group;
|
||||||
};
|
};
|
||||||
|
|
14
Libraries/LibGUI/GActionGroup.cpp
Normal file
14
Libraries/LibGUI/GActionGroup.cpp
Normal 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);
|
||||||
|
}
|
35
Libraries/LibGUI/GActionGroup.h
Normal file
35
Libraries/LibGUI/GActionGroup.h
Normal 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 };
|
||||||
|
};
|
|
@ -1,7 +1,8 @@
|
||||||
#include "GButton.h"
|
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <Kernel/KeyCode.h>
|
#include <Kernel/KeyCode.h>
|
||||||
#include <LibGUI/GAction.h>
|
#include <LibGUI/GAction.h>
|
||||||
|
#include <LibGUI/GActionGroup.h>
|
||||||
|
#include <LibGUI/GButton.h>
|
||||||
#include <LibGUI/GPainter.h>
|
#include <LibGUI/GPainter.h>
|
||||||
#include <SharedGraphics/StylePainter.h>
|
#include <SharedGraphics/StylePainter.h>
|
||||||
|
|
||||||
|
@ -60,8 +61,11 @@ void GButton::click()
|
||||||
{
|
{
|
||||||
if (!is_enabled())
|
if (!is_enabled())
|
||||||
return;
|
return;
|
||||||
if (is_checkable())
|
if (is_checkable()) {
|
||||||
|
if (is_checked() && !is_uncheckable())
|
||||||
|
return;
|
||||||
set_checked(!is_checked());
|
set_checked(!is_checked());
|
||||||
|
}
|
||||||
if (on_click)
|
if (on_click)
|
||||||
on_click(*this);
|
on_click(*this);
|
||||||
}
|
}
|
||||||
|
@ -88,3 +92,12 @@ void GButton::set_icon(RefPtr<GraphicsBitmap>&& icon)
|
||||||
m_icon = move(icon);
|
m_icon = move(icon);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GButton::is_uncheckable() const
|
||||||
|
{
|
||||||
|
if (!m_action)
|
||||||
|
return true;
|
||||||
|
if (!m_action->group())
|
||||||
|
return true;
|
||||||
|
return m_action->group()->is_unchecking_allowed();
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ public:
|
||||||
virtual const char* class_name() const override { return "GButton"; }
|
virtual const char* class_name() const override { return "GButton"; }
|
||||||
virtual bool accepts_focus() const override { return m_focusable; }
|
virtual bool accepts_focus() const override { return m_focusable; }
|
||||||
virtual bool supports_keyboard_activation() const override;
|
virtual bool supports_keyboard_activation() const override;
|
||||||
|
virtual bool is_uncheckable() const override;
|
||||||
|
|
||||||
void set_focusable(bool b) { m_focusable = b; }
|
void set_focusable(bool b) { m_focusable = b; }
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ LIBGUI_OBJS = \
|
||||||
GMenuItem.o \
|
GMenuItem.o \
|
||||||
GApplication.o \
|
GApplication.o \
|
||||||
GAction.o \
|
GAction.o \
|
||||||
|
GActionGroup.o \
|
||||||
GFontDatabase.o \
|
GFontDatabase.o \
|
||||||
GToolBar.o \
|
GToolBar.o \
|
||||||
GTableView.o \
|
GTableView.o \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue