mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-19 17:27:51 +03: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:
parent
4804609b7e
commit
b704d3d295
Notes:
sideshowbarker
2024-07-19 15:40:07 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/b704d3d295d
@ -3,47 +3,52 @@
|
||||
#include <LibGUI/GBoxLayout.h>
|
||||
#include <LibGUI/GApplication.h>
|
||||
#include <LibGUI/GStatusBar.h>
|
||||
#include <LibGUI/GToolBar.h>
|
||||
#include <LibGUI/GMenuBar.h>
|
||||
#include <LibGUI/GAction.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include "DirectoryView.h"
|
||||
|
||||
static GWindow* make_window();
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
GApplication app(argc, argv);
|
||||
|
||||
auto mkdir_action = GAction::create("New directory...", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/mkdir16.rgb", { 16, 16 }), [] (const GAction&) {
|
||||
dbgprintf("'New directory' action activated!\n");
|
||||
});
|
||||
|
||||
auto copy_action = GAction::create("Copy", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/copyfile16.rgb", { 16, 16 }), [] (const GAction&) {
|
||||
dbgprintf("'Copy' action activated!\n");
|
||||
});
|
||||
|
||||
auto delete_action = GAction::create("Delete", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/trash16.rgb", { 16, 16 }), [] (const GAction&) {
|
||||
dbgprintf("'Delete' action activated!\n");
|
||||
});
|
||||
|
||||
auto menubar = make<GMenuBar>();
|
||||
|
||||
auto app_menu = make<GMenu>("FileManager");
|
||||
app_menu->add_action(make<GAction>("Quit", String(), [] (const GAction&) {
|
||||
app_menu->add_action(GAction::create("Quit", String(), [] (const GAction&) {
|
||||
GApplication::the().quit(0);
|
||||
return;
|
||||
}));
|
||||
menubar->add_menu(move(app_menu));
|
||||
|
||||
auto file_menu = make<GMenu>("File");
|
||||
file_menu->add_action(mkdir_action.copy_ref());
|
||||
file_menu->add_action(copy_action.copy_ref());
|
||||
file_menu->add_action(delete_action.copy_ref());
|
||||
menubar->add_menu(move(file_menu));
|
||||
|
||||
auto help_menu = make<GMenu>("Help");
|
||||
help_menu->add_action(make<GAction>("About", [] (const GAction&) {
|
||||
help_menu->add_action(GAction::create("About", [] (const GAction&) {
|
||||
dbgprintf("FIXME: Implement Help/About\n");
|
||||
}));
|
||||
menubar->add_menu(move(help_menu));
|
||||
|
||||
app.set_menubar(move(menubar));
|
||||
|
||||
auto* window = make_window();
|
||||
window->set_should_exit_app_on_close(true);
|
||||
window->show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
GWindow* make_window()
|
||||
{
|
||||
auto* window = new GWindow;
|
||||
window->set_title("FileManager");
|
||||
window->set_rect(20, 200, 240, 300);
|
||||
@ -53,6 +58,11 @@ GWindow* make_window()
|
||||
|
||||
widget->set_layout(make<GBoxLayout>(Orientation::Vertical));
|
||||
|
||||
auto* toolbar = new GToolBar(widget);
|
||||
toolbar->add_action(mkdir_action.copy_ref());
|
||||
toolbar->add_action(copy_action.copy_ref());
|
||||
toolbar->add_action(delete_action.copy_ref());
|
||||
|
||||
auto* directory_view = new DirectoryView(widget);
|
||||
|
||||
auto* statusbar = new GStatusBar(widget);
|
||||
@ -68,6 +78,8 @@ GWindow* make_window()
|
||||
|
||||
directory_view->open("/");
|
||||
|
||||
return window;
|
||||
}
|
||||
window->set_should_exit_app_on_close(true);
|
||||
window->show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ int main(int argc, char** argv)
|
||||
auto menubar = make<GMenuBar>();
|
||||
|
||||
auto app_menu = make<GMenu>("Terminal");
|
||||
app_menu->add_action(make<GAction>("Quit", String(), [] (const GAction&) {
|
||||
app_menu->add_action(GAction::create("Quit", String(), [] (const GAction&) {
|
||||
dbgprintf("Terminal: Quit menu activated!\n");
|
||||
GApplication::the().quit(0);
|
||||
return;
|
||||
@ -106,7 +106,7 @@ int main(int argc, char** argv)
|
||||
|
||||
auto font_menu = make<GMenu>("Font");
|
||||
GFontDatabase::the().for_each_font([&] (const String& font_name) {
|
||||
font_menu->add_action(make<GAction>(font_name, [&terminal] (const GAction& action) {
|
||||
font_menu->add_action(GAction::create(font_name, [&terminal] (const GAction& action) {
|
||||
terminal.set_font(GFontDatabase::the().get_by_name(action.text()));
|
||||
terminal.force_repaint();
|
||||
}));
|
||||
@ -114,7 +114,7 @@ int main(int argc, char** argv)
|
||||
menubar->add_menu(move(font_menu));
|
||||
|
||||
auto help_menu = make<GMenu>("Help");
|
||||
help_menu->add_action(make<GAction>("About", [] (const GAction&) {
|
||||
help_menu->add_action(GAction::create("About", [] (const GAction&) {
|
||||
dbgprintf("FIXME: Implement Help/About\n");
|
||||
}));
|
||||
menubar->add_menu(move(help_menu));
|
||||
|
BIN
Base/res/icons/copyfile16.data
Normal file
BIN
Base/res/icons/copyfile16.data
Normal file
Binary file not shown.
BIN
Base/res/icons/copyfile16.png
Normal file
BIN
Base/res/icons/copyfile16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
Base/res/icons/copyfile16.rgb
Normal file
BIN
Base/res/icons/copyfile16.rgb
Normal file
Binary file not shown.
BIN
Base/res/icons/mkdir16.data
Normal file
BIN
Base/res/icons/mkdir16.data
Normal file
Binary file not shown.
BIN
Base/res/icons/mkdir16.png
Normal file
BIN
Base/res/icons/mkdir16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
Base/res/icons/mkdir16.rgb
Normal file
BIN
Base/res/icons/mkdir16.rgb
Normal file
Binary file not shown.
BIN
Base/res/icons/trash16.data
Normal file
BIN
Base/res/icons/trash16.data
Normal file
Binary file not shown.
BIN
Base/res/icons/trash16.png
Normal file
BIN
Base/res/icons/trash16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 452 B |
BIN
Base/res/icons/trash16.rgb
Normal file
BIN
Base/res/icons/trash16.rgb
Normal file
Binary file not shown.
@ -195,6 +195,36 @@ void exception_7_handler(RegisterDump& regs)
|
||||
}
|
||||
|
||||
|
||||
// 0: Divide error
|
||||
EH_ENTRY_NO_CODE(0);
|
||||
void exception_0_handler(RegisterDump& regs)
|
||||
{
|
||||
kprintf("%s DIVIDE ERROR: %u(%s)\n", current->is_ring0() ? "Kernel" : "User", current->pid(), current->name().characters());
|
||||
|
||||
word ss;
|
||||
dword esp;
|
||||
if (current->is_ring0()) {
|
||||
ss = regs.ds;
|
||||
esp = regs.esp;
|
||||
} else {
|
||||
ss = regs.ss_if_crossRing;
|
||||
esp = regs.esp_if_crossRing;
|
||||
}
|
||||
|
||||
kprintf("pc=%w:%x ds=%w es=%w fs=%w gs=%w\n", regs.cs, regs.eip, regs.ds, regs.es, regs.fs, regs.gs);
|
||||
kprintf("stk=%w:%x\n", ss, esp);
|
||||
kprintf("eax=%x ebx=%x ecx=%x edx=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx);
|
||||
kprintf("ebp=%x esp=%x esi=%x edi=%x\n", regs.ebp, esp, regs.esi, regs.edi);
|
||||
|
||||
if (current->is_ring0()) {
|
||||
kprintf("Oh shit, we've crashed in ring 0 :(\n");
|
||||
hang();
|
||||
}
|
||||
|
||||
current->crash();
|
||||
}
|
||||
|
||||
|
||||
// 13: General Protection Fault
|
||||
EH_ENTRY(13);
|
||||
void exception_13_handler(RegisterDumpWithExceptionCode& regs)
|
||||
@ -316,7 +346,6 @@ void exception_14_handler(RegisterDumpWithExceptionCode& regs)
|
||||
hang(); \
|
||||
}
|
||||
|
||||
EH(0, "Divide error")
|
||||
EH(1, "Debug exception")
|
||||
EH(2, "Unknown error")
|
||||
EH(3, "Breakpoint")
|
||||
@ -442,7 +471,7 @@ void idt_init()
|
||||
for (byte i = 0xff; i > 0x10; --i)
|
||||
register_interrupt_handler(i, unimp_trap);
|
||||
|
||||
register_interrupt_handler(0x00, _exception0);
|
||||
register_interrupt_handler(0x00, exception_0_entry);
|
||||
register_interrupt_handler(0x01, _exception1);
|
||||
register_interrupt_handler(0x02, _exception2);
|
||||
register_interrupt_handler(0x03, _exception3);
|
||||
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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
58
LibGUI/GToolBar.cpp
Normal 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
25
LibGUI/GToolBar.h
Normal 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;
|
||||
};
|
@ -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()) {
|
||||
|
@ -27,6 +27,7 @@ LIBGUI_OBJS = \
|
||||
GApplication.o \
|
||||
GAction.o \
|
||||
GFontDatabase.o \
|
||||
GToolBar.o \
|
||||
GWindow.o
|
||||
|
||||
OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS)
|
||||
|
@ -14,8 +14,6 @@
|
||||
#include <LibC/string.h>
|
||||
#endif
|
||||
|
||||
#define DEBUG_WIDGET_UNDERDRAW
|
||||
|
||||
Painter::Painter(GraphicsBitmap& bitmap)
|
||||
{
|
||||
m_font = &Font::default_font();
|
||||
@ -42,12 +40,6 @@ Painter::Painter(GWidget& widget)
|
||||
// NOTE: m_clip_rect is in Window coordinates since we are painting into its backing store.
|
||||
m_clip_rect = widget.window_relative_rect();
|
||||
m_clip_rect.intersect(m_target->rect());
|
||||
|
||||
#ifdef DEBUG_WIDGET_UNDERDRAW
|
||||
// If the widget is not opaque, let's not mess it up with debugging color.
|
||||
if (widget.fill_with_background_color() && m_window->main_widget() != &widget)
|
||||
fill_rect(widget.rect(), Color::Red);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user