improved resizable scrollbar functionality

This commit is contained in:
itsmattkc
2021-01-23 08:19:04 +11:00
parent 03dc971a4b
commit ec4d061857
4 changed files with 94 additions and 63 deletions
@@ -48,53 +48,23 @@ void ResizableScrollBar::mousePressEvent(QMouseEvent *event)
if (mouse_handle_state_ == kNotInHandle) {
QScrollBar::mousePressEvent(event);
} else {
mouse_dragging_ = true;
dragging_ = true;
mouse_drag_start_ = GetActiveMousePos(event);
drag_start_point_ = GetActiveMousePos(event);
emit ResizeBegan(GetActiveBarSize(), (mouse_handle_state_ == kInTopHandle));
}
}
void ResizableScrollBar::mouseMoveEvent(QMouseEvent *event)
{
QStyleOptionSlider opt;
initStyleOption(&opt);
QRect sr = GetScrollBarRect();
QRect sr = style()->subControlRect(QStyle::CC_ScrollBar, &opt,
QStyle::SC_ScrollBarSlider, this);
if (dragging_) {
// Determine how much the cursor has moved
int mouse_movement = GetActiveMousePos(event) - drag_start_point_;
if (mouse_dragging_) {
int new_drag_pos = GetActiveMousePos(event);
int mouse_movement = new_drag_pos - mouse_drag_start_;
mouse_drag_start_ = new_drag_pos;
if (mouse_handle_state_ == kInTopHandle) {
mouse_movement = -mouse_movement;
}
double width_adjustment = static_cast<double>(sr.width() + mouse_movement);
// Prevent dividing by zero or emitting a negative scale
if (width_adjustment > 0) {
double scale_multiplier = static_cast<double>(sr.width()) / width_adjustment;
emit RequestScale(scale_multiplier);
if (mouse_handle_state_ == kInTopHandle) {
QRect gr = style()->subControlRect(QStyle::CC_ScrollBar, &opt,
QStyle::SC_ScrollBarGroove, this);
int slider_min = gr.x();
int slider_max = gr.right() - (sr.width() + mouse_movement);
int val = QStyle::sliderValueFromPosition(minimum(),
maximum(),
event->pos().x() - slider_min,
slider_max - slider_min,
opt.upsideDown);
setValue(val);
} else {
setValue(qRound(static_cast<double>(value()) * scale_multiplier));
}
}
emit ResizeMoved(mouse_movement);
} else {
@@ -133,13 +103,27 @@ void ResizableScrollBar::mouseMoveEvent(QMouseEvent *event)
void ResizableScrollBar::mouseReleaseEvent(QMouseEvent *event)
{
if (mouse_dragging_) {
mouse_dragging_ = false;
if (dragging_) {
dragging_ = false;
emit ResizeEnded();
} else {
QScrollBar::mouseReleaseEvent(event);
}
}
QRect ResizableScrollBar::GetScrollBarRect()
{
// Initialize "style option". I don't know what this does, I just ripped it straight from
// Qt source code
QStyleOptionSlider opt;
initStyleOption(&opt);
// Determine rect of slider bar
return style()->subControlRect(QStyle::CC_ScrollBar, &opt,
QStyle::SC_ScrollBarSlider, this);
}
void ResizableScrollBar::Init()
{
setSingleStep(20);
@@ -147,7 +131,7 @@ void ResizableScrollBar::Init()
setMouseTracking(true);
mouse_handle_state_= kNotInHandle;
mouse_dragging_ = false;
dragging_ = false;
}
int ResizableScrollBar::GetActiveMousePos(QMouseEvent *event)
@@ -159,4 +143,15 @@ int ResizableScrollBar::GetActiveMousePos(QMouseEvent *event)
}
}
int ResizableScrollBar::GetActiveBarSize()
{
QRect sr = GetScrollBarRect();
if (orientation() == Qt::Horizontal) {
return sr.width();
} else {
return sr.height();
}
}
}
@@ -35,7 +35,11 @@ public:
ResizableScrollBar(Qt::Orientation orientation, QWidget* parent = nullptr);
signals:
void RequestScale(const double& multiplier);
void ResizeBegan(int old_bar_width, bool top_handle);
void ResizeMoved(int movement);
void ResizeEnded();
protected:
virtual void mousePressEvent(QMouseEvent* event) override;
@@ -45,6 +49,8 @@ protected:
virtual void mouseReleaseEvent(QMouseEvent* event) override;
private:
QRect GetScrollBarRect();
static const int kHandleWidth;
enum MouseHandleState {
@@ -57,11 +63,13 @@ private:
int GetActiveMousePos(QMouseEvent* event);
int GetActiveBarSize();
MouseHandleState mouse_handle_state_;
bool mouse_dragging_;
bool dragging_;
int mouse_drag_start_;
int drag_start_point_;
};
+38 -17
View File
@@ -44,7 +44,8 @@ TimeBasedWidget::TimeBasedWidget(bool ruler_text_visible, bool ruler_cache_statu
connect(ruler_, &TimeRuler::TimeChanged, this, &TimeBasedWidget::SetTimeAndSignal);
scrollbar_ = new ResizableTimelineScrollBar(Qt::Horizontal, this);
connect(scrollbar_, &ResizableScrollBar::RequestScale, this, &TimeBasedWidget::ScrollBarResized);
connect(scrollbar_, &ResizableScrollBar::ResizeBegan, this, &TimeBasedWidget::ScrollBarResizeBegan);
connect(scrollbar_, &ResizableScrollBar::ResizeMoved, this, &TimeBasedWidget::ScrollBarResizeMoved);
PassWheelEventsToScrollBar(ruler_);
}
@@ -126,7 +127,7 @@ void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node)
void TimeBasedWidget::UpdateMaximumScroll()
{
rational length = (viewer_node_) ? viewer_node_->GetLength() : rational();
rational length = (viewer_node_) ? viewer_node_->GetLength() : 0;
if (auto_max_scrollbar_) {
scrollbar_->setMaximum(qMax(0, qCeil(TimeToScene(length)) - width()));
@@ -137,27 +138,47 @@ void TimeBasedWidget::UpdateMaximumScroll()
}
}
void TimeBasedWidget::ScrollBarResized(const double &multiplier)
void TimeBasedWidget::ScrollBarResizeBegan(int current_bar_width, bool top_handle)
{
QScrollBar* bar = static_cast<QScrollBar*>(sender());
// Our extension area (represented by a TimelineViewEndItem) is NOT scaled, but the ResizableScrollBar doesn't know
// this. Here we re-calculate the requested scale knowing that the end item is not affected by scale.
scrollbar_start_width_ = current_bar_width;
scrollbar_start_value_ = bar->value();
scrollbar_start_scale_ = GetScale();
scrollbar_top_handle_ = top_handle;
}
int current_max = bar->maximum();
double proposed_max = static_cast<double>(current_max) * multiplier;
void TimeBasedWidget::ScrollBarResizeMoved(int movement)
{
ResizableScrollBar* bar = static_cast<ResizableScrollBar*>(sender());
proposed_max = proposed_max - (bar->width() * 0.5 / multiplier) + (bar->width() * 0.5);
double corrected_scale;
if (current_max == 0) {
corrected_scale = multiplier;
} else {
corrected_scale = (proposed_max / static_cast<double>(current_max));
// Negate movement for the top handle
if (scrollbar_top_handle_) {
movement = -movement;
}
SetScale(GetScale() * corrected_scale);
// The user wants the bar to be this size
int proposed_size = scrollbar_start_width_ + movement;
double ratio = double(scrollbar_start_width_) / double(proposed_size);
if (ratio > 0) {
SetScale(scrollbar_start_scale_ * ratio);
if (scrollbar_top_handle_) {
int viewable_area;
if (timeline_views_.isEmpty()) {
viewable_area = width();
} else {
viewable_area = timeline_views_.first()->width();
}
bar->setValue((scrollbar_start_value_ + viewable_area) * ratio - viewable_area);
} else {
bar->setValue(scrollbar_start_value_ * ratio);
}
}
}
void TimeBasedWidget::PageScrollToPlayhead()
@@ -492,7 +513,7 @@ void TimeBasedWidget::SetMarker()
bool ok;
QString marker_name;
if (Config::Current()["SetNameWithMarker"].toBool()) {
if (Config::Current()[QStringLiteral("SetNameWithMarker")].toBool()) {
marker_name = QInputDialog::getText(this, tr("Set Marker"), tr("Marker name:"), QLineEdit::Normal, QString(), &ok);
} else {
ok = true;
+8 -1
View File
@@ -205,10 +205,17 @@ private:
QVector<QObject*> wheel_passthrough_objects_;
int scrollbar_start_width_;
double scrollbar_start_value_;
double scrollbar_start_scale_;
bool scrollbar_top_handle_;
private slots:
void UpdateMaximumScroll();
void ScrollBarResized(const double& multiplier);
void ScrollBarResizeBegan(int current_bar_width, bool top_handle);
void ScrollBarResizeMoved(int new_bar_width);
/**
* @brief Slot to handle page scrolling of the playhead