Prechádzať zdrojové kódy

Taskbar: Show window progress as a progress bar behind the window title

If a window in the taskbar has progress, we'll now draw that progress
in the form of a progress bar behind the window title on the taskbar
button for the window.
Andreas Kling 5 rokov pred
rodič
commit
e263dc8427

+ 94 - 0
Services/Taskbar/TaskbarButton.cpp

@@ -25,8 +25,13 @@
  */
 
 #include "TaskbarButton.h"
+#include "WindowList.h"
 #include <LibGUI/Action.h>
+#include <LibGUI/Painter.h>
 #include <LibGUI/WindowServerConnection.h>
+#include <LibGfx/Font.h>
+#include <LibGfx/Palette.h>
+#include <LibGfx/StylePainter.h>
 
 TaskbarButton::TaskbarButton(const WindowIdentifier& identifier)
     : m_identifier(identifier)
@@ -51,3 +56,92 @@ void TaskbarButton::resize_event(GUI::ResizeEvent& event)
             screen_relative_rect()));
     return GUI::Button::resize_event(event);
 }
+
+static void paint_custom_progress_bar(GUI::Painter& painter, const Gfx::Rect& rect, const Gfx::Rect& text_rect, const Palette& palette, int min, int max, int value, const StringView& text, const Gfx::Font& font, Gfx::TextAlignment text_alignment)
+{
+    float range_size = max - min;
+    float progress = (value - min) / range_size;
+    float progress_width = progress * rect.width();
+
+    Gfx::Rect progress_rect { rect.x(), rect.y(), (int)progress_width, rect.height() };
+
+    {
+        Gfx::PainterStateSaver saver(painter);
+        painter.add_clip_rect(progress_rect);
+
+        Color start_color = palette.active_window_border1();
+        Color end_color = palette.active_window_border2();
+        painter.fill_rect_with_gradient(rect, start_color, end_color);
+
+        if (!text.is_null()) {
+            painter.draw_text(text_rect.translated(1, 1), text, font, text_alignment, palette.base_text(), Gfx::TextElision::Right);
+            painter.draw_text(text_rect, text, font, text_alignment, palette.base_text().inverted(), Gfx::TextElision::Right);
+        }
+    }
+
+    Gfx::Rect hole_rect { (int)progress_width, 0, (int)(rect.width() - progress_width), rect.height() };
+    hole_rect.move_by(rect.location());
+    hole_rect.set_right_without_resize(rect.right());
+    Gfx::PainterStateSaver saver(painter);
+    painter.add_clip_rect(hole_rect);
+    if (!text.is_null())
+        painter.draw_text(text_rect, text, font, text_alignment, palette.base_text(), Gfx::TextElision::Right);
+}
+
+void TaskbarButton::paint_event(GUI::PaintEvent& event)
+{
+    ASSERT(icon());
+    auto& icon = *this->icon();
+    auto& font = is_checked() ? Gfx::Font::default_bold_font() : this->font();
+    auto& window = WindowList::the().ensure_window(m_identifier);
+
+    GUI::Painter painter(*this);
+    painter.add_clip_rect(event.rect());
+
+    Gfx::StylePainter::paint_button(painter, rect(), palette(), button_style(), is_being_pressed(), is_hovered(), is_checked(), is_enabled());
+
+    if (text().is_empty())
+        return;
+
+    bool has_progress = window.progress() >= 0 && window.progress() <= 100;
+
+    auto content_rect = rect().shrunken(8, 2);
+    auto icon_location = content_rect.center().translated(-(icon.width() / 2), -(icon.height() / 2));
+    if (!text().is_empty())
+        icon_location.set_x(content_rect.x());
+
+    if (!text().is_empty()) {
+        content_rect.move_by(icon.width() + 4, 0);
+        content_rect.set_width(content_rect.width() - icon.width() - 4);
+    }
+
+    Gfx::Rect text_rect { 0, 0, font.width(text()), font.glyph_height() };
+    if (text_rect.width() > content_rect.width())
+        text_rect.set_width(content_rect.width());
+    text_rect.align_within(content_rect, text_alignment());
+
+    if (is_being_pressed() || is_checked()) {
+        text_rect.move_by(1, 1);
+        icon_location.move_by(1, 1);
+    }
+
+    if (has_progress) {
+        auto adjusted_rect = rect().shrunken(4, 4);
+        if (is_being_pressed() || is_checked()) {
+            adjusted_rect.set_height(adjusted_rect.height() + 1);
+        }
+        paint_custom_progress_bar(painter, adjusted_rect, text_rect, palette(), 0, 100, window.progress(), text(), font, text_alignment());
+    }
+
+    if (is_enabled()) {
+        if (is_hovered())
+            painter.blit_brightened(icon_location, icon, icon.rect());
+        else
+            painter.blit(icon_location, icon, icon.rect());
+    } else {
+        painter.blit_dimmed(icon_location, icon, icon.rect());
+    }
+
+    if (!has_progress)
+        paint_text(painter, text_rect, font, text_alignment());
+}

+ 1 - 0
Services/Taskbar/TaskbarButton.h

@@ -39,6 +39,7 @@ private:
 
     virtual void context_menu_event(GUI::ContextMenuEvent&) override;
     virtual void resize_event(GUI::ResizeEvent&) override;
+    virtual void paint_event(GUI::PaintEvent&) override;
 
     WindowIdentifier m_identifier;
 };

+ 1 - 0
Services/Taskbar/TaskbarWindow.cpp

@@ -221,6 +221,7 @@ void TaskbarWindow::wm_event(GUI::WMEvent& event)
         window.set_rect(changed_event.rect());
         window.set_active(changed_event.is_active());
         window.set_minimized(changed_event.is_minimized());
+        window.set_progress(changed_event.progress());
         if (window.is_minimized()) {
             window.button()->set_foreground_color(Color::DarkGray);
             window.button()->set_text(String::format("[%s]", changed_event.title().characters()));

+ 11 - 0
Services/Taskbar/WindowList.h

@@ -62,6 +62,16 @@ public:
     void set_minimized(bool minimized) { m_minimized = minimized; }
     bool is_minimized() const { return m_minimized; }
 
+    void set_progress(int progress)
+    {
+        if (m_progress == progress)
+            return;
+        m_progress = progress;
+        m_button->update();
+    }
+
+    int progress() const { return m_progress; }
+
     const Gfx::Bitmap* icon() const { return m_icon.ptr(); }
 
 private:
@@ -72,6 +82,7 @@ private:
     RefPtr<Gfx::Bitmap> m_icon;
     bool m_active { false };
     bool m_minimized { false };
+    int m_progress { -1 };
 };
 
 class WindowList {