mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:38:10 +00:00
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.
This commit is contained in:
parent
9ff36afeaa
commit
8f81a3f9dd
15 changed files with 148 additions and 20 deletions
|
@ -98,13 +98,24 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
auto view_as_table_action = GAction::create("Table view", { Mod_Ctrl, KeyCode::Key_L }, GraphicsBitmap::load_from_file("/res/icons/16x16/table-view.png"), [&] (const GAction&) {
|
RetainPtr<GAction> view_as_table_action;
|
||||||
directory_view->set_view_mode(DirectoryView::ViewMode::List);
|
RetainPtr<GAction> view_as_icons_action;
|
||||||
});
|
|
||||||
|
|
||||||
auto view_as_icons_action = GAction::create("Icon view", { Mod_Ctrl, KeyCode::Key_I }, GraphicsBitmap::load_from_file("/res/icons/16x16/icon-view.png"), [&] (const GAction&) {
|
view_as_table_action = GAction::create("Table view", { Mod_Ctrl, KeyCode::Key_L }, GraphicsBitmap::load_from_file("/res/icons/16x16/table-view.png"), [&] (const GAction&) {
|
||||||
directory_view->set_view_mode(DirectoryView::ViewMode::Icon);
|
directory_view->set_view_mode(DirectoryView::ViewMode::List);
|
||||||
|
view_as_icons_action->set_checked(false);
|
||||||
|
view_as_table_action->set_checked(true);
|
||||||
});
|
});
|
||||||
|
view_as_table_action->set_checkable(true);
|
||||||
|
view_as_table_action->set_checked(false);
|
||||||
|
|
||||||
|
view_as_icons_action = GAction::create("Icon view", { Mod_Ctrl, KeyCode::Key_I }, GraphicsBitmap::load_from_file("/res/icons/16x16/icon-view.png"), [&] (const GAction&) {
|
||||||
|
directory_view->set_view_mode(DirectoryView::ViewMode::Icon);
|
||||||
|
view_as_table_action->set_checked(false);
|
||||||
|
view_as_icons_action->set_checked(true);
|
||||||
|
});
|
||||||
|
view_as_icons_action->set_checkable(true);
|
||||||
|
view_as_icons_action->set_checked(true);
|
||||||
|
|
||||||
auto copy_action = GAction::create("Copy", GraphicsBitmap::load_from_file("/res/icons/16x16/edit-copy.png"), [] (const GAction&) {
|
auto copy_action = GAction::create("Copy", GraphicsBitmap::load_from_file("/res/icons/16x16/edit-copy.png"), [] (const GAction&) {
|
||||||
dbgprintf("'Copy' action activated!\n");
|
dbgprintf("'Copy' action activated!\n");
|
||||||
|
@ -138,8 +149,8 @@ int main(int argc, char** argv)
|
||||||
menubar->add_menu(move(file_menu));
|
menubar->add_menu(move(file_menu));
|
||||||
|
|
||||||
auto view_menu = make<GMenu>("View");
|
auto view_menu = make<GMenu>("View");
|
||||||
view_menu->add_action(view_as_table_action.copy_ref());
|
view_menu->add_action(*view_as_icons_action);
|
||||||
view_menu->add_action(view_as_icons_action.copy_ref());
|
view_menu->add_action(*view_as_table_action);
|
||||||
menubar->add_menu(move(view_menu));
|
menubar->add_menu(move(view_menu));
|
||||||
|
|
||||||
auto go_menu = make<GMenu>("Go");
|
auto go_menu = make<GMenu>("Go");
|
||||||
|
@ -165,8 +176,8 @@ int main(int argc, char** argv)
|
||||||
main_toolbar->add_action(delete_action.copy_ref());
|
main_toolbar->add_action(delete_action.copy_ref());
|
||||||
|
|
||||||
main_toolbar->add_separator();
|
main_toolbar->add_separator();
|
||||||
main_toolbar->add_action(view_as_icons_action.copy_ref());
|
main_toolbar->add_action(*view_as_icons_action);
|
||||||
main_toolbar->add_action(view_as_table_action.copy_ref());
|
main_toolbar->add_action(*view_as_table_action);
|
||||||
|
|
||||||
directory_view->on_path_change = [window, location_textbox, &file_system_model, tree_view] (const String& new_path) {
|
directory_view->on_path_change = [window, location_textbox, &file_system_model, tree_view] (const String& new_path) {
|
||||||
window->set_title(String::format("FileManager: %s", new_path.characters()));
|
window->set_title(String::format("FileManager: %s", new_path.characters()));
|
||||||
|
|
|
@ -106,3 +106,16 @@ void GAction::set_enabled(bool enabled)
|
||||||
item.set_enabled(enabled);
|
item.set_enabled(enabled);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GAction::set_checked(bool checked)
|
||||||
|
{
|
||||||
|
if (m_checked == checked)
|
||||||
|
return;
|
||||||
|
m_checked = checked;
|
||||||
|
for_each_toolbar_button([checked] (GButton& button) {
|
||||||
|
button.set_checked(checked);
|
||||||
|
});
|
||||||
|
for_each_menu_item([checked] (GMenuItem& item) {
|
||||||
|
item.set_checked(checked);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -59,6 +59,12 @@ public:
|
||||||
bool is_enabled() const { return m_enabled; }
|
bool is_enabled() const { return m_enabled; }
|
||||||
void set_enabled(bool);
|
void set_enabled(bool);
|
||||||
|
|
||||||
|
bool is_checkable() const { return m_checkable; }
|
||||||
|
void set_checkable(bool checkable) { m_checkable = checkable; }
|
||||||
|
|
||||||
|
bool is_checked() const { ASSERT(is_checkable()); return m_checked; }
|
||||||
|
void set_checked(bool);
|
||||||
|
|
||||||
void register_button(Badge<GButton>, GButton&);
|
void register_button(Badge<GButton>, GButton&);
|
||||||
void unregister_button(Badge<GButton>, GButton&);
|
void unregister_button(Badge<GButton>, GButton&);
|
||||||
void register_menu_item(Badge<GMenuItem>, GMenuItem&);
|
void register_menu_item(Badge<GMenuItem>, GMenuItem&);
|
||||||
|
@ -79,6 +85,8 @@ private:
|
||||||
RetainPtr<GraphicsBitmap> m_icon;
|
RetainPtr<GraphicsBitmap> m_icon;
|
||||||
GShortcut m_shortcut;
|
GShortcut m_shortcut;
|
||||||
bool m_enabled { true };
|
bool m_enabled { true };
|
||||||
|
bool m_checkable { false };
|
||||||
|
bool m_checked { false };
|
||||||
ShortcutScope m_scope { ShortcutScope::None };
|
ShortcutScope m_scope { ShortcutScope::None };
|
||||||
|
|
||||||
HashTable<GButton*> m_buttons;
|
HashTable<GButton*> m_buttons;
|
||||||
|
|
|
@ -133,6 +133,9 @@ void GButton::set_action(GAction& action)
|
||||||
m_action = action.make_weak_ptr();
|
m_action = action.make_weak_ptr();
|
||||||
action.register_button({ }, *this);
|
action.register_button({ }, *this);
|
||||||
set_enabled(action.is_enabled());
|
set_enabled(action.is_enabled());
|
||||||
|
set_checkable(action.is_checkable());
|
||||||
|
if (action.is_checkable())
|
||||||
|
set_checked(action.is_checked());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GButton::set_icon(RetainPtr<GraphicsBitmap>&& icon)
|
void GButton::set_icon(RetainPtr<GraphicsBitmap>&& icon)
|
||||||
|
|
|
@ -90,6 +90,9 @@ int GMenu::realize_menu()
|
||||||
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();
|
request.menu.enabled = action.is_enabled();
|
||||||
|
request.menu.checkable = action.is_checkable();
|
||||||
|
if (action.is_checkable())
|
||||||
|
request.menu.checked = action.is_checked();
|
||||||
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();
|
||||||
|
|
|
@ -16,6 +16,9 @@ GMenuItem::GMenuItem(unsigned menu_id, Retained<GAction>&& action)
|
||||||
{
|
{
|
||||||
m_action->register_menu_item({ }, *this);
|
m_action->register_menu_item({ }, *this);
|
||||||
m_enabled = m_action->is_enabled();
|
m_enabled = m_action->is_enabled();
|
||||||
|
m_checkable = m_action->is_checkable();
|
||||||
|
if (m_checkable)
|
||||||
|
m_checked = m_action->is_checked();
|
||||||
}
|
}
|
||||||
|
|
||||||
GMenuItem::~GMenuItem()
|
GMenuItem::~GMenuItem()
|
||||||
|
@ -32,6 +35,15 @@ void GMenuItem::set_enabled(bool enabled)
|
||||||
update_window_server();
|
update_window_server();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GMenuItem::set_checked(bool checked)
|
||||||
|
{
|
||||||
|
ASSERT(is_checkable());
|
||||||
|
if (m_checked == checked)
|
||||||
|
return;
|
||||||
|
m_checked = checked;
|
||||||
|
update_window_server();
|
||||||
|
}
|
||||||
|
|
||||||
void GMenuItem::update_window_server()
|
void GMenuItem::update_window_server()
|
||||||
{
|
{
|
||||||
auto& action = *m_action;
|
auto& action = *m_action;
|
||||||
|
@ -40,6 +52,9 @@ void GMenuItem::update_window_server()
|
||||||
request.menu.menu_id = m_menu_id;
|
request.menu.menu_id = m_menu_id;
|
||||||
request.menu.identifier = m_identifier;
|
request.menu.identifier = m_identifier;
|
||||||
request.menu.enabled = action.is_enabled();
|
request.menu.enabled = action.is_enabled();
|
||||||
|
request.menu.checkable = action.is_checkable();
|
||||||
|
if (action.is_checkable())
|
||||||
|
request.menu.checked = action.is_checked();
|
||||||
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();
|
||||||
|
|
|
@ -20,6 +20,12 @@ 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_checkable() const { return m_checkable; }
|
||||||
|
void set_checkable(bool checkable) { m_checkable = checkable; }
|
||||||
|
|
||||||
|
bool is_checked() const { return m_checked; }
|
||||||
|
void set_checked(bool);
|
||||||
|
|
||||||
bool is_enabled() const { return m_enabled; }
|
bool is_enabled() const { return m_enabled; }
|
||||||
void set_enabled(bool);
|
void set_enabled(bool);
|
||||||
|
|
||||||
|
@ -33,6 +39,8 @@ private:
|
||||||
unsigned m_menu_id { 0 };
|
unsigned m_menu_id { 0 };
|
||||||
unsigned m_identifier { 0 };
|
unsigned m_identifier { 0 };
|
||||||
bool m_enabled { true };
|
bool m_enabled { true };
|
||||||
|
bool m_checkable { false };
|
||||||
|
bool m_checked { false };
|
||||||
RetainPtr<GAction> m_action;
|
RetainPtr<GAction> m_action;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -246,6 +246,8 @@ struct WSAPI_ClientMessage {
|
||||||
char shortcut_text[32];
|
char shortcut_text[32];
|
||||||
int shortcut_text_length;
|
int shortcut_text_length;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
bool checkable;
|
||||||
|
bool checked;
|
||||||
WSAPI_Point position;
|
WSAPI_Point position;
|
||||||
bool top_anchored;
|
bool top_anchored;
|
||||||
} menu;
|
} menu;
|
||||||
|
|
|
@ -241,7 +241,7 @@ void WSClientConnection::handle_request(const WSAPIAddMenuItemRequest& request)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto& menu = *(*it).value;
|
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;
|
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;
|
||||||
|
@ -292,6 +292,9 @@ void WSClientConnection::handle_request(const WSAPIUpdateMenuItemRequest& reques
|
||||||
menu_item->set_text(request.text());
|
menu_item->set_text(request.text());
|
||||||
menu_item->set_shortcut_text(request.shortcut_text());
|
menu_item->set_shortcut_text(request.shortcut_text());
|
||||||
menu_item->set_enabled(request.is_enabled());
|
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;
|
WSAPI_ServerMessage response;
|
||||||
response.type = WSAPI_ServerMessage::Type::DidUpdateMenuItem;
|
response.type = WSAPI_ServerMessage::Type::DidUpdateMenuItem;
|
||||||
response.menu.menu_id = menu_id;
|
response.menu.menu_id = menu_id;
|
||||||
|
|
|
@ -276,13 +276,15 @@ 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, 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)
|
: WSAPIClientRequest(WSEvent::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)
|
, m_enabled(enabled)
|
||||||
|
, m_checkable(checkable)
|
||||||
|
, m_checked(checked)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,24 +293,30 @@ public:
|
||||||
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; }
|
bool is_enabled() const { return m_enabled; }
|
||||||
|
bool is_checkable() const { return m_checkable; }
|
||||||
|
bool is_checked() const { return m_checked; }
|
||||||
|
|
||||||
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 };
|
bool m_enabled;
|
||||||
|
bool m_checkable;
|
||||||
|
bool m_checked;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WSAPIUpdateMenuItemRequest : public WSAPIClientRequest {
|
class WSAPIUpdateMenuItemRequest : public WSAPIClientRequest {
|
||||||
public:
|
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)
|
: WSAPIClientRequest(WSEvent::APIUpdateMenuItemRequest, 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)
|
, m_enabled(enabled)
|
||||||
|
, m_checkable(checkable)
|
||||||
|
, m_checked(checked)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,6 +325,8 @@ public:
|
||||||
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; }
|
bool is_enabled() const { return m_enabled; }
|
||||||
|
bool is_checkable() const { return m_checkable; }
|
||||||
|
bool is_checked() const { return m_checked; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_menu_id { 0 };
|
int m_menu_id { 0 };
|
||||||
|
@ -324,6 +334,8 @@ private:
|
||||||
String m_text;
|
String m_text;
|
||||||
String m_shortcut_text;
|
String m_shortcut_text;
|
||||||
bool m_enabled { true };
|
bool m_enabled { true };
|
||||||
|
bool m_checkable;
|
||||||
|
bool m_checked;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WSAPIAddMenuSeparatorRequest : public WSAPIClientRequest {
|
class WSAPIAddMenuSeparatorRequest : public WSAPIClientRequest {
|
||||||
|
|
|
@ -170,12 +170,12 @@ bool WSEventLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessag
|
||||||
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_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;
|
break;
|
||||||
case WSAPI_ClientMessage::Type::UpdateMenuItem:
|
case WSAPI_ClientMessage::Type::UpdateMenuItem:
|
||||||
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_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;
|
break;
|
||||||
case WSAPI_ClientMessage::Type::AddMenuSeparator:
|
case WSAPI_ClientMessage::Type::AddMenuSeparator:
|
||||||
post_event(client, make<WSAPIAddMenuSeparatorRequest>(client_id, message.menu.menu_id));
|
post_event(client, make<WSAPIAddMenuSeparatorRequest>(client_id, message.menu.menu_id));
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "WSWindowManager.h"
|
#include "WSWindowManager.h"
|
||||||
#include <WindowServer/WSAPITypes.h>
|
#include <WindowServer/WSAPITypes.h>
|
||||||
#include <WindowServer/WSClientConnection.h>
|
#include <WindowServer/WSClientConnection.h>
|
||||||
|
#include <SharedGraphics/CharacterBitmap.h>
|
||||||
#include <SharedGraphics/Painter.h>
|
#include <SharedGraphics/Painter.h>
|
||||||
#include <SharedGraphics/StylePainter.h>
|
#include <SharedGraphics/StylePainter.h>
|
||||||
#include <SharedGraphics/Font.h>
|
#include <SharedGraphics/Font.h>
|
||||||
|
@ -26,6 +27,23 @@ const Font& WSMenu::font() const
|
||||||
return Font::default_font();
|
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 WSMenu::width() const
|
||||||
{
|
{
|
||||||
int longest = 0;
|
int longest = 0;
|
||||||
|
@ -34,6 +52,8 @@ int WSMenu::width() const
|
||||||
int item_width = font().width(item->text());
|
int item_width = font().width(item->text());
|
||||||
if (!item->shortcut_text().is_empty())
|
if (!item->shortcut_text().is_empty())
|
||||||
item_width += padding_between_text_and_shortcut() + font().width(item->shortcut_text());
|
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);
|
longest = max(longest, item_width);
|
||||||
}
|
}
|
||||||
|
@ -92,6 +112,9 @@ void WSMenu::draw()
|
||||||
StylePainter::paint_menu_frame(painter, rect);
|
StylePainter::paint_menu_frame(painter, rect);
|
||||||
int width = this->width();
|
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) {
|
for (auto& item : m_items) {
|
||||||
if (item->type() == WSMenuItem::Text) {
|
if (item->type() == WSMenuItem::Text) {
|
||||||
Color text_color = Color::Black;
|
Color text_color = Color::Black;
|
||||||
|
@ -101,7 +124,16 @@ void WSMenu::draw()
|
||||||
}
|
}
|
||||||
if (!item->is_enabled())
|
if (!item->is_enabled())
|
||||||
text_color = Color::MidGray;
|
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()) {
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#include "WSMenuItem.h"
|
#include "WSMenuItem.h"
|
||||||
#include "WSMenu.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_menu(menu)
|
||||||
, m_type(Text)
|
, m_type(Text)
|
||||||
, m_enabled(enabled)
|
, m_enabled(enabled)
|
||||||
|
, m_checkable(checkable)
|
||||||
|
, m_checked(checked)
|
||||||
, m_identifier(identifier)
|
, m_identifier(identifier)
|
||||||
, m_text(text)
|
, m_text(text)
|
||||||
, m_shortcut_text(shortcut_text)
|
, m_shortcut_text(shortcut_text)
|
||||||
|
@ -28,3 +30,11 @@ void WSMenuItem::set_enabled(bool enabled)
|
||||||
m_enabled = enabled;
|
m_enabled = enabled;
|
||||||
m_menu.redraw();
|
m_menu.redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WSMenuItem::set_checked(bool checked)
|
||||||
|
{
|
||||||
|
if (m_checked == checked)
|
||||||
|
return;
|
||||||
|
m_checked = checked;
|
||||||
|
m_menu.redraw();
|
||||||
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public:
|
||||||
Separator,
|
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(WSMenu&, Type);
|
||||||
~WSMenuItem();
|
~WSMenuItem();
|
||||||
|
|
||||||
|
@ -23,6 +23,12 @@ public:
|
||||||
bool is_enabled() const { return m_enabled; }
|
bool is_enabled() const { return m_enabled; }
|
||||||
void set_enabled(bool);
|
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; }
|
String text() const { return m_text; }
|
||||||
void set_text(const String& text) { m_text = text; }
|
void set_text(const String& text) { m_text = text; }
|
||||||
|
|
||||||
|
@ -38,6 +44,8 @@ private:
|
||||||
WSMenu& m_menu;
|
WSMenu& m_menu;
|
||||||
Type m_type { None };
|
Type m_type { None };
|
||||||
bool m_enabled { true };
|
bool m_enabled { true };
|
||||||
|
bool m_checkable { false };
|
||||||
|
bool m_checked { false };
|
||||||
unsigned m_identifier { 0 };
|
unsigned m_identifier { 0 };
|
||||||
String m_text;
|
String m_text;
|
||||||
String m_shortcut_text;
|
String m_shortcut_text;
|
||||||
|
|
|
@ -58,7 +58,7 @@ void StylePainter::paint_button(Painter& painter, const Rect& rect, ButtonStyle
|
||||||
if (button_style == ButtonStyle::Normal)
|
if (button_style == ButtonStyle::Normal)
|
||||||
return paint_button_new(painter, rect, pressed, checked, hovered);
|
return paint_button_new(painter, rect, pressed, checked, hovered);
|
||||||
|
|
||||||
Color button_color = Color::LightGray;
|
Color button_color = checked ? Color::from_rgb(0xd6d2ce) : Color::LightGray;
|
||||||
Color highlight_color = Color::White;
|
Color highlight_color = Color::White;
|
||||||
Color shadow_color = Color(96, 96, 96);
|
Color shadow_color = Color(96, 96, 96);
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ void StylePainter::paint_button(Painter& painter, const Rect& rect, ButtonStyle
|
||||||
PainterStateSaver saver(painter);
|
PainterStateSaver saver(painter);
|
||||||
painter.translate(rect.location());
|
painter.translate(rect.location());
|
||||||
|
|
||||||
if (pressed) {
|
if (pressed || checked) {
|
||||||
// Base
|
// Base
|
||||||
painter.fill_rect({ 1, 1, rect.width() - 2, rect.height() - 2 }, button_color);
|
painter.fill_rect({ 1, 1, rect.width() - 2, rect.height() - 2 }, button_color);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue