From 9c6be9b21e3da727ef41908f0377cf1547dfc9c3 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 29 Apr 2019 19:20:34 +0200 Subject: [PATCH] LibGUI: Add a GSlider widget. --- LibGUI/GSlider.cpp | 106 +++++++++++++++++++++++++++++++++++++++++++++ LibGUI/GSlider.h | 40 +++++++++++++++++ LibGUI/Makefile | 1 + 3 files changed, 147 insertions(+) create mode 100644 LibGUI/GSlider.cpp create mode 100644 LibGUI/GSlider.h diff --git a/LibGUI/GSlider.cpp b/LibGUI/GSlider.cpp new file mode 100644 index 00000000000..7f053ddf2bd --- /dev/null +++ b/LibGUI/GSlider.cpp @@ -0,0 +1,106 @@ +#include +#include +#include + +GSlider::GSlider(GWidget* parent) + : GWidget(parent) +{ +} + +GSlider::~GSlider() +{ +} + +void GSlider::set_range(int min, int max) +{ + ASSERT(min <= max); + if (m_min == min && m_max == max) + return; + m_min = min; + m_max = max; + + if (m_value > max) + m_value = max; + if (m_value < min) + m_value = min; + update(); +} + +void GSlider::set_value(int value) +{ + if (value > m_max) + value = m_max; + if (value < m_min) + value = m_min; + if (m_value == value) + return; + m_value = value; + update(); + + if (on_value_changed) + on_value_changed(m_value); +} + +void GSlider::paint_event(GPaintEvent& event) +{ + GPainter painter(*this); + painter.add_clip_rect(event.rect()); + + auto inner_rect = this->inner_rect(); + + Rect track_rect { inner_rect.x(), 0, inner_rect.width(), track_height() }; + track_rect.center_vertically_within(inner_rect); + + StylePainter::paint_frame(painter, track_rect, FrameShape::Panel, FrameShadow::Sunken, 1); + + StylePainter::paint_button(painter, knob_rect(), ButtonStyle::Normal, false, false); +} + +Rect GSlider::knob_rect() const +{ + auto inner_rect = this->inner_rect(); + float range_size = m_max - m_min; + float adjusted_value = m_value - m_min; + float relative_value = adjusted_value / range_size; + Rect rect { inner_rect.x() + (int)(relative_value * inner_rect.width()) - knob_width() / 2, 0, knob_width(), knob_height() }; + rect.center_vertically_within(inner_rect); + return rect; +} + +void GSlider::mousedown_event(GMouseEvent& event) +{ + if (event.button() == GMouseButton::Left) { + if (knob_rect().contains(event.position())) { + m_dragging = true; + m_drag_origin = event.position(); + m_drag_origin_value = m_value; + return; + } + } + + return GWidget::mousedown_event(event); +} + +void GSlider::mousemove_event(GMouseEvent& event) +{ + if (m_dragging) { + float delta = event.position().x() - m_drag_origin.x(); + float scrubbable_range = inner_rect().width(); + float value_steps_per_scrubbed_pixel = (m_max - m_min) / scrubbable_range; + float new_value = m_drag_origin_value + (value_steps_per_scrubbed_pixel * delta); + set_value(new_value); + return; + } + + return GWidget::mousemove_event(event); +} + +void GSlider::mouseup_event(GMouseEvent& event) +{ + if (event.button() == GMouseButton::Left) { + m_dragging = false; + return; + } + + return GWidget::mouseup_event(event); +} diff --git a/LibGUI/GSlider.h b/LibGUI/GSlider.h new file mode 100644 index 00000000000..b90cdb2ed86 --- /dev/null +++ b/LibGUI/GSlider.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +class GSlider : public GWidget { +public: + explicit GSlider(GWidget*); + virtual ~GSlider() override; + + int value() const { return m_value; } + int min() const { return m_min; } + int max() const { return m_max; } + + void set_range(int min, int max); + void set_value(int); + + int track_height() const { return 4; } + int knob_width() const { return 8; } + int knob_height() const { return 20; } + + Rect knob_rect() const; + Rect inner_rect() const { return rect().shrunken(20, 0); } + + Function on_value_changed; + +protected: + virtual void paint_event(GPaintEvent&) override; + virtual void mousedown_event(GMouseEvent&) override; + virtual void mousemove_event(GMouseEvent&) override; + virtual void mouseup_event(GMouseEvent&) override; + +private: + int m_value { 0 }; + int m_min { 0 }; + int m_max { 100 }; + + bool m_dragging { false }; + int m_drag_origin_value { 0 }; + Point m_drag_origin; +}; diff --git a/LibGUI/Makefile b/LibGUI/Makefile index 924a5d3f601..0255d055206 100644 --- a/LibGUI/Makefile +++ b/LibGUI/Makefile @@ -52,6 +52,7 @@ LIBGUI_OBJS = \ GSplitter.o \ GSpinBox.o \ GGroupBox.o \ + GSlider.o \ GWindow.o OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS)