1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 22:57:34 +00:00

LibGUI: Add a GToolBar class that can be populated with GActions.

The same action can be added to both a menu and a toolbar.
Use this to put a toolbar into FileManager. This is pretty neat. :^)
This commit is contained in:
Andreas Kling 2019-02-20 02:39:46 +01:00
parent 4804609b7e
commit b704d3d295
24 changed files with 196 additions and 44 deletions

View file

@ -1,8 +1,8 @@
#include <LibGUI/GAction.h>
GAction::GAction(const String& text, const String& custom_data, Function<void(const GAction&)> on_activation_callback)
: m_text(text)
, on_activation(move(on_activation_callback))
: on_activation(move(on_activation_callback))
, m_text(text)
, m_custom_data(custom_data)
{
}
@ -12,6 +12,13 @@ GAction::GAction(const String& text, Function<void(const GAction&)> on_activatio
{
}
GAction::GAction(const String& text, RetainPtr<GraphicsBitmap>&& icon, Function<void(const GAction&)> on_activation_callback)
: on_activation(move(on_activation_callback))
, m_text(text)
, m_icon(move(icon))
{
}
GAction::~GAction()
{
}

View file

@ -2,22 +2,41 @@
#include <AK/AKString.h>
#include <AK/Function.h>
#include <AK/Retainable.h>
#include <AK/RetainPtr.h>
#include <SharedGraphics/GraphicsBitmap.h>
class GAction {
class GAction : public Retainable<GAction> {
public:
GAction(const String& text, Function<void(const GAction&)> = nullptr);
GAction(const String& text, const String& custom_data = String(), Function<void(const GAction&)> = nullptr);
static RetainPtr<GAction> create(const String& text, Function<void(const GAction&)> callback)
{
return adopt(*new GAction(text, move(callback)));
}
static RetainPtr<GAction> create(const String& text, const String& custom_data, Function<void(const GAction&)> callback)
{
return adopt(*new GAction(text, custom_data, move(callback)));
}
static RetainPtr<GAction> create(const String& text, RetainPtr<GraphicsBitmap>&& icon, Function<void(const GAction&)> callback)
{
return adopt(*new GAction(text, move(icon), move(callback)));
}
~GAction();
String text() const { return m_text; }
String custom_data() const { return m_custom_data; }
const GraphicsBitmap* icon() const { return m_icon.ptr(); }
Function<void(GAction&)> on_activation;
void activate();
private:
GAction(const String& text, Function<void(const GAction&)> = nullptr);
GAction(const String& text, RetainPtr<GraphicsBitmap>&& icon, Function<void(const GAction&)> = nullptr);
GAction(const String& text, const String& custom_data = String(), Function<void(const GAction&)> = nullptr);
String m_text;
String m_custom_data;
RetainPtr<GraphicsBitmap> m_icon;
};

View file

@ -52,12 +52,14 @@ void GBoxLayout::run(GWidget& widget)
Size automatic_size;
if (m_orientation == Orientation::Horizontal) {
automatic_size.set_width(available_size.width() / number_of_entries_with_automatic_size);
automatic_size.set_height(widget.height());
} else {
automatic_size.set_width(widget.width());
automatic_size.set_height(available_size.height() / number_of_entries_with_automatic_size);
if (number_of_entries_with_automatic_size) {
if (m_orientation == Orientation::Horizontal) {
automatic_size.set_width(available_size.width() / number_of_entries_with_automatic_size);
automatic_size.set_height(widget.height());
} else {
automatic_size.set_width(widget.width());
automatic_size.set_height(available_size.height() / number_of_entries_with_automatic_size);
}
}
#ifdef GBOXLAYOUT_DEBUG

View file

@ -29,7 +29,7 @@ GMenu::~GMenu()
unrealize_menu();
}
void GMenu::add_action(OwnPtr<GAction>&& action)
void GMenu::add_action(RetainPtr<GAction>&& action)
{
m_items.append(make<GMenuItem>(move(action)));
}

View file

@ -15,7 +15,7 @@ public:
GAction* action_at(size_t);
void add_action(OwnPtr<GAction>&&);
void add_action(RetainPtr<GAction>&&);
void add_separator();
Function<void(unsigned)> on_item_activation;

View file

@ -6,7 +6,7 @@ GMenuItem::GMenuItem(Type type)
{
}
GMenuItem::GMenuItem(OwnPtr<GAction>&& action)
GMenuItem::GMenuItem(RetainPtr<GAction>&& action)
: m_type(Action)
, m_action(move(action))
{

View file

@ -9,7 +9,7 @@ public:
enum Type { Invalid, Action, Separator };
explicit GMenuItem(Type);
explicit GMenuItem(OwnPtr<GAction>&&);
explicit GMenuItem(RetainPtr<GAction>&&);
~GMenuItem();
Type type() const { return m_type; }
@ -21,6 +21,6 @@ public:
private:
Type m_type { Invalid };
unsigned m_identifier { 0 };
OwnPtr<GAction> m_action;
RetainPtr<GAction> m_action;
};

58
LibGUI/GToolBar.cpp Normal file
View file

@ -0,0 +1,58 @@
#include <LibGUI/GToolBar.h>
#include <LibGUI/GBoxLayout.h>
#include <LibGUI/GButton.h>
#include <LibGUI/GAction.h>
#include <SharedGraphics/Painter.h>
GToolBar::GToolBar(GWidget* parent)
: GWidget(parent)
{
set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
set_preferred_size({ 0, 24 });
set_layout(make<GBoxLayout>(Orientation::Horizontal));
}
GToolBar::~GToolBar()
{
}
void GToolBar::add_action(RetainPtr<GAction>&& action)
{
ASSERT(action);
GAction* raw_action_ptr = action.ptr();
auto item = make<Item>();
item->type = Item::Action;
item->action = move(action);
auto* button = new GButton(this);
if (item->action->icon())
button->set_icon(item->action->icon());
else
button->set_caption(item->action->text());
button->on_click = [raw_action_ptr] (const GButton&) {
raw_action_ptr->activate();
};
#if 0
// FIXME: Gotta fix GBoxLayout for this to work.
button->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
button->set_preferred_size({ 16, 16 });
#endif
m_items.append(move(item));
}
void GToolBar::add_separator()
{
auto item = make<Item>();
item->type = Item::Separator;
m_items.append(move(item));
}
void GToolBar::paint_event(GPaintEvent& event)
{
Painter painter(*this);
painter.set_clip_rect(event.rect());
painter.fill_rect({ 0, 0, width(), height() - 1 }, Color::LightGray);
painter.draw_line({ 0, rect().bottom() }, { width() - 1, rect().bottom() }, Color::DarkGray);
}

25
LibGUI/GToolBar.h Normal file
View file

@ -0,0 +1,25 @@
#pragma once
#include <LibGUI/GWidget.h>
class GAction;
class GToolBar : public GWidget {
public:
explicit GToolBar(GWidget* parent);
virtual ~GToolBar() override;
void add_action(RetainPtr<GAction>&&);
void add_separator();
private:
virtual const char* class_name() const override { return "GToolBar"; }
virtual void paint_event(GPaintEvent&) override;
struct Item {
enum Type { Invalid, Separator, Action };
Type type { Invalid };
RetainPtr<GAction> action;
};
Vector<OwnPtr<Item>> m_items;
};

View file

@ -73,6 +73,13 @@ void GWidget::handle_paint_event(GPaintEvent& event)
if (fill_with_background_color()) {
Painter painter(*this);
painter.fill_rect(event.rect(), background_color());
} else {
#ifdef DEBUG_WIDGET_UNDERDRAW
// FIXME: This is a bit broken.
// If the widget is not opaque, let's not mess it up with debugging color.
Painter painter(*this);
painter.fill_rect(rect(), Color::Red);
#endif
}
paint_event(event);
for (auto* ch : children()) {

View file

@ -27,6 +27,7 @@ LIBGUI_OBJS = \
GApplication.o \
GAction.o \
GFontDatabase.o \
GToolBar.o \
GWindow.o
OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS)