1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 07:27:45 +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:
Andreas Kling 2019-04-12 02:53:27 +02:00
parent 32e5c8c689
commit 054c982181
20 changed files with 308 additions and 53 deletions

View file

@ -82,6 +82,7 @@ struct WSAPI_ServerMessage {
DidSetApplicationMenubar,
DidAddMenuItem,
DidAddMenuSeparator,
DidUpdateMenuItem,
DidCreateWindow,
DidDestroyWindow,
DidGetWindowTitle,
@ -171,6 +172,7 @@ struct WSAPI_ClientMessage {
SetApplicationMenubar,
AddMenuItem,
AddMenuSeparator,
UpdateMenuItem,
CreateWindow,
DestroyWindow,
SetWindowTitle,
@ -211,6 +213,7 @@ struct WSAPI_ClientMessage {
unsigned identifier;
char shortcut_text[32];
int shortcut_text_length;
bool enabled;
} menu;
struct {
WSAPI_Rect rect;

View file

@ -215,7 +215,7 @@ void WSClientConnection::handle_request(const WSAPIAddMenuItemRequest& request)
return;
}
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;
response.type = WSAPI_ServerMessage::Type::DidAddMenuItem;
response.menu.menu_id = menu_id;
@ -223,6 +223,31 @@ void WSClientConnection::handle_request(const WSAPIAddMenuItemRequest& request)
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)
{
int menu_id = request.menu_id();
@ -232,7 +257,7 @@ void WSClientConnection::handle_request(const WSAPIAddMenuSeparatorRequest& requ
return;
}
auto& menu = *(*it).value;
menu.add_item(make<WSMenuItem>(WSMenuItem::Separator));
menu.add_item(make<WSMenuItem>(menu, WSMenuItem::Separator));
WSAPI_ServerMessage response;
response.type = WSAPI_ServerMessage::Type::DidAddMenuSeparator;
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));
case WSMessage::APIAddMenuSeparatorRequest:
return handle_request(static_cast<const WSAPIAddMenuSeparatorRequest&>(request));
case WSMessage::APIUpdateMenuItemRequest:
return handle_request(static_cast<const WSAPIUpdateMenuItemRequest&>(request));
case WSMessage::APISetWindowTitleRequest:
return handle_request(static_cast<const WSAPISetWindowTitleRequest&>(request));
case WSMessage::APIGetWindowTitleRequest:

View file

@ -50,6 +50,7 @@ private:
void handle_request(const WSAPISetApplicationMenubarRequest&);
void handle_request(const WSAPIAddMenuToMenubarRequest&);
void handle_request(const WSAPIAddMenuItemRequest&);
void handle_request(const WSAPIUpdateMenuItemRequest&);
void handle_request(const WSAPIAddMenuSeparatorRequest&);
void handle_request(const WSAPISetWindowTitleRequest&);
void handle_request(const WSAPIGetWindowTitleRequest&);

View file

