diff --git a/Applications/Terminal/main.cpp b/Applications/Terminal/main.cpp index 4f981d18154..eb20db6fe48 100644 --- a/Applications/Terminal/main.cpp +++ b/Applications/Terminal/main.cpp @@ -14,6 +14,7 @@ #include #include #include +#include static void make_shell(int ptm_fd) { @@ -95,38 +96,28 @@ int main(int argc, char** argv) auto menubar = make(); auto app_menu = make("Terminal"); - app_menu->add_item(0, "Quit"); - app_menu->on_item_activation = [] (unsigned identifier) { - if (identifier == 0) { - dbgprintf("Terminal: Quit menu activated!\n"); - GApplication::the().exit(0); - return; - } - }; + app_menu->add_action(make("Quit", String(), [] (const GAction&) { + dbgprintf("Terminal: Quit menu activated!\n"); + GApplication::the().exit(0); + return; + })); menubar->add_menu(move(app_menu)); auto font_menu = make("Font"); - font_menu->add_item(0, "Liza Thin"); - font_menu->add_item(1, "Liza Regular"); - font_menu->add_item(2, "Liza Bold"); - font_menu->on_item_activation = [&terminal] (unsigned identifier) { - switch (identifier) { - case 0: - terminal.set_font(Font::load_from_file("/res/fonts/LizaThin8x10.font")); - break; - case 1: - terminal.set_font(Font::load_from_file("/res/fonts/LizaRegular8x10.font")); - break; - case 2: - terminal.set_font(Font::load_from_file("/res/fonts/LizaBold8x10.font")); - break; - } + auto handle_font_selection = [&terminal] (const GAction& action) { + terminal.set_font(Font::load_from_file(action.custom_data())); terminal.force_repaint(); }; + font_menu->add_action(make("Liza Thin", "/res/fonts/LizaThin8x10.font", move(handle_font_selection))); + font_menu->add_action(make("Liza Regular", "/res/fonts/LizaRegular8x10.font", move(handle_font_selection))); + font_menu->add_action(make("Liza Bold", "/res/fonts/LizaBold8x10.font", move(handle_font_selection))); + menubar->add_menu(move(font_menu)); auto help_menu = make("Help"); - help_menu->add_item(0, "About"); + help_menu->add_action(make("About", [] (const GAction&) { + dbgprintf("FIXME: Implement Help/About\n"); + })); menubar->add_menu(move(help_menu)); app.set_menubar(move(menubar)); diff --git a/LibGUI/GAction.cpp b/LibGUI/GAction.cpp new file mode 100644 index 00000000000..1d04ea1bcb3 --- /dev/null +++ b/LibGUI/GAction.cpp @@ -0,0 +1,23 @@ +#include + +GAction::GAction(const String& text, const String& custom_data, Function on_activation_callback) + : m_text(text) + , on_activation(move(on_activation_callback)) + , m_custom_data(custom_data) +{ +} + +GAction::GAction(const String& text, Function on_activation_callback) + : GAction(text, String(), move(on_activation_callback)) +{ +} + +GAction::~GAction() +{ +} + +void GAction::activate() +{ + if (on_activation) + on_activation(*this); +} diff --git a/LibGUI/GAction.h b/LibGUI/GAction.h new file mode 100644 index 00000000000..6e2bea04042 --- /dev/null +++ b/LibGUI/GAction.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +class GAction { +public: + GAction(const String& text, Function = nullptr); + GAction(const String& text, const String& custom_data = String(), Function = nullptr); + ~GAction(); + + String text() const { return m_text; } + String custom_data() const { return m_custom_data; } + + Function on_activation; + + void activate(); + +private: + String m_text; + String m_custom_data; +}; + diff --git a/LibGUI/GEventLoop.cpp b/LibGUI/GEventLoop.cpp index 70f38eb9eae..49d171c2373 100644 --- a/LibGUI/GEventLoop.cpp +++ b/LibGUI/GEventLoop.cpp @@ -2,6 +2,7 @@ #include "GEvent.h" #include "GObject.h" #include "GWindow.h" +#include #include #include #include @@ -156,8 +157,8 @@ void GEventLoop::handle_menu_event(const GUI_Event& event) dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id); return; } - if (menu->on_item_activation) - menu->on_item_activation(event.menu.identifier); + if (auto* action = menu->action_at(event.menu.identifier)) + action->activate(); return; } ASSERT_NOT_REACHED(); diff --git a/LibGUI/GMenu.cpp b/LibGUI/GMenu.cpp index 923fb784f92..439a71d9cd6 100644 --- a/LibGUI/GMenu.cpp +++ b/LibGUI/GMenu.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -32,26 +33,38 @@ GMenu::~GMenu() } } -void GMenu::add_item(unsigned identifier, const String& text) +void GMenu::add_action(OwnPtr&& action) { - m_items.append({ identifier, text }); + m_items.append(make(move(action))); } void GMenu::add_separator() { - m_items.append(GMenuItem(GMenuItem::Separator)); + m_items.append(make(GMenuItem::Separator)); } int GMenu::realize_menu() { m_menu_id = gui_menu_create(m_name.characters()); ASSERT(m_menu_id > 0); - for (auto& item : m_items) { - if (item.type() == GMenuItem::Separator) + for (size_t i = 0; i < m_items.size(); ++i) { + auto& item = *m_items[i]; + if (item.type() == GMenuItem::Separator) { gui_menu_add_separator(m_menu_id); - else if (item.type() == GMenuItem::Text) - gui_menu_add_item(m_menu_id, item.identifier(), item.text().characters()); + continue; + } + if (item.type() == GMenuItem::Action) { + auto& action = *item.action(); + gui_menu_add_item(m_menu_id, i, action.text().characters()); + } } all_menus().set(m_menu_id, this); return m_menu_id; } + +GAction* GMenu::action_at(size_t index) +{ + if (index >= m_items.size()) + return nullptr; + return m_items[index]->action(); +} diff --git a/LibGUI/GMenu.h b/LibGUI/GMenu.h index 3eeed3527fe..dceaad72eb8 100644 --- a/LibGUI/GMenu.h +++ b/LibGUI/GMenu.h @@ -4,6 +4,8 @@ #include #include +class GAction; + class GMenu { public: explicit GMenu(const String& name); @@ -11,7 +13,9 @@ public: static GMenu* from_menu_id(int); - void add_item(unsigned identifier, const String& text); + GAction* action_at(size_t); + + void add_action(OwnPtr&&); void add_separator(); Function on_item_activation; @@ -23,5 +27,5 @@ private: int m_menu_id { 0 }; String m_name; - Vector m_items; + Vector> m_items; }; diff --git a/LibGUI/GMenuItem.cpp b/LibGUI/GMenuItem.cpp index 0aebf1cf6d9..42900548ae7 100644 --- a/LibGUI/GMenuItem.cpp +++ b/LibGUI/GMenuItem.cpp @@ -1,14 +1,14 @@ #include +#include GMenuItem::GMenuItem(Type type) : m_type(type) { } -GMenuItem::GMenuItem(unsigned identifier, const String& text) - : m_type(Text) - , m_identifier(identifier) - , m_text(text) +GMenuItem::GMenuItem(OwnPtr&& action) + : m_type(Action) + , m_action(move(action)) { } diff --git a/LibGUI/GMenuItem.h b/LibGUI/GMenuItem.h index 48675e303f9..383c1b00fef 100644 --- a/LibGUI/GMenuItem.h +++ b/LibGUI/GMenuItem.h @@ -2,21 +2,25 @@ #include +class GAction; + class GMenuItem { public: - enum Type { Invalid, Text, Separator }; + enum Type { Invalid, Action, Separator }; explicit GMenuItem(Type); - GMenuItem(unsigned identifier, const String& text); + explicit GMenuItem(OwnPtr&&); ~GMenuItem(); Type type() const { return m_type; } - String text() const { return m_text; } + String text() const; + const GAction* action() const { return m_action.ptr(); } + GAction* action() { return m_action.ptr(); } unsigned identifier() const { return m_identifier; } private: Type m_type { Invalid }; unsigned m_identifier { 0 }; - String m_text; + OwnPtr m_action; }; diff --git a/LibGUI/Makefile b/LibGUI/Makefile index 928a91dc5a2..f148566f5dd 100644 --- a/LibGUI/Makefile +++ b/LibGUI/Makefile @@ -25,6 +25,7 @@ LIBGUI_OBJS = \ GMenu.o \ GMenuItem.o \ GApplication.o \ + GAction.o \ GWindow.o OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS)