mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 03:27:44 +00:00
LibGUI+WindowServer: Add support for enabled/disabled actions.
The enabled state of a GAction now propagates both to any toolbar buttons and any menu items linked to the action. Toolbar buttons are painted in a grayed out style when disabled. Menu items are gray when disabled. :^)
This commit is contained in:
parent
32e5c8c689
commit
054c982181
20 changed files with 308 additions and 53 deletions
|
@ -128,16 +128,21 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
toolbar->add_separator();
|
toolbar->add_separator();
|
||||||
|
|
||||||
toolbar->add_action(move(cut_action));
|
toolbar->add_action(cut_action.copy_ref());
|
||||||
toolbar->add_action(move(copy_action));
|
toolbar->add_action(copy_action.copy_ref());
|
||||||
toolbar->add_action(move(paste_action));
|
toolbar->add_action(move(paste_action));
|
||||||
toolbar->add_action(move(delete_action));
|
toolbar->add_action(delete_action.copy_ref());
|
||||||
|
|
||||||
toolbar->add_separator();
|
toolbar->add_separator();
|
||||||
|
|
||||||
toolbar->add_action(move(undo_action));
|
toolbar->add_action(move(undo_action));
|
||||||
toolbar->add_action(move(redo_action));
|
toolbar->add_action(move(redo_action));
|
||||||
|
|
||||||
|
text_editor->on_selection_change = [&] {
|
||||||
|
cut_action->set_enabled(text_editor->has_selection());
|
||||||
|
copy_action->set_enabled(text_editor->has_selection());
|
||||||
|
};
|
||||||
|
|
||||||
auto* window = new GWindow;
|
auto* window = new GWindow;
|
||||||
window->set_title(String::format("TextEditor: %s", path.characters()));
|
window->set_title(String::format("TextEditor: %s", path.characters()));
|
||||||
window->set_rect(20, 200, 640, 400);
|
window->set_rect(20, 200, 640, 400);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include <LibGUI/GAction.h>
|
#include <LibGUI/GAction.h>
|
||||||
#include <LibGUI/GApplication.h>
|
#include <LibGUI/GApplication.h>
|
||||||
|
#include <LibGUI/GButton.h>
|
||||||
|
#include <LibGUI/GMenuItem.h>
|
||||||
|
|
||||||
GAction::GAction(const String& text, const String& custom_data, Function<void(const GAction&)> on_activation_callback)
|
GAction::GAction(const String& text, const String& custom_data, Function<void(const GAction&)> on_activation_callback)
|
||||||
: on_activation(move(on_activation_callback))
|
: on_activation(move(on_activation_callback))
|
||||||
|
@ -46,3 +48,50 @@ void GAction::activate()
|
||||||
if (on_activation)
|
if (on_activation)
|
||||||
on_activation(*this);
|
on_activation(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GAction::register_button(Badge<GButton>, GButton& button)
|
||||||
|
{
|
||||||
|
m_buttons.set(&button);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAction::unregister_button(Badge<GButton>, GButton& button)
|
||||||
|
{
|
||||||
|
m_buttons.remove(&button);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAction::register_menu_item(Badge<GMenuItem>, GMenuItem& menu_item)
|
||||||
|
{
|
||||||
|
m_menu_items.set(&menu_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAction::unregister_menu_item(Badge<GMenuItem>, GMenuItem& menu_item)
|
||||||
|
{
|
||||||
|
m_menu_items.remove(&menu_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Callback>
|
||||||
|
void GAction::for_each_toolbar_button(Callback callback)
|
||||||
|
{
|
||||||
|
for (auto& it : m_buttons)
|
||||||
|
callback(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Callback>
|
||||||
|
void GAction::for_each_menu_item(Callback callback)
|
||||||
|
{
|
||||||
|
for (auto& it : m_menu_items)
|
||||||
|
callback(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GAction::set_enabled(bool enabled)
|
||||||
|
{
|
||||||
|
if (m_enabled == enabled)
|
||||||
|
return;
|
||||||
|
m_enabled = enabled;
|
||||||
|
for_each_toolbar_button([enabled] (GButton& button) {
|
||||||
|
button.set_enabled(enabled);
|
||||||
|
});
|
||||||
|
for_each_menu_item([enabled] (GMenuItem& item) {
|
||||||
|
item.set_enabled(enabled);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -4,10 +4,16 @@
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <AK/Retainable.h>
|
#include <AK/Retainable.h>
|
||||||
#include <AK/Retained.h>
|
#include <AK/Retained.h>
|
||||||
|
#include <AK/Weakable.h>
|
||||||
|
#include <AK/Badge.h>
|
||||||
|
#include <AK/HashTable.h>
|
||||||
#include <SharedGraphics/GraphicsBitmap.h>
|
#include <SharedGraphics/GraphicsBitmap.h>
|
||||||
#include <LibGUI/GShortcut.h>
|
#include <LibGUI/GShortcut.h>
|
||||||
|
|
||||||
class GAction : public Retainable<GAction> {
|
class GButton;
|
||||||
|
class GMenuItem;
|
||||||
|
|
||||||
|
class GAction : public Retainable<GAction>, public Weakable<GAction> {
|
||||||
public:
|
public:
|
||||||
static Retained<GAction> create(const String& text, Function<void(const GAction&)> callback)
|
static Retained<GAction> create(const String& text, Function<void(const GAction&)> callback)
|
||||||
{
|
{
|
||||||
|
@ -40,6 +46,14 @@ public:
|
||||||
|
|
||||||
void activate();
|
void activate();
|
||||||
|
|
||||||
|
bool is_enabled() const { return m_enabled; }
|
||||||
|
void set_enabled(bool);
|
||||||
|
|
||||||
|
void register_button(Badge<GButton>, GButton&);
|
||||||
|
void unregister_button(Badge<GButton>, GButton&);
|
||||||
|
void register_menu_item(Badge<GMenuItem>, GMenuItem&);
|
||||||
|
void unregister_menu_item(Badge<GMenuItem>, GMenuItem&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GAction(const String& text, Function<void(const GAction&)> = nullptr);
|
GAction(const String& text, Function<void(const GAction&)> = nullptr);
|
||||||
GAction(const String& text, const GShortcut&, Function<void(const GAction&)> = nullptr);
|
GAction(const String& text, const GShortcut&, Function<void(const GAction&)> = nullptr);
|
||||||
|
@ -47,9 +61,16 @@ private:
|
||||||
GAction(const String& text, RetainPtr<GraphicsBitmap>&& icon, 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);
|
GAction(const String& text, const String& custom_data = String(), Function<void(const GAction&)> = nullptr);
|
||||||
|
|
||||||
|
template<typename Callback> void for_each_toolbar_button(Callback);
|
||||||
|
template<typename Callback> void for_each_menu_item(Callback);
|
||||||
|
|
||||||
String m_text;
|
String m_text;
|
||||||
String m_custom_data;
|
String m_custom_data;
|
||||||
RetainPtr<GraphicsBitmap> m_icon;
|
RetainPtr<GraphicsBitmap> m_icon;
|
||||||
GShortcut m_shortcut;
|
GShortcut m_shortcut;
|
||||||
|
bool m_enabled { true };
|
||||||
|
|
||||||
|
HashTable<GButton*> m_buttons;
|
||||||
|
HashTable<GMenuItem*> m_menu_items;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <LibGUI/GPainter.h>
|
#include <LibGUI/GPainter.h>
|
||||||
#include <SharedGraphics/StylePainter.h>
|
#include <SharedGraphics/StylePainter.h>
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
|
#include <LibGUI/GAction.h>
|
||||||
|
|
||||||
//#define GBUTTON_DEBUG
|
//#define GBUTTON_DEBUG
|
||||||
|
|
||||||
|
@ -12,6 +13,8 @@ GButton::GButton(GWidget* parent)
|
||||||
|
|
||||||
GButton::~GButton()
|
GButton::~GButton()
|
||||||
{
|
{
|
||||||
|
if (m_action)
|
||||||
|
m_action->unregister_button({ }, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GButton::set_caption(const String& caption)
|
void GButton::set_caption(const String& caption)
|
||||||
|
@ -35,7 +38,7 @@ void GButton::paint_event(GPaintEvent& event)
|
||||||
GPainter painter(*this);
|
GPainter painter(*this);
|
||||||
painter.add_clip_rect(event.rect());
|
painter.add_clip_rect(event.rect());
|
||||||
|
|
||||||
StylePainter::paint_button(painter, rect(), m_button_style, m_being_pressed, m_hovered, m_checkable && m_checked);
|
StylePainter::paint_button(painter, rect(), m_button_style, m_being_pressed, m_hovered, m_checkable && m_checked, is_enabled());
|
||||||
|
|
||||||
if (m_caption.is_empty() && !m_icon)
|
if (m_caption.is_empty() && !m_icon)
|
||||||
return;
|
return;
|
||||||
|
@ -46,8 +49,12 @@ void GButton::paint_event(GPaintEvent& event)
|
||||||
content_rect.move_by(1, 1);
|
content_rect.move_by(1, 1);
|
||||||
icon_location.move_by(1, 1);
|
icon_location.move_by(1, 1);
|
||||||
}
|
}
|
||||||
if (m_icon)
|
if (m_icon) {
|
||||||
painter.blit(icon_location, *m_icon, m_icon->rect());
|
if (is_enabled())
|
||||||
|
painter.blit(icon_location, *m_icon, m_icon->rect());
|
||||||
|
else
|
||||||
|
painter.blit_dimmed(icon_location, *m_icon, m_icon->rect());
|
||||||
|
}
|
||||||
auto& font = (m_checkable && m_checked) ? Font::default_bold_font() : this->font();
|
auto& font = (m_checkable && m_checked) ? Font::default_bold_font() : this->font();
|
||||||
painter.draw_text(content_rect, m_caption, font, text_alignment(), foreground_color(), TextElision::Right);
|
painter.draw_text(content_rect, m_caption, font, text_alignment(), foreground_color(), TextElision::Right);
|
||||||
}
|
}
|
||||||
|
@ -55,10 +62,12 @@ void GButton::paint_event(GPaintEvent& event)
|
||||||
void GButton::mousemove_event(GMouseEvent& event)
|
void GButton::mousemove_event(GMouseEvent& event)
|
||||||
{
|
{
|
||||||
if (event.buttons() == GMouseButton::Left) {
|
if (event.buttons() == GMouseButton::Left) {
|
||||||
bool being_pressed = rect().contains(event.position());
|
if (is_enabled()) {
|
||||||
if (being_pressed != m_being_pressed) {
|
bool being_pressed = rect().contains(event.position());
|
||||||
m_being_pressed = being_pressed;
|
if (being_pressed != m_being_pressed) {
|
||||||
update();
|
m_being_pressed = being_pressed;
|
||||||
|
update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GWidget::mousemove_event(event);
|
GWidget::mousemove_event(event);
|
||||||
|
@ -70,14 +79,18 @@ void GButton::mousedown_event(GMouseEvent& event)
|
||||||
dbgprintf("GButton::mouse_down_event: x=%d, y=%d, button=%u\n", event.x(), event.y(), (unsigned)event.button());
|
dbgprintf("GButton::mouse_down_event: x=%d, y=%d, button=%u\n", event.x(), event.y(), (unsigned)event.button());
|
||||||
#endif
|
#endif
|
||||||
if (event.button() == GMouseButton::Left) {
|
if (event.button() == GMouseButton::Left) {
|
||||||
m_being_pressed = true;
|
if (is_enabled()) {
|
||||||
update();
|
m_being_pressed = true;
|
||||||
|
update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GWidget::mousedown_event(event);
|
GWidget::mousedown_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GButton::click()
|
void GButton::click()
|
||||||
{
|
{
|
||||||
|
if (!is_enabled())
|
||||||
|
return;
|
||||||
if (on_click)
|
if (on_click)
|
||||||
on_click(*this);
|
on_click(*this);
|
||||||
}
|
}
|
||||||
|
@ -88,11 +101,13 @@ void GButton::mouseup_event(GMouseEvent& event)
|
||||||
dbgprintf("GButton::mouse_up_event: x=%d, y=%d, button=%u\n", event.x(), event.y(), (unsigned)event.button());
|
dbgprintf("GButton::mouse_up_event: x=%d, y=%d, button=%u\n", event.x(), event.y(), (unsigned)event.button());
|
||||||
#endif
|
#endif
|
||||||
if (event.button() == GMouseButton::Left) {
|
if (event.button() == GMouseButton::Left) {
|
||||||
bool was_being_pressed = m_being_pressed;
|
if (is_enabled()) {
|
||||||
m_being_pressed = false;
|
bool was_being_pressed = m_being_pressed;
|
||||||
update();
|
m_being_pressed = false;
|
||||||
if (was_being_pressed)
|
update();
|
||||||
click();
|
if (was_being_pressed)
|
||||||
|
click();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GWidget::mouseup_event(event);
|
GWidget::mouseup_event(event);
|
||||||
}
|
}
|
||||||
|
@ -108,3 +123,10 @@ void GButton::leave_event(CEvent&)
|
||||||
m_hovered = false;
|
m_hovered = false;
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GButton::set_action(GAction& action)
|
||||||
|
{
|
||||||
|
m_action = action.make_weak_ptr();
|
||||||
|
action.register_button({ }, *this);
|
||||||
|
set_enabled(action.is_enabled());
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include <SharedGraphics/GraphicsBitmap.h>
|
#include <SharedGraphics/GraphicsBitmap.h>
|
||||||
#include <SharedGraphics/TextAlignment.h>
|
#include <SharedGraphics/TextAlignment.h>
|
||||||
|
|
||||||
|
class GAction;
|
||||||
|
|
||||||
class GButton : public GWidget {
|
class GButton : public GWidget {
|
||||||
public:
|
public:
|
||||||
explicit GButton(GWidget* parent);
|
explicit GButton(GWidget* parent);
|
||||||
|
@ -35,6 +37,8 @@ public:
|
||||||
|
|
||||||
void click();
|
void click();
|
||||||
|
|
||||||
|
void set_action(GAction&);
|
||||||
|
|
||||||
virtual const char* class_name() const override { return "GButton"; }
|
virtual const char* class_name() const override { return "GButton"; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -49,6 +53,7 @@ private:
|
||||||
RetainPtr<GraphicsBitmap> m_icon;
|
RetainPtr<GraphicsBitmap> m_icon;
|
||||||
ButtonStyle m_button_style { ButtonStyle::Normal };
|
ButtonStyle m_button_style { ButtonStyle::Normal };
|
||||||
TextAlignment m_text_alignment { TextAlignment::Center };
|
TextAlignment m_text_alignment { TextAlignment::Center };
|
||||||
|
WeakPtr<GAction> m_action;
|
||||||
bool m_being_pressed { false };
|
bool m_being_pressed { false };
|
||||||
bool m_hovered { false };
|
bool m_hovered { false };
|
||||||
bool m_checkable { false };
|
bool m_checkable { false };
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
//#define GEVENTLOOP_DEBUG
|
//#define GEVENTLOOP_DEBUG
|
||||||
//#define COALESCING_DEBUG
|
//#define COALESCING_DEBUG
|
||||||
|
|
||||||
static HashMap<GShortcut, GAction*>* g_actions;
|
|
||||||
int GEventLoop::s_event_fd = -1;
|
int GEventLoop::s_event_fd = -1;
|
||||||
pid_t GEventLoop::s_server_pid = -1;
|
pid_t GEventLoop::s_server_pid = -1;
|
||||||
|
|
||||||
|
@ -71,9 +70,6 @@ GEventLoop::GEventLoop()
|
||||||
connected = true;
|
connected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_actions)
|
|
||||||
g_actions = new HashMap<GShortcut, GAction*>;
|
|
||||||
|
|
||||||
#ifdef GEVENTLOOP_DEBUG
|
#ifdef GEVENTLOOP_DEBUG
|
||||||
dbgprintf("(%u) GEventLoop constructed :)\n", getpid());
|
dbgprintf("(%u) GEventLoop constructed :)\n", getpid());
|
||||||
#endif
|
#endif
|
||||||
|
@ -125,8 +121,10 @@ void GEventLoop::handle_key_event(const WSAPI_ServerMessage& event, GWindow& win
|
||||||
|
|
||||||
if (event.type == WSAPI_ServerMessage::Type::KeyDown) {
|
if (event.type == WSAPI_ServerMessage::Type::KeyDown) {
|
||||||
if (auto* action = GApplication::the().action_for_key_event(*key_event)) {
|
if (auto* action = GApplication::the().action_for_key_event(*key_event)) {
|
||||||
action->activate();
|
if (action->is_enabled()) {
|
||||||
return;
|
action->activate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
post_event(window, move(key_event));
|
post_event(window, move(key_event));
|
||||||
|
|
|
@ -31,12 +31,12 @@ GMenu::~GMenu()
|
||||||
|
|
||||||
void GMenu::add_action(Retained<GAction>&& action)
|
void GMenu::add_action(Retained<GAction>&& action)
|
||||||
{
|
{
|
||||||
m_items.append(make<GMenuItem>(move(action)));
|
m_items.append(make<GMenuItem>(m_menu_id, move(action)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMenu::add_separator()
|
void GMenu::add_separator()
|
||||||
{
|
{
|
||||||
m_items.append(make<GMenuItem>(GMenuItem::Separator));
|
m_items.append(make<GMenuItem>(m_menu_id, GMenuItem::Separator));
|
||||||
}
|
}
|
||||||
|
|
||||||
int GMenu::realize_menu()
|
int GMenu::realize_menu()
|
||||||
|
@ -52,6 +52,8 @@ int GMenu::realize_menu()
|
||||||
ASSERT(m_menu_id > 0);
|
ASSERT(m_menu_id > 0);
|
||||||
for (int i = 0; i < m_items.size(); ++i) {
|
for (int i = 0; i < m_items.size(); ++i) {
|
||||||
auto& item = *m_items[i];
|
auto& item = *m_items[i];
|
||||||
|
item.set_menu_id({ }, m_menu_id);
|
||||||
|
item.set_identifier({ }, i);
|
||||||
if (item.type() == GMenuItem::Separator) {
|
if (item.type() == GMenuItem::Separator) {
|
||||||
WSAPI_ClientMessage request;
|
WSAPI_ClientMessage request;
|
||||||
request.type = WSAPI_ClientMessage::Type::AddMenuSeparator;
|
request.type = WSAPI_ClientMessage::Type::AddMenuSeparator;
|
||||||
|
@ -65,6 +67,7 @@ int GMenu::realize_menu()
|
||||||
request.type = WSAPI_ClientMessage::Type::AddMenuItem;
|
request.type = WSAPI_ClientMessage::Type::AddMenuItem;
|
||||||
request.menu.menu_id = m_menu_id;
|
request.menu.menu_id = m_menu_id;
|
||||||
request.menu.identifier = i;
|
request.menu.identifier = i;
|
||||||
|
request.menu.enabled = action.is_enabled();
|
||||||
ASSERT(action.text().length() < (ssize_t)sizeof(request.text));
|
ASSERT(action.text().length() < (ssize_t)sizeof(request.text));
|
||||||
strcpy(request.text, action.text().characters());
|
strcpy(request.text, action.text().characters());
|
||||||
request.text_length = action.text().length();
|
request.text_length = action.text().length();
|
||||||
|
|
|
@ -1,18 +1,57 @@
|
||||||
#include <LibGUI/GMenuItem.h>
|
#include <LibGUI/GMenuItem.h>
|
||||||
#include <LibGUI/GAction.h>
|
#include <LibGUI/GAction.h>
|
||||||
|
#include <LibGUI/GEventLoop.h>
|
||||||
|
#include <WindowServer/WSAPITypes.h>
|
||||||
|
|
||||||
GMenuItem::GMenuItem(Type type)
|
GMenuItem::GMenuItem(unsigned menu_id, Type type)
|
||||||
: m_type(type)
|
: m_type(type)
|
||||||
|
, m_menu_id(menu_id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
GMenuItem::GMenuItem(Retained<GAction>&& action)
|
GMenuItem::GMenuItem(unsigned menu_id, Retained<GAction>&& action)
|
||||||
: m_type(Action)
|
: m_type(Action)
|
||||||
|
, m_menu_id(menu_id)
|
||||||
, m_action(move(action))
|
, m_action(move(action))
|
||||||
{
|
{
|
||||||
|
m_action->register_menu_item({ }, *this);
|
||||||
|
m_enabled = m_action->is_enabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
GMenuItem::~GMenuItem()
|
GMenuItem::~GMenuItem()
|
||||||
{
|
{
|
||||||
|
if (m_action)
|
||||||
|
m_action->unregister_menu_item({ }, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GMenuItem::set_enabled(bool enabled)
|
||||||
|
{
|
||||||
|
if (m_enabled == enabled)
|
||||||
|
return;
|
||||||
|
m_enabled = enabled;
|
||||||
|
update_window_server();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMenuItem::update_window_server()
|
||||||
|
{
|
||||||
|
auto& action = *m_action;
|
||||||
|
WSAPI_ClientMessage request;
|
||||||
|
request.type = WSAPI_ClientMessage::Type::UpdateMenuItem;
|
||||||
|
request.menu.menu_id = m_menu_id;
|
||||||
|
request.menu.identifier = m_identifier;
|
||||||
|
request.menu.enabled = action.is_enabled();
|
||||||
|
ASSERT(action.text().length() < (ssize_t)sizeof(request.text));
|
||||||
|
strcpy(request.text, action.text().characters());
|
||||||
|
request.text_length = action.text().length();
|
||||||
|
|
||||||
|
if (action.shortcut().is_valid()) {
|
||||||
|
auto shortcut_text = action.shortcut().to_string();
|
||||||
|
ASSERT(shortcut_text.length() < (ssize_t)sizeof(request.menu.shortcut_text));
|
||||||
|
strcpy(request.menu.shortcut_text, shortcut_text.characters());
|
||||||
|
request.menu.shortcut_text_length = shortcut_text.length();
|
||||||
|
} else {
|
||||||
|
request.menu.shortcut_text_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidUpdateMenuItem);
|
||||||
|
}
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/AKString.h>
|
#include <AK/AKString.h>
|
||||||
|
#include <AK/Badge.h>
|
||||||
|
|
||||||
class GAction;
|
class GAction;
|
||||||
|
class GMenu;
|
||||||
|
|
||||||
class GMenuItem {
|
class GMenuItem {
|
||||||
public:
|
public:
|
||||||
enum Type { Invalid, Action, Separator };
|
enum Type { Invalid, Action, Separator };
|
||||||
|
|
||||||
explicit GMenuItem(Type);
|
GMenuItem(unsigned menu_id, Type);
|
||||||
explicit GMenuItem(Retained<GAction>&&);
|
GMenuItem(unsigned menu_id, Retained<GAction>&&);
|
||||||
~GMenuItem();
|
~GMenuItem();
|
||||||
|
|
||||||
Type type() const { return m_type; }
|
Type type() const { return m_type; }
|
||||||
|
@ -18,9 +20,19 @@ public:
|
||||||
GAction* action() { return m_action.ptr(); }
|
GAction* action() { return m_action.ptr(); }
|
||||||
unsigned identifier() const { return m_identifier; }
|
unsigned identifier() const { return m_identifier; }
|
||||||
|
|
||||||
|
bool is_enabled() const { return m_enabled; }
|
||||||
|
void set_enabled(bool);
|
||||||
|
|
||||||
|
void set_menu_id(Badge<GMenu>, unsigned menu_id) { m_menu_id = menu_id; }
|
||||||
|
void set_identifier(Badge<GMenu>, unsigned identifier) { m_identifier = identifier; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void update_window_server();
|
||||||
|
|
||||||
Type m_type { Invalid };
|
Type m_type { Invalid };
|
||||||
|
unsigned m_menu_id { 0 };
|
||||||
unsigned m_identifier { 0 };
|
unsigned m_identifier { 0 };
|
||||||
|
bool m_enabled { true };
|
||||||
RetainPtr<GAction> m_action;
|
RetainPtr<GAction> m_action;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ void GToolBar::add_action(Retained<GAction>&& action)
|
||||||
item->action = move(action);
|
item->action = move(action);
|
||||||
|
|
||||||
auto* button = new GButton(this);
|
auto* button = new GButton(this);
|
||||||
|
button->set_action(*item->action);
|
||||||
button->set_tooltip(item->action->text());
|
button->set_tooltip(item->action->text());
|
||||||
if (item->action->icon())
|
if (item->action->icon())
|
||||||
button->set_icon(item->action->icon());
|
button->set_icon(item->action->icon());
|
||||||
|
|
|
@ -82,6 +82,7 @@ struct WSAPI_ServerMessage {
|
||||||
DidSetApplicationMenubar,
|
DidSetApplicationMenubar,
|
||||||
DidAddMenuItem,
|
DidAddMenuItem,
|
||||||
DidAddMenuSeparator,
|
DidAddMenuSeparator,
|
||||||
|
DidUpdateMenuItem,
|
||||||
DidCreateWindow,
|
DidCreateWindow,
|
||||||
DidDestroyWindow,
|
DidDestroyWindow,
|
||||||
DidGetWindowTitle,
|
DidGetWindowTitle,
|
||||||
|
@ -171,6 +172,7 @@ struct WSAPI_ClientMessage {
|
||||||
SetApplicationMenubar,
|
SetApplicationMenubar,
|
||||||
AddMenuItem,
|
AddMenuItem,
|
||||||
AddMenuSeparator,
|
AddMenuSeparator,
|
||||||
|
UpdateMenuItem,
|
||||||
CreateWindow,
|
CreateWindow,
|
||||||
DestroyWindow,
|
DestroyWindow,
|
||||||
SetWindowTitle,
|
SetWindowTitle,
|
||||||
|
@ -211,6 +213,7 @@ struct WSAPI_ClientMessage {
|
||||||
unsigned identifier;
|
unsigned identifier;
|
||||||
char shortcut_text[32];
|
char shortcut_text[32];
|
||||||
int shortcut_text_length;
|
int shortcut_text_length;
|
||||||
|
bool enabled;
|
||||||
} menu;
|
} menu;
|
||||||
struct {
|
struct {
|
||||||
WSAPI_Rect rect;
|
WSAPI_Rect rect;
|
||||||
|
|
|
@ -215,7 +215,7 @@ void WSClientConnection::handle_request(const WSAPIAddMenuItemRequest& request)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto& menu = *(*it).value;
|
auto& menu = *(*it).value;
|
||||||
menu.add_item(make<WSMenuItem>(identifier, request.text(), request.shortcut_text()));
|
menu.add_item(make<WSMenuItem>(menu, identifier, request.text(), request.shortcut_text(), request.is_enabled()));
|
||||||
WSAPI_ServerMessage response;
|
WSAPI_ServerMessage response;
|
||||||
response.type = WSAPI_ServerMessage::Type::DidAddMenuItem;
|
response.type = WSAPI_ServerMessage::Type::DidAddMenuItem;
|
||||||
response.menu.menu_id = menu_id;
|
response.menu.menu_id = menu_id;
|
||||||
|
@ -223,6 +223,31 @@ void WSClientConnection::handle_request(const WSAPIAddMenuItemRequest& request)
|
||||||
post_message(response);
|
post_message(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WSClientConnection::handle_request(const WSAPIUpdateMenuItemRequest& request)
|
||||||
|
{
|
||||||
|
int menu_id = request.menu_id();
|
||||||
|
unsigned identifier = request.identifier();
|
||||||
|
auto it = m_menus.find(menu_id);
|
||||||
|
if (it == m_menus.end()) {
|
||||||
|
post_error("WSAPIUpdateMenuItemRequest: Bad menu ID");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto& menu = *(*it).value;
|
||||||
|
auto* menu_item = menu.item_with_identifier(request.identifier());
|
||||||
|
if (!menu_item) {
|
||||||
|
post_error("WSAPIUpdateMenuItemRequest: Bad menu item identifier");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
menu_item->set_text(request.text());
|
||||||
|
menu_item->set_shortcut_text(request.shortcut_text());
|
||||||
|
menu_item->set_enabled(request.is_enabled());
|
||||||
|
WSAPI_ServerMessage response;
|
||||||
|
response.type = WSAPI_ServerMessage::Type::DidUpdateMenuItem;
|
||||||
|
response.menu.menu_id = menu_id;
|
||||||
|
response.menu.identifier = identifier;
|
||||||
|
post_message(response);
|
||||||
|
}
|
||||||
|
|
||||||
void WSClientConnection::handle_request(const WSAPIAddMenuSeparatorRequest& request)
|
void WSClientConnection::handle_request(const WSAPIAddMenuSeparatorRequest& request)
|
||||||
{
|
{
|
||||||
int menu_id = request.menu_id();
|
int menu_id = request.menu_id();
|
||||||
|
@ -232,7 +257,7 @@ void WSClientConnection::handle_request(const WSAPIAddMenuSeparatorRequest& requ
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto& menu = *(*it).value;
|
auto& menu = *(*it).value;
|
||||||
menu.add_item(make<WSMenuItem>(WSMenuItem::Separator));
|
menu.add_item(make<WSMenuItem>(menu, WSMenuItem::Separator));
|
||||||
WSAPI_ServerMessage response;
|
WSAPI_ServerMessage response;
|
||||||
response.type = WSAPI_ServerMessage::Type::DidAddMenuSeparator;
|
response.type = WSAPI_ServerMessage::Type::DidAddMenuSeparator;
|
||||||
response.menu.menu_id = menu_id;
|
response.menu.menu_id = menu_id;
|
||||||
|
@ -553,6 +578,8 @@ void WSClientConnection::on_request(const WSAPIClientRequest& request)
|
||||||
return handle_request(static_cast<const WSAPIAddMenuItemRequest&>(request));
|
return handle_request(static_cast<const WSAPIAddMenuItemRequest&>(request));
|
||||||
case WSMessage::APIAddMenuSeparatorRequest:
|
case WSMessage::APIAddMenuSeparatorRequest:
|
||||||
return handle_request(static_cast<const WSAPIAddMenuSeparatorRequest&>(request));
|
return handle_request(static_cast<const WSAPIAddMenuSeparatorRequest&>(request));
|
||||||
|
case WSMessage::APIUpdateMenuItemRequest:
|
||||||
|
return handle_request(static_cast<const WSAPIUpdateMenuItemRequest&>(request));
|
||||||
case WSMessage::APISetWindowTitleRequest:
|
case WSMessage::APISetWindowTitleRequest:
|
||||||
return handle_request(static_cast<const WSAPISetWindowTitleRequest&>(request));
|
return handle_request(static_cast<const WSAPISetWindowTitleRequest&>(request));
|
||||||
case WSMessage::APIGetWindowTitleRequest:
|
case WSMessage::APIGetWindowTitleRequest:
|
||||||
|
|
|
@ -50,6 +50,7 @@ private:
|
||||||
void handle_request(const WSAPISetApplicationMenubarRequest&);
|
void handle_request(const WSAPISetApplicationMenubarRequest&);
|
||||||
void handle_request(const WSAPIAddMenuToMenubarRequest&);
|
void handle_request(const WSAPIAddMenuToMenubarRequest&);
|
||||||
void handle_request(const WSAPIAddMenuItemRequest&);
|
void handle_request(const WSAPIAddMenuItemRequest&);
|
||||||
|
void handle_request(const WSAPIUpdateMenuItemRequest&);
|
||||||
void handle_request(const WSAPIAddMenuSeparatorRequest&);
|
void handle_request(const WSAPIAddMenuSeparatorRequest&);
|
||||||
void handle_request(const WSAPISetWindowTitleRequest&);
|
void handle_request(const WSAPISetWindowTitleRequest&);
|
||||||
void handle_request(const WSAPIGetWindowTitleRequest&);
|
void handle_request(const WSAPIGetWindowTitleRequest&);
|
||||||
|
|
|
@ -50,7 +50,8 @@ int WSMenu::height() const
|
||||||
|
|
||||||
void WSMenu::redraw()
|
void WSMenu::redraw()
|
||||||
{
|
{
|
||||||
ASSERT(menu_window());
|
if (!menu_window())
|
||||||
|
return;
|
||||||
draw();
|
draw();
|
||||||
menu_window()->invalidate();
|
menu_window()->invalidate();
|
||||||
}
|
}
|
||||||
|
@ -95,6 +96,8 @@ void WSMenu::draw()
|
||||||
painter.fill_rect(item->rect(), WSWindowManager::the().menu_selection_color());
|
painter.fill_rect(item->rect(), WSWindowManager::the().menu_selection_color());
|
||||||
text_color = Color::White;
|
text_color = Color::White;
|
||||||
}
|
}
|
||||||
|
if (!item->is_enabled())
|
||||||
|
text_color = Color::MidGray;
|
||||||
painter.draw_text(item->rect().translated(left_padding(), 0), item->text(), TextAlignment::CenterLeft, text_color);
|
painter.draw_text(item->rect().translated(left_padding(), 0), item->text(), TextAlignment::CenterLeft, text_color);
|
||||||
if (!item->shortcut_text().is_empty()) {
|
if (!item->shortcut_text().is_empty()) {
|
||||||
painter.draw_text(item->rect().translated(-right_padding(), 0), item->shortcut_text(), TextAlignment::CenterRight, text_color);
|
painter.draw_text(item->rect().translated(-right_padding(), 0), item->shortcut_text(), TextAlignment::CenterRight, text_color);
|
||||||
|
@ -122,7 +125,8 @@ void WSMenu::on_message(const WSMessage& message)
|
||||||
if (message.type() == WSMessage::MouseUp) {
|
if (message.type() == WSMessage::MouseUp) {
|
||||||
if (!m_hovered_item)
|
if (!m_hovered_item)
|
||||||
return;
|
return;
|
||||||
did_activate(*m_hovered_item);
|
if (m_hovered_item->is_enabled())
|
||||||
|
did_activate(*m_hovered_item);
|
||||||
clear_hovered_item();
|
clear_hovered_item();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -152,6 +156,15 @@ void WSMenu::did_activate(WSMenuItem& item)
|
||||||
m_client->post_message(message);
|
m_client->post_message(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WSMenuItem* WSMenu::item_with_identifier(unsigned identifer)
|
||||||
|
{
|
||||||
|
for (auto& item : m_items) {
|
||||||
|
if (item->identifier() == identifer)
|
||||||
|
return item.ptr();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
WSMenuItem* WSMenu::item_at(const Point& position)
|
WSMenuItem* WSMenu::item_at(const Point& position)
|
||||||
{
|
{
|
||||||
for (auto& item : m_items) {
|
for (auto& item : m_items) {
|
||||||
|
|
|
@ -62,6 +62,7 @@ public:
|
||||||
void draw();
|
void draw();
|
||||||
const Font& font() const;
|
const Font& font() const;
|
||||||
|
|
||||||
|
WSMenuItem* item_with_identifier(unsigned);
|
||||||
WSMenuItem* item_at(const Point&);
|
WSMenuItem* item_at(const Point&);
|
||||||
void redraw();
|
void redraw();
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,30 @@
|
||||||
#include "WSMenuItem.h"
|
#include "WSMenuItem.h"
|
||||||
|
#include "WSMenu.h"
|
||||||
|
|
||||||
WSMenuItem::WSMenuItem(unsigned identifier, const String& text, const String& shortcut_text)
|
WSMenuItem::WSMenuItem(WSMenu& menu, unsigned identifier, const String& text, const String& shortcut_text, bool enabled)
|
||||||
: m_type(Text)
|
: m_menu(menu)
|
||||||
|
, m_type(Text)
|
||||||
|
, m_enabled(enabled)
|
||||||
, m_identifier(identifier)
|
, m_identifier(identifier)
|
||||||
, m_text(text)
|
, m_text(text)
|
||||||
, m_shortcut_text(shortcut_text)
|
, m_shortcut_text(shortcut_text)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
WSMenuItem::WSMenuItem(Type type)
|
WSMenuItem::WSMenuItem(WSMenu& menu, Type type)
|
||||||
: m_type(type)
|
: m_menu(menu)
|
||||||
|
, m_type(type)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
WSMenuItem::~WSMenuItem()
|
WSMenuItem::~WSMenuItem()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WSMenuItem::set_enabled(bool enabled)
|
||||||
|
{
|
||||||
|
if (m_enabled == enabled)
|
||||||
|
return;
|
||||||
|
m_enabled = enabled;
|
||||||
|
m_menu.redraw();
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <SharedGraphics/Rect.h>
|
#include <SharedGraphics/Rect.h>
|
||||||
|
|
||||||
|
class WSMenu;
|
||||||
|
|
||||||
class WSMenuItem {
|
class WSMenuItem {
|
||||||
public:
|
public:
|
||||||
enum Type {
|
enum Type {
|
||||||
|
@ -12,15 +14,20 @@ public:
|
||||||
Separator,
|
Separator,
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit WSMenuItem(unsigned identifier, const String& text, const String& shortcut_text = { });
|
WSMenuItem(WSMenu&, unsigned identifier, const String& text, const String& shortcut_text = { }, bool enabled = true);
|
||||||
explicit WSMenuItem(Type);
|
WSMenuItem(WSMenu&, Type);
|
||||||
~WSMenuItem();
|
~WSMenuItem();
|
||||||
|
|
||||||
Type type() const { return m_type; }
|
Type type() const { return m_type; }
|
||||||
bool enabled() const { return m_enabled; }
|
|
||||||
|
bool is_enabled() const { return m_enabled; }
|
||||||
|
void set_enabled(bool);
|
||||||
|
|
||||||
String text() const { return m_text; }
|
String text() const { return m_text; }
|
||||||
|
void set_text(const String& text) { m_text = text; }
|
||||||
|
|
||||||
String shortcut_text() const { return m_shortcut_text; }
|
String shortcut_text() const { return m_shortcut_text; }
|
||||||
|
void set_shortcut_text(const String& text) { m_shortcut_text = text; }
|
||||||
|
|
||||||
void set_rect(const Rect& rect) { m_rect = rect; }
|
void set_rect(const Rect& rect) { m_rect = rect; }
|
||||||
Rect rect() const { return m_rect; }
|
Rect rect() const { return m_rect; }
|
||||||
|
@ -28,6 +35,7 @@ public:
|
||||||
unsigned identifier() const { return m_identifier; }
|
unsigned identifier() const { return m_identifier; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
WSMenu& m_menu;
|
||||||
Type m_type { None };
|
Type m_type { None };
|
||||||
bool m_enabled { true };
|
bool m_enabled { true };
|
||||||
unsigned m_identifier { 0 };
|
unsigned m_identifier { 0 };
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
APIDestroyMenuRequest,
|
APIDestroyMenuRequest,
|
||||||
APIAddMenuItemRequest,
|
APIAddMenuItemRequest,
|
||||||
APIAddMenuSeparatorRequest,
|
APIAddMenuSeparatorRequest,
|
||||||
|
APIUpdateMenuItemRequest,
|
||||||
APICreateWindowRequest,
|
APICreateWindowRequest,
|
||||||
APIDestroyWindowRequest,
|
APIDestroyWindowRequest,
|
||||||
APISetWindowTitleRequest,
|
APISetWindowTitleRequest,
|
||||||
|
@ -218,12 +219,13 @@ private:
|
||||||
|
|
||||||
class WSAPIAddMenuItemRequest : public WSAPIClientRequest {
|
class WSAPIAddMenuItemRequest : public WSAPIClientRequest {
|
||||||
public:
|
public:
|
||||||
WSAPIAddMenuItemRequest(int client_id, int menu_id, unsigned identifier, const String& text, const String& shortcut_text)
|
WSAPIAddMenuItemRequest(int client_id, int menu_id, unsigned identifier, const String& text, const String& shortcut_text, bool enabled)
|
||||||
: WSAPIClientRequest(WSMessage::APIAddMenuItemRequest, client_id)
|
: WSAPIClientRequest(WSMessage::APIAddMenuItemRequest, client_id)
|
||||||
, m_menu_id(menu_id)
|
, m_menu_id(menu_id)
|
||||||
, m_identifier(identifier)
|
, m_identifier(identifier)
|
||||||
, m_text(text)
|
, m_text(text)
|
||||||
, m_shortcut_text(shortcut_text)
|
, m_shortcut_text(shortcut_text)
|
||||||
|
, m_enabled(enabled)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,12 +233,40 @@ public:
|
||||||
unsigned identifier() const { return m_identifier; }
|
unsigned identifier() const { return m_identifier; }
|
||||||
String text() const { return m_text; }
|
String text() const { return m_text; }
|
||||||
String shortcut_text() const { return m_shortcut_text; }
|
String shortcut_text() const { return m_shortcut_text; }
|
||||||
|
bool is_enabled() const { return m_enabled; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_menu_id { 0 };
|
int m_menu_id { 0 };
|
||||||
unsigned m_identifier { 0 };
|
unsigned m_identifier { 0 };
|
||||||
String m_text;
|
String m_text;
|
||||||
String m_shortcut_text;
|
String m_shortcut_text;
|
||||||
|
bool m_enabled { true };
|
||||||
|
};
|
||||||
|
|
||||||
|
class WSAPIUpdateMenuItemRequest : public WSAPIClientRequest {
|
||||||
|
public:
|
||||||
|
WSAPIUpdateMenuItemRequest(int client_id, int menu_id, unsigned identifier, const String& text, const String& shortcut_text, bool enabled)
|
||||||
|
: WSAPIClientRequest(WSMessage::APIUpdateMenuItemRequest, client_id)
|
||||||
|
, m_menu_id(menu_id)
|
||||||
|
, m_identifier(identifier)
|
||||||
|
, m_text(text)
|
||||||
|
, m_shortcut_text(shortcut_text)
|
||||||
|
, m_enabled(enabled)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int menu_id() const { return m_menu_id; }
|
||||||
|
unsigned identifier() const { return m_identifier; }
|
||||||
|
String text() const { return m_text; }
|
||||||
|
String shortcut_text() const { return m_shortcut_text; }
|
||||||
|
bool is_enabled() const { return m_enabled; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_menu_id { 0 };
|
||||||
|
unsigned m_identifier { 0 };
|
||||||
|
String m_text;
|
||||||
|
String m_shortcut_text;
|
||||||
|
bool m_enabled { true };
|
||||||
};
|
};
|
||||||
|
|
||||||
class WSAPIAddMenuSeparatorRequest : public WSAPIClientRequest {
|
class WSAPIAddMenuSeparatorRequest : public WSAPIClientRequest {
|
||||||
|
|
|
@ -296,7 +296,12 @@ void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMess
|
||||||
case WSAPI_ClientMessage::Type::AddMenuItem:
|
case WSAPI_ClientMessage::Type::AddMenuItem:
|
||||||
ASSERT(message.text_length < (ssize_t)sizeof(message.text));
|
ASSERT(message.text_length < (ssize_t)sizeof(message.text));
|
||||||
ASSERT(message.menu.shortcut_text_length < (ssize_t)sizeof(message.menu.shortcut_text));
|
ASSERT(message.menu.shortcut_text_length < (ssize_t)sizeof(message.menu.shortcut_text));
|
||||||
post_message(client, make<WSAPIAddMenuItemRequest>(client_id, message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length), String(message.menu.shortcut_text, message.menu.shortcut_text_length)));
|
post_message(client, make<WSAPIAddMenuItemRequest>(client_id, message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length), String(message.menu.shortcut_text, message.menu.shortcut_text_length), message.menu.enabled));
|
||||||
|
break;
|
||||||
|
case WSAPI_ClientMessage::Type::UpdateMenuItem:
|
||||||
|
ASSERT(message.text_length < (ssize_t)sizeof(message.text));
|
||||||
|
ASSERT(message.menu.shortcut_text_length < (ssize_t)sizeof(message.menu.shortcut_text));
|
||||||
|
post_message(client, make<WSAPIUpdateMenuItemRequest>(client_id, message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length), String(message.menu.shortcut_text, message.menu.shortcut_text_length), message.menu.enabled));
|
||||||
break;
|
break;
|
||||||
case WSAPI_ClientMessage::Type::AddMenuSeparator:
|
case WSAPI_ClientMessage::Type::AddMenuSeparator:
|
||||||
post_message(client, make<WSAPIAddMenuSeparatorRequest>(client_id, message.menu.menu_id));
|
post_message(client, make<WSAPIAddMenuSeparatorRequest>(client_id, message.menu.menu_id));
|
||||||
|
|
|
@ -95,16 +95,16 @@ WSWindowManager::WSWindowManager()
|
||||||
{
|
{
|
||||||
byte system_menu_name[] = { 0xf8, 0 };
|
byte system_menu_name[] = { 0xf8, 0 };
|
||||||
m_system_menu = make<WSMenu>(nullptr, -1, String((const char*)system_menu_name));
|
m_system_menu = make<WSMenu>(nullptr, -1, String((const char*)system_menu_name));
|
||||||
m_system_menu->add_item(make<WSMenuItem>(0, "Open Terminal..."));
|
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 0, "Open Terminal..."));
|
||||||
m_system_menu->add_item(make<WSMenuItem>(1, "Open ProcessManager..."));
|
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 1, "Open ProcessManager..."));
|
||||||
m_system_menu->add_item(make<WSMenuItem>(WSMenuItem::Separator));
|
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, WSMenuItem::Separator));
|
||||||
m_system_menu->add_item(make<WSMenuItem>(100, "640x480"));
|
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 100, "640x480"));
|
||||||
m_system_menu->add_item(make<WSMenuItem>(101, "800x600"));
|
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 101, "800x600"));
|
||||||
m_system_menu->add_item(make<WSMenuItem>(102, "1024x768"));
|
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 102, "1024x768"));
|
||||||
m_system_menu->add_item(make<WSMenuItem>(103, "1440x900"));
|
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 103, "1440x900"));
|
||||||
m_system_menu->add_item(make<WSMenuItem>(104, "1920x1080"));
|
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 104, "1920x1080"));
|
||||||
m_system_menu->add_item(make<WSMenuItem>(WSMenuItem::Separator));
|
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, WSMenuItem::Separator));
|
||||||
m_system_menu->add_item(make<WSMenuItem>(200, "About..."));
|
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 200, "About..."));
|
||||||
m_system_menu->on_item_activation = [this] (WSMenuItem& item) {
|
m_system_menu->on_item_activation = [this] (WSMenuItem& item) {
|
||||||
if (item.identifier() == 0) {
|
if (item.identifier() == 0) {
|
||||||
if (fork() == 0) {
|
if (fork() == 0) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue