mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 20:45:14 +00:00
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.
This commit is contained in:
parent
4d5fe39494
commit
1f355f2a79
Notes:
sideshowbarker
2024-07-19 15:48:56 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/1f355f2a79e
11 changed files with 231 additions and 5 deletions
|
@ -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
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -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
LibGUI/GScrollBar.cpp
Normal file
120
LibGUI/GScrollBar.cpp
Normal file
|
@ -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
LibGUI/GScrollBar.h
Normal file
42
LibGUI/GScrollBar.h
Normal file
|
@ -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,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&)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -14,6 +14,7 @@ LIBGUI_OBJS = \
|
|||
GListBox.o \
|
||||
GObject.o \
|
||||
GTextBox.o \
|
||||
GScrollBar.o \
|
||||
GWidget.o \
|
||||
GWindow.o
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -24,6 +24,11 @@ public:
|
|||
m_height == other.m_height;
|
||||
}
|
||||
|
||||
bool operator!=(const Size& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
operator GUI_Size() const;
|
||||
|
||||
private:
|
||||
|
|
Loading…
Add table
Reference in a new issue