@ -50,7 +50,8 @@ int WSMenu::height() const
void WSMenu::redraw()
{
ASSERT(menu_window());
if (!menu_window())
return;
draw();
menu_window()->invalidate();
}
@ -95,6 +96,8 @@ void WSMenu::draw()
painter.fill_rect(item->rect(), WSWindowManager::the().menu_selection_color());
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);
if (!item->shortcut_text().is_empty()) {
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 (!m_hovered_item)
return;
did_activate(*m_hovered_item);
if (m_hovered_item->is_enabled())
did_activate(*m_hovered_item);
clear_hovered_item();
return;
}
@ -152,6 +156,15 @@ void WSMenu::did_activate(WSMenuItem& item)
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)
{
for (auto& item : m_items) {

View file

@ -62,6 +62,7 @@ public:
void draw();
const Font& font() const;
WSMenuItem* item_with_identifier(unsigned);
WSMenuItem* item_at(const Point&);
void redraw();

View file

@ -1,18 +1,30 @@
#include "WSMenuItem.h"
#include "WSMenu.h"
WSMenuItem::WSMenuItem(unsigned identifier, const String& text, const String& shortcut_text)
: m_type(Text)
WSMenuItem::WSMenuItem(WSMenu& menu, unsigned identifier, const String& text, const String& shortcut_text, bool enabled)
: m_menu(menu)
, m_type(Text)
, m_enabled(enabled)
, m_identifier(identifier)
, m_text(text)
, m_shortcut_text(shortcut_text)
{
}
WSMenuItem::WSMenuItem(Type type)
: m_type(type)
WSMenuItem::WSMenuItem(WSMenu& menu, Type type)
: m_menu(menu)
, m_type(type)
{
}
WSMenuItem::~WSMenuItem()
{
}
void WSMenuItem::set_enabled(bool enabled)
{
if (m_enabled == enabled)
return;
m_enabled = enabled;
m_menu.redraw();
}

View file

@ -4,6 +4,8 @@
#include <AK/Function.h>
#include <SharedGraphics/Rect.h>
class WSMenu;
class WSMenuItem {
public:
enum Type {
@ -12,15 +14,20 @@ public:
Separator,
};
explicit WSMenuItem(unsigned identifier, const String& text, const String& shortcut_text = { });
explicit WSMenuItem(Type);
WSMenuItem(WSMenu&, unsigned identifier, const String& text, const String& shortcut_text = { }, bool enabled = true);
WSMenuItem(WSMenu&, Type);
~WSMenuItem();
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; }
void set_text(const String& text) { m_text = 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; }
Rect rect() const { return m_rect; }
@ -28,6 +35,7 @@ public:
unsigned identifier() const { return m_identifier; }
private:
WSMenu& m_menu;
Type m_type { None };
bool m_enabled { true };
unsigned m_identifier { 0 };

View file

@ -38,6 +38,7 @@ public:
APIDestroyMenuRequest,
APIAddMenuItemRequest,
APIAddMenuSeparatorRequest,
APIUpdateMenuItemRequest,
APICreateWindowRequest,
APIDestroyWindowRequest,
APISetWindowTitleRequest,
@ -218,12 +219,13 @@ private:
class WSAPIAddMenuItemRequest : public WSAPIClientRequest {
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)
, m_menu_id(menu_id)
, m_identifier(identifier)
, m_text(text)
, m_shortcut_text(shortcut_text)
, m_enabled(enabled)
{
}
@ -231,12 +233,40 @@ public:
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 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 {

View file

@ -296,7 +296,12 @@ void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMess
case WSAPI_ClientMessage::Type::AddMenuItem:
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<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;
case WSAPI_ClientMessage::Type::AddMenuSeparator:
post_message(client, make<WSAPIAddMenuSeparatorRequest>(client_id, message.menu.menu_id));

View file

@ -95,16 +95,16 @@ WSWindowManager::WSWindowManager()
{
byte system_menu_name[] = { 0xf8, 0 };
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>(1, "Open ProcessManager..."));
m_system_menu->add_item(make<WSMenuItem>(WSMenuItem::Separator));
m_system_menu->add_item(make<WSMenuItem>(100, "640x480"));
m_system_menu->add_item(make<WSMenuItem>(101, "800x600"));
m_system_menu->add_item(make<WSMenuItem>(102, "1024x768"));
m_system_menu->add_item(make<WSMenuItem>(103, "1440x900"));
m_system_menu->add_item(make<WSMenuItem>(104, "1920x1080"));
m_system_menu->add_item(make<WSMenuItem>(WSMenuItem::Separator));
m_system_menu->add_item(make<WSMenuItem>(200, "About..."));
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 0, "Open Terminal..."));
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 1, "Open ProcessManager..."));
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, WSMenuItem::Separator));
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 100, "640x480"));
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 101, "800x600"));
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 102, "1024x768"));
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 103, "1440x900"));
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 104, "1920x1080"));
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, WSMenuItem::Separator));
m_system_menu->add_item(make<WSMenuItem>(*m_system_menu, 200, "About..."));
m_system_menu->on_item_activation = [this] (WSMenuItem& item) {
if (item.identifier() == 0) {
if (fork() == 0) {