diff options
author | Andreas Kling <kling@serenityos.org> | 2020-03-30 17:00:23 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-03-30 17:03:15 +0200 |
commit | 012a4eb0b5840d1a6843a015e3c0710495984554 (patch) | |
tree | 4a4a14cd9bc0c2f78942d8cc1503f85248aba49d | |
parent | cbd7effd3b0b8a3b19b127f7aad97c75bc680201 (diff) | |
download | serenity-012a4eb0b5840d1a6843a015e3c0710495984554.zip |
WindowServer+NotificationServer: Vertical title bar for notifications
This patch adds a specialized window type for notifications. They now
have a title bar on the right-hand side, with a close button.
This removes the need for the "Done" button in notifications, giving us
a bit more horizontal space overall.
Design based on a mock-up from @xTibor :^)
-rw-r--r-- | Libraries/LibGUI/WindowType.h | 3 | ||||
-rw-r--r-- | Servers/NotificationServer/NotificationWindow.cpp | 23 | ||||
-rw-r--r-- | Servers/WindowServer/Window.cpp | 1 | ||||
-rw-r--r-- | Servers/WindowServer/WindowFrame.cpp | 130 | ||||
-rw-r--r-- | Servers/WindowServer/WindowFrame.h | 11 | ||||
-rw-r--r-- | Servers/WindowServer/WindowManager.h | 6 | ||||
-rw-r--r-- | Servers/WindowServer/WindowType.h | 1 |
7 files changed, 115 insertions, 60 deletions
diff --git a/Libraries/LibGUI/WindowType.h b/Libraries/LibGUI/WindowType.h index 44f342212a..7c2c63930b 100644 --- a/Libraries/LibGUI/WindowType.h +++ b/Libraries/LibGUI/WindowType.h @@ -28,7 +28,7 @@ namespace GUI { -// Keep this in sync with WindowType. +// Keep this in sync with WindowServer::WindowType. enum class WindowType { Invalid = 0, Normal, @@ -38,6 +38,7 @@ enum class WindowType { Tooltip, Menubar, MenuApplet, + Notification, }; } diff --git a/Servers/NotificationServer/NotificationWindow.cpp b/Servers/NotificationServer/NotificationWindow.cpp index 614075701c..96b0c2652d 100644 --- a/Servers/NotificationServer/NotificationWindow.cpp +++ b/Servers/NotificationServer/NotificationWindow.cpp @@ -45,9 +45,9 @@ void update_notification_window_locations() for (auto& window : s_windows) { Gfx::Point new_window_location; if (last_window_rect.is_null()) - new_window_location = GUI::Desktop::the().rect().top_right().translated(-window->rect().width() - 8, 26); + new_window_location = GUI::Desktop::the().rect().top_right().translated(-window->rect().width() - 24, 26); else - new_window_location = last_window_rect.bottom_left().translated(0, 8); + new_window_location = last_window_rect.bottom_left().translated(0, 10); if (window->rect().location() != new_window_location) { window->move_to(new_window_location); window->set_original_rect(window->rect()); @@ -60,7 +60,9 @@ NotificationWindow::NotificationWindow(const String& text, const String& title, { s_windows.append(this); - set_window_type(GUI::WindowType::Tooltip); + set_window_type(GUI::WindowType::Notification); + set_resizable(false); + set_minimizable(false); Gfx::Rect lowest_notification_rect_on_screen; for (auto& window : s_windows) { @@ -69,12 +71,12 @@ NotificationWindow::NotificationWindow(const String& text, const String& title, } Gfx::Rect rect; - rect.set_width(240); + rect.set_width(220); rect.set_height(40); - rect.set_location(GUI::Desktop::the().rect().top_right().translated(-rect.width() - 8, 26)); + rect.set_location(GUI::Desktop::the().rect().top_right().translated(-rect.width() - 24, 26)); if (!lowest_notification_rect_on_screen.is_null()) - rect.set_location(lowest_notification_rect_on_screen.bottom_left().translated(0, 8)); + rect.set_location(lowest_notification_rect_on_screen.bottom_left().translated(0, 10)); set_rect(rect); @@ -108,13 +110,10 @@ NotificationWindow::NotificationWindow(const String& text, const String& title, right_container.set_preferred_size(36, 0); right_container.set_layout<GUI::HorizontalBoxLayout>(); - auto& button = right_container.add<GUI::Button>("Okay"); - button.on_click = [this] { - auto this_window_index = s_windows.find_first_index(this); - if (this_window_index.has_value()) - s_windows.remove(this_window_index.value()); - close(); + on_close_request = [this] { + s_windows.remove_first_matching([this](auto& entry) { return entry == this; }); update_notification_window_locations(); + return CloseRequestDecision::Close; }; } diff --git a/Servers/WindowServer/Window.cpp b/Servers/WindowServer/Window.cpp index d9aff659a1..550c067e13 100644 --- a/Servers/WindowServer/Window.cpp +++ b/Servers/WindowServer/Window.cpp @@ -75,6 +75,7 @@ Window::Window(ClientConnection& client, WindowType window_type, int window_id, m_wm_event_mask = WMEventMask::WindowStateChanges | WMEventMask::WindowRemovals | WMEventMask::WindowIconChanges; m_listens_to_wm_events = true; } + WindowManager::the().add_window(*this); } diff --git a/Servers/WindowServer/WindowFrame.cpp b/Servers/WindowServer/WindowFrame.cpp index ba06336344..cb33949af5 100644 --- a/Servers/WindowServer/WindowFrame.cpp +++ b/Servers/WindowServer/WindowFrame.cpp @@ -152,6 +152,8 @@ void WindowFrame::did_set_maximized(Badge<Window>, bool maximized) Gfx::Rect WindowFrame::title_bar_rect() const { + if (m_window.type() == WindowType::Notification) + return { m_window.width() + 3, 3, window_titlebar_height, m_window.height() }; return { 3, 3, m_window.width(), window_titlebar_height }; } @@ -178,54 +180,58 @@ Gfx::Rect WindowFrame::title_bar_text_rect() const }; } -void WindowFrame::paint(Gfx::Painter& painter) +WindowFrame::FrameColors WindowFrame::compute_frame_colors() const { - Gfx::PainterStateSaver saver(painter); - painter.translate(rect().location()); - - if (m_window.type() != WindowType::Normal) - return; + auto& wm = WindowManager::the(); + auto palette = wm.palette(); + if (&m_window == wm.m_highlight_window) + return { palette.highlight_window_title(), palette.highlight_window_border1(), palette.highlight_window_border2() }; + if (&m_window == wm.m_move_window) + return { palette.moving_window_title(), palette.moving_window_border1(), palette.moving_window_border2() }; + if (&m_window == wm.m_active_window) + return { palette.active_window_title(), palette.active_window_border1(), palette.active_window_border2() }; + return { palette.inactive_window_title(), palette.inactive_window_border1(), palette.inactive_window_border2() }; +} +void WindowFrame::paint_notification_frame(Gfx::Painter& painter) +{ auto palette = WindowManager::the().palette(); - auto& window = m_window; - - auto titlebar_rect = title_bar_rect(); - auto titlebar_icon_rect = title_bar_icon_rect(); - auto titlebar_inner_rect = title_bar_text_rect(); Gfx::Rect outer_rect = { {}, rect().size() }; - auto titlebar_title_rect = titlebar_inner_rect; - titlebar_title_rect.set_width(Gfx::Font::default_bold_font().width(window.title())); - - Color title_color; - Color border_color; - Color border_color2; + Gfx::StylePainter::paint_window_frame(painter, outer_rect, palette); - auto& wm = WindowManager::the(); + auto titlebar_rect = title_bar_rect(); + painter.fill_rect_with_gradient(Gfx::Orientation::Vertical, titlebar_rect, palette.active_window_border1(), palette.active_window_border2()); - if (&window == wm.m_highlight_window) { - border_color = palette.highlight_window_border1(); - border_color2 = palette.highlight_window_border2(); - title_color = palette.highlight_window_title(); - } else if (&window == wm.m_move_window) { - border_color = palette.moving_window_border1(); - border_color2 = palette.moving_window_border2(); - title_color = palette.moving_window_title(); - } else if (&window == wm.m_active_window) { - border_color = palette.active_window_border1(); - border_color2 = palette.active_window_border2(); - title_color = palette.active_window_title(); - } else { - border_color = palette.inactive_window_border1(); - border_color2 = palette.inactive_window_border2(); - title_color = palette.inactive_window_title(); + int stripe_top = m_buttons.last().relative_rect().bottom() + 4; + int stripe_bottom = m_window.height() - 3; + if (stripe_top && stripe_bottom && stripe_top < stripe_bottom) { + for (int i = 2; i <= window_titlebar_height - 2; i += 2) { + painter.draw_line({ titlebar_rect.x() + i, stripe_top }, { titlebar_rect.x() + i, stripe_bottom }, palette.active_window_border1()); + } } +} + +void WindowFrame::paint_normal_frame(Gfx::Painter& painter) +{ + auto palette = WindowManager::the().palette(); + auto& window = m_window; + Gfx::Rect outer_rect = { {}, rect().size() }; Gfx::StylePainter::paint_window_frame(painter, outer_rect, palette); if (!window.show_titlebar()) return; + auto titlebar_rect = title_bar_rect(); + auto titlebar_icon_rect = title_bar_icon_rect(); + auto titlebar_inner_rect = title_bar_text_rect(); + auto titlebar_title_rect = titlebar_inner_rect; + titlebar_title_rect.set_width(Gfx::Font::default_bold_font().width(window.title())); + + auto [title_color, border_color, border_color2] = compute_frame_colors(); + + auto& wm = WindowManager::the(); painter.draw_line(titlebar_rect.bottom_left().translated(0, 1), titlebar_rect.bottom_right().translated(0, 1), palette.button()); auto leftmost_button_rect = m_buttons.is_empty() ? Gfx::Rect() : m_buttons.last().relative_rect(); @@ -249,6 +255,19 @@ void WindowFrame::paint(Gfx::Painter& painter) } painter.blit(titlebar_icon_rect.location(), window.icon(), window.icon().rect()); +} + +void WindowFrame::paint(Gfx::Painter& painter) +{ + Gfx::PainterStateSaver saver(painter); + painter.translate(rect().location()); + + if (m_window.type() == WindowType::Notification) + paint_notification_frame(painter); + else if (m_window.type() == WindowType::Normal) + paint_normal_frame(painter); + else + return; for (auto& button : m_buttons) { button.paint(painter); @@ -262,10 +281,19 @@ static Gfx::Rect frame_rect_for_window(Window& window, const Gfx::Rect& rect) switch (type) { case WindowType::Normal: - return { rect.x() - 3, + return { + rect.x() - 3, rect.y() - window_titlebar_height - 4 + offset, rect.width() + 6, - rect.height() + 7 + window_titlebar_height - offset }; + rect.height() + 7 + window_titlebar_height - offset + }; + case WindowType::Notification: + return { + rect.x() - 3, + rect.y() - 3, + rect.width() + 6 + window_titlebar_height, + rect.height() + 6 + }; default: return rect; } @@ -290,13 +318,24 @@ void WindowFrame::notify_window_rect_changed(const Gfx::Rect& old_rect, const Gf { int window_button_width = 15; int window_button_height = 15; - int x = title_bar_text_rect().right() + 1; + int pos; + if (m_window.type() == WindowType::Notification) + pos = title_bar_rect().top() + 2; + else + pos = title_bar_text_rect().right() + 1; for (auto& button : m_buttons) { - x -= window_button_width; - Gfx::Rect rect { x, 0, window_button_width, window_button_height }; - rect.center_vertically_within(title_bar_text_rect()); - button.set_relative_rect(rect); + if (m_window.type() == WindowType::Notification) { + Gfx::Rect rect { 0, pos, window_button_width, window_button_height }; + rect.center_horizontally_within(title_bar_rect()); + button.set_relative_rect(rect); + pos += window_button_width; + } else { + pos -= window_button_width; + Gfx::Rect rect { pos, 0, window_button_width, window_button_height }; + rect.center_vertically_within(title_bar_text_rect()); + button.set_relative_rect(rect); + } } auto& wm = WindowManager::the(); @@ -313,10 +352,10 @@ void WindowFrame::on_mouse_event(const MouseEvent& event) return; auto& wm = WindowManager::the(); - if (m_window.type() != WindowType::Normal) + if (m_window.type() != WindowType::Normal && m_window.type() != WindowType::Notification) return; - if (event.type() == Event::MouseDown && (event.button() == MouseButton::Left || event.button() == MouseButton::Right) && title_bar_icon_rect().contains(event.position())) { + if (m_window.type() == WindowType::Normal && event.type() == Event::MouseDown && (event.button() == MouseButton::Left || event.button() == MouseButton::Right) && title_bar_icon_rect().contains(event.position())) { wm.move_to_front_and_make_active(m_window); m_window.popup_window_menu(event.position().translated(rect().location())); return; @@ -339,11 +378,11 @@ void WindowFrame::on_mouse_event(const MouseEvent& event) return button.on_mouse_event(event.translated(-button.relative_rect().location())); } if (event.type() == Event::MouseDown) { - if (event.button() == MouseButton::Right) { + if (m_window.type() == WindowType::Normal && event.button() == MouseButton::Right) { m_window.popup_window_menu(event.position().translated(rect().location())); return; } - if (event.button() == MouseButton::Left) + if (m_window.is_movable() && event.button() == MouseButton::Left) wm.start_window_move(m_window, event.translated(rect().location())); } return; @@ -369,5 +408,4 @@ void WindowFrame::on_mouse_event(const MouseEvent& event) if (m_window.is_resizable() && event.type() == Event::MouseDown && event.button() == MouseButton::Left) wm.start_window_resize(m_window, event.translated(rect().location())); } - } diff --git a/Servers/WindowServer/WindowFrame.h b/Servers/WindowServer/WindowFrame.h index 4b2670a725..021edb9d0f 100644 --- a/Servers/WindowServer/WindowFrame.h +++ b/Servers/WindowServer/WindowFrame.h @@ -54,6 +54,17 @@ public: void did_set_maximized(Badge<Window>, bool); private: + void paint_notification_frame(Gfx::Painter&); + void paint_normal_frame(Gfx::Painter&); + + struct FrameColors { + Color title_color; + Color border_color; + Color border_color2; + }; + + FrameColors compute_frame_colors() const; + Window& m_window; NonnullOwnPtrVector<Button> m_buttons; Button* m_maximize_button { nullptr }; diff --git a/Servers/WindowServer/WindowManager.h b/Servers/WindowServer/WindowManager.h index 9c2d1eaf41..a415144fd4 100644 --- a/Servers/WindowServer/WindowManager.h +++ b/Servers/WindowServer/WindowManager.h @@ -315,6 +315,8 @@ IterationDecision WindowManager::for_each_visible_window_from_back_to_front(Call return IterationDecision::Break; if (for_each_visible_window_of_type_from_back_to_front(WindowType::Tooltip, callback) == IterationDecision::Break) return IterationDecision::Break; + if (for_each_visible_window_of_type_from_back_to_front(WindowType::Notification, callback) == IterationDecision::Break) + return IterationDecision::Break; if (for_each_visible_window_of_type_from_back_to_front(WindowType::Menubar, callback) == IterationDecision::Break) return IterationDecision::Break; if (for_each_visible_window_of_type_from_back_to_front(WindowType::Menu, callback) == IterationDecision::Break) @@ -354,10 +356,12 @@ IterationDecision WindowManager::for_each_visible_window_from_front_to_back(Call return IterationDecision::Break; if (for_each_visible_window_of_type_from_front_to_back(WindowType::Menubar, callback) == IterationDecision::Break) return IterationDecision::Break; - if (for_each_visible_window_of_type_from_front_to_back(WindowType::Taskbar, callback) == IterationDecision::Break) + if (for_each_visible_window_of_type_from_back_to_front(WindowType::Notification, callback) == IterationDecision::Break) return IterationDecision::Break; if (for_each_visible_window_of_type_from_front_to_back(WindowType::Tooltip, callback) == IterationDecision::Break) return IterationDecision::Break; + if (for_each_visible_window_of_type_from_front_to_back(WindowType::Taskbar, callback) == IterationDecision::Break) + return IterationDecision::Break; return for_each_visible_window_of_type_from_front_to_back(WindowType::Normal, callback); } diff --git a/Servers/WindowServer/WindowType.h b/Servers/WindowServer/WindowType.h index be6a7522a8..aafb2f19ed 100644 --- a/Servers/WindowServer/WindowType.h +++ b/Servers/WindowServer/WindowType.h @@ -36,4 +36,5 @@ enum class WindowType { Tooltip, Menubar, MenuApplet, + Notification, }; |