mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-20 03:25:13 +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
Notes:
sideshowbarker
2024-07-19 13:21:12 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/7083a0104ab
9 changed files with 97 additions and 6 deletions
|
@ -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&) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
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 <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();
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ LIBGUI_OBJS = \
|
|||
GMenuItem.o \
|
||||
GApplication.o \
|
||||
GAction.o \
|
||||
GActionGroup.o \
|
||||
GFontDatabase.o \
|
||||
GToolBar.o \
|
||||
GTableView.o \
|
||||
|
|
Loading…
Add table
Reference in a new issue