Forráskód Böngészése

LibGUI: Start working on a GScrollBar.

This widget is far from finished, but it's off to a good start.
Also added a GResizeEvent and GWidget::resize_event() so that widgets
can react to being resized.
Andreas Kling 6 éve
szülő
commit
1f355f2a79

+ 9 - 0
FileManager/DirectoryView.cpp

@@ -5,6 +5,7 @@
 #include <unistd.h>
 #include <SharedGraphics/GraphicsBitmap.h>
 #include <SharedGraphics/Painter.h>
+#include <LibGUI/GScrollBar.h>
 #include <AK/FileSystemPath.h>
 #include "DirectoryView.h"
 
@@ -14,12 +15,19 @@ DirectoryView::DirectoryView(GWidget* parent)
     m_directory_icon = GraphicsBitmap::load_from_file("/res/icons/folder16.rgb", { 16, 16 });
     m_file_icon = GraphicsBitmap::load_from_file("/res/icons/file16.rgb", { 16, 16 });
     m_symlink_icon = GraphicsBitmap::load_from_file("/res/icons/link16.rgb", { 16, 16 });
+
+    m_scrollbar = new GScrollBar(this);
 }
 
 DirectoryView::~DirectoryView()
 {
 }
 
+void DirectoryView::resize_event(GResizeEvent& event)
+{
+    m_scrollbar->set_relative_rect(event.size().width() - 16, 0, 16, event.size().height());
+}
+
 void DirectoryView::open(const String& path)
 {
     if (m_path == path)
@@ -55,6 +63,7 @@ void DirectoryView::reload()
         entries.append(move(entry));
     }
     closedir(dirp);
+    m_scrollbar->set_range(0, item_count() - 1);
 }
 
 const GraphicsBitmap& DirectoryView::icon_for(const Entry& entry) const

+ 5 - 0
FileManager/DirectoryView.h

@@ -4,6 +4,8 @@
 #include <AK/Function.h>
 #include <sys/stat.h>
 
+class GScrollBar;
+
 class DirectoryView final : public GWidget {
 public:
     DirectoryView(GWidget* parent);
@@ -19,6 +21,7 @@ public:
 
 private:
     virtual void paint_event(GPaintEvent&) override;
+    virtual void resize_event(GResizeEvent&) override;
     virtual void mousedown_event(GMouseEvent&) override;
 
     Rect row_rect(int item_index) const;
@@ -47,4 +50,6 @@ private:
     RetainPtr<GraphicsBitmap> m_directory_icon;
     RetainPtr<GraphicsBitmap> m_file_icon;
     RetainPtr<GraphicsBitmap> m_symlink_icon;
+
+    GScrollBar* m_scrollbar { nullptr };
 };

+ 17 - 0
LibGUI/GEvent.h

@@ -13,6 +13,7 @@ public:
         Show,
         Hide,
         Paint,
+        Resize,
         MouseMove,
         MouseDown,
         MouseUp,
@@ -62,6 +63,22 @@ private:
     Rect m_rect;
 };
 
+class GResizeEvent final : public GEvent {
+public:
+    explicit GResizeEvent(const Size& old_size, const Size& size)
+        : GEvent(GEvent::Resize)
+        , m_old_size(old_size)
+        , m_size(size)
+    {
+    }
+
+    const Size& old_size() const { return m_old_size; }
+    const Size& size() const { return m_size; }
+private:
+    Size m_old_size;
+    Size m_size;
+};
+
 class GShowEvent final : public GEvent {
 public:
     GShowEvent()

+ 120 - 0
LibGUI/GScrollBar.cpp

@@ -0,0 +1,120 @@
+#include <LibGUI/GScrollBar.h>
+#include <SharedGraphics/GraphicsBitmap.h>
+#include <SharedGraphics/Painter.h>
+
+GScrollBar::GScrollBar(GWidget* parent)
+    : GWidget(parent)
+{
+}
+
+GScrollBar::~GScrollBar()
+{
+}
+
+void GScrollBar::set_range(int min, int max)
+{
+    ASSERT(min <= max);
+    if (m_min == min && m_max == max)
+        return;
+
+    m_min = min;
+    m_max = max;
+
+    int old_value = m_value;
+    if (m_value < m_min)
+        m_value = m_min;
+    if (m_value > m_max)
+        m_value = m_max;
+    if (on_change && m_value != old_value)
+        on_change(m_value);
+
+    update();
+}
+
+void GScrollBar::set_value(int value)
+{
+    if (value < m_min)
+        value = m_min;
+    if (value > m_max)
+        value = m_max;
+    if (value == m_value)
+        return;
+    m_value = value;
+    if (on_change)
+        on_change(value);
+    update();
+}
+
+Rect GScrollBar::up_button_rect() const
+{
+    return { 0, 0, button_size(), button_size() };
+}
+
+Rect GScrollBar::down_button_rect() const
+{
+    return { 0, height() - button_size(), button_size(), button_size() };
+}
+
+Rect GScrollBar::pgup_rect() const
+{
+    return { 0, button_size(), button_size(), scrubber_rect().top() - button_size() };
+}
+
+Rect GScrollBar::pgdn_rect() const
+{
+    auto scrubber_rect = this->scrubber_rect();
+    return { 0, scrubber_rect.bottom(), button_size(), height() - button_size() - scrubber_rect.bottom() };
+}
+
+Rect GScrollBar::scrubber_rect() const
+{
+    int range_size = m_max - m_min;
+    if (range_size == 0)
+        return { 0, button_size(), button_size(), height() - button_size() * 2 };
+    float available_y = height() - button_size() * 3;
+    float y_step = available_y / range_size;
+    float y = button_size() + (y_step * m_value);
+    return { 0, (int)y, button_size(), button_size() };
+}
+
+void GScrollBar::paint_event(GPaintEvent&)
+{
+    Painter painter(*this);
+
+    painter.fill_rect(rect(), Color(0xc0c0c0));
+
+    painter.draw_rect(up_button_rect(), Color::DarkGray, true);
+    painter.fill_rect(up_button_rect().shrunken(2, 2), Color::LightGray);
+
+    painter.draw_rect(down_button_rect(), Color::DarkGray, true);
+    painter.fill_rect(down_button_rect().shrunken(2, 2), Color::LightGray);
+
+    painter.fill_rect(pgup_rect(), Color::Magenta);
+    painter.fill_rect(pgdn_rect(), Color::Yellow);
+
+    painter.fill_rect(scrubber_rect(), Color::Red);
+
+    dbgprintf("Paint!\n");
+}
+
+void GScrollBar::mousedown_event(GMouseEvent& event)
+{
+    if (event.button() != GMouseButton::Left)
+        return;
+    if (up_button_rect().contains(event.position())) {
+        set_value(value() - m_step);
+        return;
+    }
+    if (down_button_rect().contains(event.position())) {
+        set_value(value() + m_step);
+        return;
+    }
+    if (pgup_rect().contains(event.position())) {
+        set_value(value() - m_big_step);
+        return;
+    }
+    if (pgdn_rect().contains(event.position())) {
+        set_value(value() + m_big_step);
+        return;
+    }
+}

+ 42 - 0
LibGUI/GScrollBar.h

@@ -0,0 +1,42 @@
+#pragma once
+
+#include <LibGUI/GWidget.h>
+#include <AK/Function.h>
+
+class GScrollBar final : public GWidget {
+public:
+    explicit GScrollBar(GWidget* parent);
+    virtual ~GScrollBar() override;
+
+    int value() const { return m_value; }
+    int min() const { return m_min; }
+    int max() const { return m_max; }
+    int step() const { return m_step; }
+    int big_step() const { return m_big_step; }
+
+    void set_range(int min, int max);
+    void set_value(int value);
+    void set_step(int step) { m_step = step; }
+    void set_big_step(int big_step) { m_big_step = big_step; }
+
+    Function<void(int)> on_change;
+
+private:
+    virtual void paint_event(GPaintEvent&) override;
+    virtual void mousedown_event(GMouseEvent&) override;
+    virtual const char* class_name() const override { return "GScrollBar"; }
+
+    int button_size() const { return 16; }
+    Rect up_button_rect() const;
+    Rect down_button_rect() const;
+    Rect pgup_rect() const;
+    Rect pgdn_rect() const;
+    Rect scrubber_rect() const;
+
+    int m_min { 0 };
+    int m_max { 0 };
+    int m_value { 0 };
+    int m_step { 1 };
+    int m_big_step { 5 };
+};
+

+ 22 - 5
LibGUI/GWidget.cpp

@@ -22,7 +22,10 @@ void GWidget::set_relative_rect(const Rect& rect)
 {
     if (rect == m_relative_rect)
         return;
-    // FIXME: Make some kind of event loop driven ResizeEvent?
+    if (m_relative_rect.size() != rect.size()) {
+        auto event = make<GResizeEvent>(m_relative_rect.size(), rect.size());
+        GEventLoop::main().post_event(this, move(event));
+    }
     m_relative_rect = rect;
     update();
 }
@@ -37,7 +40,9 @@ void GWidget::event(GEvent& event)
     switch (event.type()) {
     case GEvent::Paint:
         m_has_pending_paint_event = false;
-        return paint_event(static_cast<GPaintEvent&>(event));
+        return handle_paint_event(static_cast<GPaintEvent&>(event));
+    case GEvent::Resize:
+        return resize_event(static_cast<GResizeEvent&>(event));
     case GEvent::FocusIn:
         return focusin_event(event);
     case GEvent::FocusOut:
@@ -63,21 +68,33 @@ void GWidget::event(GEvent& event)
     }
 }
 
-void GWidget::paint_event(GPaintEvent& event)
+void GWidget::handle_paint_event(GPaintEvent& event)
 {
     if (fill_with_background_color()) {
         Painter painter(*this);
         painter.fill_rect(event.rect(), background_color());
     }
+    paint_event(event);
     for (auto* ch : children()) {
         auto* child = (GWidget*)ch;
         if (child->relative_rect().intersects(event.rect())) {
-            // FIXME: Pass localized rect?
-            child->event(event);
+            auto local_rect = event.rect();
+            local_rect.intersect(child->relative_rect());
+            local_rect.move_by(-child->relative_rect().x(), -child->relative_rect().y());
+            GPaintEvent local_event(local_rect);
+            child->event(local_event);
         }
     }
 }
 
+void GWidget::resize_event(GResizeEvent&)
+{
+}
+
+void GWidget::paint_event(GPaintEvent&)
+{
+}
+
 void GWidget::show_event(GShowEvent&)
 {
 }

+ 4 - 0
LibGUI/GWidget.h

@@ -17,6 +17,7 @@ public:
 
     virtual void event(GEvent&) override;
     virtual void paint_event(GPaintEvent&);
+    virtual void resize_event(GResizeEvent&);
     virtual void show_event(GShowEvent&);
     virtual void hide_event(GHideEvent&);
     virtual void keydown_event(GKeyEvent&);
@@ -56,6 +57,7 @@ public:
     virtual const char* class_name() const override { return "GWidget"; }
 
     void set_relative_rect(const Rect&);
+    void set_relative_rect(int x, int y, int width, int height) { set_relative_rect({ x, y, width, height }); }
 
     void move_to(const Point& point) { set_relative_rect({ point, relative_rect().size() }); }
     void move_to(int x, int y) { move_to({ x, y }); }
@@ -97,6 +99,8 @@ public:
     bool global_cursor_tracking() const;
 
 private:
+    void handle_paint_event(GPaintEvent&);
+
     GWindow* m_window { nullptr };
 
     Rect m_relative_rect;

+ 1 - 0
LibGUI/Makefile

@@ -14,6 +14,7 @@ LIBGUI_OBJS = \
     GListBox.o \
     GObject.o \
     GTextBox.o \
+    GScrollBar.o \
     GWidget.o \
     GWindow.o
 

+ 3 - 0
SharedGraphics/Point.h

@@ -1,5 +1,7 @@
 #pragma once
 
+#include <AK/AKString.h>
+
 class Rect;
 struct GUI_Point;
 
@@ -47,6 +49,7 @@ public:
     }
 
     operator GUI_Point() const;
+    String to_string() const { return String::format("[%d,%d]", x(), y()); }
 
 private:
     int m_x { 0 };

+ 3 - 0
SharedGraphics/Rect.h

@@ -2,6 +2,7 @@
 
 #include "Point.h"
 #include "Size.h"
+#include <AK/AKString.h>
 
 struct GUI_Rect;
 
@@ -171,6 +172,8 @@ public:
 
     Rect united(const Rect&) const;
 
+    String to_string() const { return String::format("[%d,%d %dx%d]", x(), y(), width(), height()); }
+
 private:
     Point m_location;
     Size m_size;

+ 5 - 0
SharedGraphics/Size.h

@@ -24,6 +24,11 @@ public:
                m_height == other.m_height;
     }
 
+    bool operator!=(const Size& other) const
+    {
+        return !(*this == other);
+    }
+
     operator GUI_Size() const;
 
 private: