mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 21:57:35 +00:00
LibGUI+WindowServer: Flash menubar menu when using a keyboard shortcut
Briefly flash the menubar menu containing the keyboard shortcut action to give the user immediate visual feedback on their interaction with the system.
This commit is contained in:
parent
ed0f4bdfaf
commit
6c049ea4c4
11 changed files with 88 additions and 1 deletions
|
@ -192,6 +192,40 @@ void ClientConnection::update_menu_item(i32 menu_id, i32 identifier, [[maybe_unu
|
|||
menu_item->set_checked(checked);
|
||||
}
|
||||
|
||||
void ClientConnection::flash_menubar_menu(i32 window_id, i32 menu_id)
|
||||
{
|
||||
auto itw = m_windows.find(window_id);
|
||||
if (itw == m_windows.end()) {
|
||||
did_misbehave("FlashMenubarMenu: Bad window ID");
|
||||
return;
|
||||
}
|
||||
auto& window = *(*itw).value;
|
||||
|
||||
auto itm = m_menus.find(menu_id);
|
||||
if (itm == m_menus.end()) {
|
||||
did_misbehave("FlashMenubarMenu: Bad menu ID");
|
||||
return;
|
||||
}
|
||||
auto& menu = *(*itm).value;
|
||||
|
||||
if (window.menubar().flash_menu(&menu)) {
|
||||
window.frame().invalidate_menubar();
|
||||
|
||||
if (m_flashed_menu_timer && m_flashed_menu_timer->is_active()) {
|
||||
m_flashed_menu_timer->on_timeout();
|
||||
m_flashed_menu_timer->stop();
|
||||
}
|
||||
|
||||
m_flashed_menu_timer = Core::Timer::create_single_shot(75, [&window] {
|
||||
window.menubar().flash_menu(nullptr);
|
||||
window.frame().invalidate_menubar();
|
||||
});
|
||||
m_flashed_menu_timer->start();
|
||||
} else if (m_flashed_menu_timer) {
|
||||
m_flashed_menu_timer->restart();
|
||||
}
|
||||
}
|
||||
|
||||
void ClientConnection::add_menu_separator(i32 menu_id)
|
||||
{
|
||||
auto it = m_menus.find(menu_id);
|
||||
|
|
|
@ -97,6 +97,7 @@ private:
|
|||
virtual void add_menu_item(i32, i32, i32, String const&, bool, bool, bool, bool, String const&, Gfx::ShareableBitmap const&, bool) override;
|
||||
virtual void add_menu_separator(i32) override;
|
||||
virtual void update_menu_item(i32, i32, i32, String const&, bool, bool, bool, bool, String const&) override;
|
||||
virtual void flash_menubar_menu(i32, i32) override;
|
||||
virtual void create_window(i32, Gfx::IntRect const&, bool, bool, bool, bool, bool,
|
||||
bool, bool, bool, bool, bool, float, float, Gfx::IntSize const&, Gfx::IntSize const&, Gfx::IntSize const&,
|
||||
Optional<Gfx::IntSize> const&, i32, String const&, i32, Gfx::IntRect const&) override;
|
||||
|
@ -178,6 +179,7 @@ private:
|
|||
HashMap<int, NonnullRefPtr<Window>> m_windows;
|
||||
HashMap<int, NonnullRefPtr<Menu>> m_menus;
|
||||
|
||||
RefPtr<Core::Timer> m_flashed_menu_timer;
|
||||
RefPtr<Core::Timer> m_ping_timer;
|
||||
|
||||
bool m_has_display_link { false };
|
||||
|
|
|
@ -23,6 +23,26 @@ public:
|
|||
layout_menu(menu, window_rect);
|
||||
}
|
||||
|
||||
bool flash_menu(Menu* flashed_submenu)
|
||||
{
|
||||
Menu* const old_flashed_menu = m_flashed_menu;
|
||||
m_flashed_menu = nullptr;
|
||||
|
||||
if (flashed_submenu) {
|
||||
for_each_menu([&](Menu& menu) {
|
||||
if ((&menu) == flashed_submenu || menu.is_menu_ancestor_of(*flashed_submenu)) {
|
||||
m_flashed_menu = &menu;
|
||||
return IterationDecision::Break;
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
return (old_flashed_menu != m_flashed_menu);
|
||||
}
|
||||
|
||||
Menu* flashed_menu() const { return m_flashed_menu; }
|
||||
|
||||
bool has_menus()
|
||||
{
|
||||
return !m_menus.is_empty();
|
||||
|
@ -40,6 +60,7 @@ private:
|
|||
void layout_menu(Menu&, Gfx::IntRect window_rect);
|
||||
|
||||
Vector<Menu&> m_menus;
|
||||
Menu* m_flashed_menu { nullptr };
|
||||
|
||||
// FIXME: This doesn't support removing menus from a menubar or inserting a
|
||||
// menu in the middle.
|
||||
|
|
|
@ -264,8 +264,15 @@ void WindowFrame::paint_menubar(Gfx::Painter& painter)
|
|||
painter.translate(menubar_rect.location());
|
||||
|
||||
m_window.menubar().for_each_menu([&](Menu& menu) {
|
||||
bool paint_as_flashed = ((&menu) == m_window.menubar().flashed_menu());
|
||||
if (paint_as_flashed) {
|
||||
auto flashed_rect = menu.rect_in_window_menubar();
|
||||
flashed_rect.shrink(2, 2);
|
||||
painter.fill_rect(flashed_rect, palette.selection());
|
||||
}
|
||||
|
||||
auto text_rect = menu.rect_in_window_menubar();
|
||||
Color text_color = palette.window_text();
|
||||
Color text_color = (paint_as_flashed ? palette.selection_text() : palette.window_text());
|
||||
auto is_open = menu.is_open();
|
||||
if (is_open)
|
||||
text_rect.translate_by(1, 1);
|
||||
|
|
|
@ -24,6 +24,7 @@ endpoint WindowServer
|
|||
add_menu_separator(i32 menu_id) =|
|
||||
|
||||
update_menu_item(i32 menu_id, i32 identifier, i32 submenu_id, [UTF8] String text, bool enabled, bool checkable, bool checked, bool is_default, [UTF8] String shortcut) =|
|
||||
flash_menubar_menu(i32 window_id, i32 menu_id) =|
|
||||
|
||||
create_window(
|
||||
i32 window_id,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue