summaryrefslogtreecommitdiff
path: root/Servers
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-04-26 21:09:56 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-04-26 21:09:56 +0200
commit8f81a3f9dde15f4bf328c8864e6dcbf75a7090fe (patch)
tree8e0ef21fd86c0e55abb5ff85671e7e5cb9dcc2c8 /Servers
parent9ff36afeaab7e583afd3de303bba5ded3b8a448e (diff)
downloadserenity-8f81a3f9dde15f4bf328c8864e6dcbf75a7090fe.zip
LibGUI+WindowServer: Make it possible to have checkable GActions.
They show up as checkable GButtons in GToolBar, and with (or without) check marks in menus. There are a bunch of places to make use of this. This patch only takes advantage of it in the FileManager for the view type actions.
Diffstat (limited to 'Servers')
-rw-r--r--Servers/WindowServer/WSAPITypes.h2
-rw-r--r--Servers/WindowServer/WSClientConnection.cpp5
-rw-r--r--Servers/WindowServer/WSEvent.h18
-rw-r--r--Servers/WindowServer/WSEventLoop.cpp4
-rw-r--r--Servers/WindowServer/WSMenu.cpp34
-rw-r--r--Servers/WindowServer/WSMenuItem.cpp12
-rw-r--r--Servers/WindowServer/WSMenuItem.h10
7 files changed, 76 insertions, 9 deletions
diff --git a/Servers/WindowServer/WSAPITypes.h b/Servers/WindowServer/WSAPITypes.h
index 5c1cd50a2f..a22ed4bc91 100644
--- a/Servers/WindowServer/WSAPITypes.h
+++ b/Servers/WindowServer/WSAPITypes.h
@@ -246,6 +246,8 @@ struct WSAPI_ClientMessage {
char shortcut_text[32];
int shortcut_text_length;
bool enabled;
+ bool checkable;
+ bool checked;
WSAPI_Point position;
bool top_anchored;
} menu;
diff --git a/Servers/WindowServer/WSClientConnection.cpp b/Servers/WindowServer/WSClientConnection.cpp
index b52bcf00e4..78826f0fa6 100644
--- a/Servers/WindowServer/WSClientConnection.cpp
+++ b/Servers/WindowServer/WSClientConnection.cpp
@@ -241,7 +241,7 @@ void WSClientConnection::handle_request(const WSAPIAddMenuItemRequest& request)
return;
}
auto& menu = *(*it).value;
- menu.add_item(make<WSMenuItem>(menu, identifier, request.text(), request.shortcut_text(), request.is_enabled()));
+ menu.add_item(make<WSMenuItem>(menu, identifier, request.text(), request.shortcut_text(), request.is_enabled(), request.is_checkable(), request.is_checked()));
WSAPI_ServerMessage response;
response.type = WSAPI_ServerMessage::Type::DidAddMenuItem;
response.menu.menu_id = menu_id;
@@ -292,6 +292,9 @@ void WSClientConnection::handle_request(const WSAPIUpdateMenuItemRequest& reques
menu_item->set_text(request.text());
menu_item->set_shortcut_text(request.shortcut_text());
menu_item->set_enabled(request.is_enabled());
+ menu_item->set_checkable(request.is_checkable());
+ if (request.is_checkable())
+ menu_item->set_checked(request.is_checked());
WSAPI_ServerMessage response;
response.type = WSAPI_ServerMessage::Type::DidUpdateMenuItem;
response.menu.menu_id = menu_id;
diff --git a/Servers/WindowServer/WSEvent.h b/Servers/WindowServer/WSEvent.h
index e1a9d80fb0..d8fe0cd9ca 100644
--- a/Servers/WindowServer/WSEvent.h
+++ b/Servers/WindowServer/WSEvent.h
@@ -276,13 +276,15 @@ private:
class WSAPIAddMenuItemRequest : public WSAPIClientRequest {
public:
- WSAPIAddMenuItemRequest(int client_id, int menu_id, unsigned identifier, const String& text, const String& shortcut_text, bool enabled)
+ WSAPIAddMenuItemRequest(int client_id, int menu_id, unsigned identifier, const String& text, const String& shortcut_text, bool enabled, bool checkable, bool checked)
: WSAPIClientRequest(WSEvent::APIAddMenuItemRequest, client_id)
, m_menu_id(menu_id)
, m_identifier(identifier)
, m_text(text)
, m_shortcut_text(shortcut_text)
, m_enabled(enabled)
+ , m_checkable(checkable)
+ , m_checked(checked)
{
}
@@ -291,24 +293,30 @@ public:
String text() const { return m_text; }
String shortcut_text() const { return m_shortcut_text; }
bool is_enabled() const { return m_enabled; }
+ bool is_checkable() const { return m_checkable; }
+ bool is_checked() const { return m_checked; }
private:
int m_menu_id { 0 };
unsigned m_identifier { 0 };
String m_text;
String m_shortcut_text;
- bool m_enabled { true };
+ bool m_enabled;
+ bool m_checkable;
+ bool m_checked;
};
class WSAPIUpdateMenuItemRequest : public WSAPIClientRequest {
public:
- WSAPIUpdateMenuItemRequest(int client_id, int menu_id, unsigned identifier, const String& text, const String& shortcut_text, bool enabled)
+ WSAPIUpdateMenuItemRequest(int client_id, int menu_id, unsigned identifier, const String& text, const String& shortcut_text, bool enabled, bool checkable, bool checked)
: WSAPIClientRequest(WSEvent::APIUpdateMenuItemRequest, client_id)
, m_menu_id(menu_id)
, m_identifier(identifier)
, m_text(text)
, m_shortcut_text(shortcut_text)
, m_enabled(enabled)
+ , m_checkable(checkable)
+ , m_checked(checked)
{
}
@@ -317,6 +325,8 @@ public:
String text() const { return m_text; }
String shortcut_text() const { return m_shortcut_text; }
bool is_enabled() const { return m_enabled; }
+ bool is_checkable() const { return m_checkable; }
+ bool is_checked() const { return m_checked; }
private:
int m_menu_id { 0 };
@@ -324,6 +334,8 @@ private:
String m_text;
String m_shortcut_text;
bool m_enabled { true };
+ bool m_checkable;
+ bool m_checked;
};
class WSAPIAddMenuSeparatorRequest : public WSAPIClientRequest {
diff --git a/Servers/WindowServer/WSEventLoop.cpp b/Servers/WindowServer/WSEventLoop.cpp
index 9c3d19654d..8a2e0a28aa 100644
--- a/Servers/WindowServer/WSEventLoop.cpp
+++ b/Servers/WindowServer/WSEventLoop.cpp
@@ -170,12 +170,12 @@ bool WSEventLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessag
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_event(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));
+ post_event(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, message.menu.checkable, message.menu.checked));
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_event(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));
+ post_event(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, message.menu.checkable, message.menu.checked));
break;
case WSAPI_ClientMessage::Type::AddMenuSeparator:
post_event(client, make<WSAPIAddMenuSeparatorRequest>(client_id, message.menu.menu_id));
diff --git a/Servers/WindowServer/WSMenu.cpp b/Servers/WindowServer/WSMenu.cpp
index 877f074c48..983c1527d9 100644
--- a/Servers/WindowServer/WSMenu.cpp
+++ b/Servers/WindowServer/WSMenu.cpp
@@ -6,6 +6,7 @@
#include "WSWindowManager.h"
#include <WindowServer/WSAPITypes.h>
#include <WindowServer/WSClientConnection.h>
+#include <SharedGraphics/CharacterBitmap.h>
#include <SharedGraphics/Painter.h>
#include <SharedGraphics/StylePainter.h>
#include <SharedGraphics/Font.h>
@@ -26,6 +27,23 @@ const Font& WSMenu::font() const
return Font::default_font();
}
+static const char* s_checked_bitmap_data = {
+ " "
+ " ## "
+ " ## "
+ " ## "
+ " ## "
+ " ## ## "
+ " #### "
+ " ## "
+ " "
+};
+
+static CharacterBitmap* s_checked_bitmap;
+static const int s_checked_bitmap_width = 9;
+static const int s_checked_bitmap_height = 9;
+static const int s_checked_bitmap_padding = 6;
+
int WSMenu::width() const
{
int longest = 0;
@@ -34,6 +52,8 @@ int WSMenu::width() const
int item_width = font().width(item->text());
if (!item->shortcut_text().is_empty())
item_width += padding_between_text_and_shortcut() + font().width(item->shortcut_text());
+ if (item->is_checkable())
+ item_width += s_checked_bitmap_width + s_checked_bitmap_padding;
longest = max(longest, item_width);
}
@@ -92,6 +112,9 @@ void WSMenu::draw()
StylePainter::paint_menu_frame(painter, rect);
int width = this->width();
+ if (!s_checked_bitmap)
+ s_checked_bitmap = &CharacterBitmap::create_from_ascii(s_checked_bitmap_data, s_checked_bitmap_width, s_checked_bitmap_height).leak_ref();
+
for (auto& item : m_items) {
if (item->type() == WSMenuItem::Text) {
Color text_color = Color::Black;
@@ -101,7 +124,16 @@ void WSMenu::draw()
}
if (!item->is_enabled())
text_color = Color::MidGray;
- painter.draw_text(item->rect().translated(left_padding(), 0), item->text(), TextAlignment::CenterLeft, text_color);
+ Rect text_rect = item->rect().translated(left_padding(), 0);
+ if (item->is_checkable()) {
+ if (item->is_checked()) {
+ Rect checkmark_rect { text_rect.location().x(), 0, s_checked_bitmap_width, s_checked_bitmap_height };
+ checkmark_rect.center_vertically_within(text_rect);
+ painter.draw_bitmap(checkmark_rect.location(), *s_checked_bitmap, Color::Black);
+ }
+ text_rect.move_by(s_checked_bitmap_width + s_checked_bitmap_padding, 0);
+ }
+ painter.draw_text(text_rect, 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);
}
diff --git a/Servers/WindowServer/WSMenuItem.cpp b/Servers/WindowServer/WSMenuItem.cpp
index 95823c86ac..94db473dec 100644
--- a/Servers/WindowServer/WSMenuItem.cpp
+++ b/Servers/WindowServer/WSMenuItem.cpp
@@ -1,10 +1,12 @@
#include "WSMenuItem.h"
#include "WSMenu.h"
-WSMenuItem::WSMenuItem(WSMenu& menu, unsigned identifier, const String& text, const String& shortcut_text, bool enabled)
+WSMenuItem::WSMenuItem(WSMenu& menu, unsigned identifier, const String& text, const String& shortcut_text, bool enabled, bool checkable, bool checked)
: m_menu(menu)
, m_type(Text)
, m_enabled(enabled)
+ , m_checkable(checkable)
+ , m_checked(checked)
, m_identifier(identifier)
, m_text(text)
, m_shortcut_text(shortcut_text)
@@ -28,3 +30,11 @@ void WSMenuItem::set_enabled(bool enabled)
m_enabled = enabled;
m_menu.redraw();
}
+
+void WSMenuItem::set_checked(bool checked)
+{
+ if (m_checked == checked)
+ return;
+ m_checked = checked;
+ m_menu.redraw();
+}
diff --git a/Servers/WindowServer/WSMenuItem.h b/Servers/WindowServer/WSMenuItem.h
index 263114648e..c725a43c14 100644
--- a/Servers/WindowServer/WSMenuItem.h
+++ b/Servers/WindowServer/WSMenuItem.h
@@ -14,7 +14,7 @@ public:
Separator,
};
- WSMenuItem(WSMenu&, unsigned identifier, const String& text, const String& shortcut_text = { }, bool enabled = true);
+ WSMenuItem(WSMenu&, unsigned identifier, const String& text, const String& shortcut_text = { }, bool enabled = true, bool checkable = false, bool checked = false);
WSMenuItem(WSMenu&, Type);
~WSMenuItem();
@@ -23,6 +23,12 @@ public:
bool is_enabled() const { return m_enabled; }
void set_enabled(bool);
+ bool is_checkable() const { return m_checkable; }
+ void set_checkable(bool checkable) { m_checkable = checkable; }
+
+ bool is_checked() const { return m_checked; }
+ void set_checked(bool);
+
String text() const { return m_text; }
void set_text(const String& text) { m_text = text; }
@@ -38,6 +44,8 @@ private:
WSMenu& m_menu;
Type m_type { None };
bool m_enabled { true };
+ bool m_checkable { false };
+ bool m_checked { false };
unsigned m_identifier { 0 };
String m_text;
String m_shortcut_text;