From 50f4e8767d39bba962e2a4353102633885a776fc Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 8 Dec 2019 05:13:43 +1100 Subject: [PATCH] wrangled QWidgets to allow for resizable tracks with track headers --- .../timelinewidget/timelineandtrackview.cpp | 2 +- .../timelinewidget/trackview/CMakeLists.txt | 4 + .../timelinewidget/trackview/trackview.cpp | 57 ++++++--- .../timelinewidget/trackview/trackview.h | 24 +++- .../trackview/trackviewitem.cpp | 44 +++++++ .../timelinewidget/trackview/trackviewitem.h | 28 +++++ .../trackview/trackviewsplitter.cpp | 109 ++++++++++++++++++ .../trackview/trackviewsplitter.h | 39 +++++++ 8 files changed, 286 insertions(+), 21 deletions(-) create mode 100644 app/widget/timelinewidget/trackview/trackviewitem.cpp create mode 100644 app/widget/timelinewidget/trackview/trackviewitem.h create mode 100644 app/widget/timelinewidget/trackview/trackviewsplitter.cpp create mode 100644 app/widget/timelinewidget/trackview/trackviewsplitter.h diff --git a/app/widget/timelinewidget/timelineandtrackview.cpp b/app/widget/timelinewidget/timelineandtrackview.cpp index 7995d007e..33d43556f 100644 --- a/app/widget/timelinewidget/timelineandtrackview.cpp +++ b/app/widget/timelinewidget/timelineandtrackview.cpp @@ -13,7 +13,7 @@ TimelineAndTrackView::TimelineAndTrackView(const TrackType &type, Qt::Alignment splitter_->setChildrenCollapsible(false); layout->addWidget(splitter_); - track_view_ = new TrackView(); + track_view_ = new TrackView(vertical_alignment); splitter_->addWidget(track_view_); view_ = new TimelineView(type, vertical_alignment); diff --git a/app/widget/timelinewidget/trackview/CMakeLists.txt b/app/widget/timelinewidget/trackview/CMakeLists.txt index bbd5bc605..a569b27c9 100644 --- a/app/widget/timelinewidget/trackview/CMakeLists.txt +++ b/app/widget/timelinewidget/trackview/CMakeLists.txt @@ -18,5 +18,9 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/timelinewidget/trackview/trackview.h widget/timelinewidget/trackview/trackview.cpp + widget/timelinewidget/trackview/trackviewitem.h + widget/timelinewidget/trackview/trackviewitem.cpp + widget/timelinewidget/trackview/trackviewsplitter.h + widget/timelinewidget/trackview/trackviewsplitter.cpp PARENT_SCOPE ) diff --git a/app/widget/timelinewidget/trackview/trackview.cpp b/app/widget/timelinewidget/trackview/trackview.cpp index 712360b55..fed6d7526 100644 --- a/app/widget/timelinewidget/trackview/trackview.cpp +++ b/app/widget/timelinewidget/trackview/trackview.cpp @@ -1,29 +1,52 @@ #include "trackview.h" +#include +#include +#include #include #include -TrackView::TrackView(QWidget *parent) : - QWidget(parent) +#include "trackviewitem.h" + +TrackView::TrackView(Qt::Alignment vertical_alignment, QWidget *parent) : + QScrollArea(parent), + alignment_(vertical_alignment) { - QVBoxLayout* layout = new QVBoxLayout(this); - layout->setSpacing(0); + QWidget* central = new QWidget(); + setWidget(central); + setWidgetResizable(true); + + QVBoxLayout* layout = new QVBoxLayout(central); layout->setMargin(0); + layout->setSpacing(0); - QSplitter* splitter = new QSplitter(Qt::Vertical); - splitter->setChildrenCollapsible(false); - splitter->setHandleWidth(1); - layout->addWidget(splitter); + if (alignment_ == Qt::AlignBottom) { + layout->addStretch(); - QWidget* test1 = new QWidget(); - test1->setStyleSheet("background: red;"); - splitter->addWidget(test1); + connect(verticalScrollBar(), SIGNAL(rangeChanged(int, int)), this, SLOT(ScrollbarRangeChanged(int, int))); + last_scrollbar_max_ = verticalScrollBar()->maximum(); + } - QWidget* test3 = new QWidget(); - test3->setStyleSheet("background: yellow;"); - splitter->addWidget(test3); + splitter_ = new TrackViewSplitter(alignment_); + splitter_->setChildrenCollapsible(false); + layout->addWidget(splitter_); +} - QWidget* test2 = new QWidget(); - test2->setStyleSheet("background: blue;"); - splitter->addWidget(test2); +void TrackView::resizeEvent(QResizeEvent *event) +{ + QScrollArea::resizeEvent(event); + + //splitter_->setFixedWidth(viewport()->width()); +} + +void TrackView::ScrollbarRangeChanged(int, int max) +{ + if (max != last_scrollbar_max_) { + int ba_val = last_scrollbar_max_ - verticalScrollBar()->value(); + int new_val = max - ba_val; + + verticalScrollBar()->setValue(new_val); + + last_scrollbar_max_ = max; + } } diff --git a/app/widget/timelinewidget/trackview/trackview.h b/app/widget/timelinewidget/trackview/trackview.h index 6277a4c2b..e6309ccc9 100644 --- a/app/widget/timelinewidget/trackview/trackview.h +++ b/app/widget/timelinewidget/trackview/trackview.h @@ -1,14 +1,32 @@ #ifndef TRACKVIEW_H #define TRACKVIEW_H -#include +#include +#include -class TrackView : public QWidget +#include "trackviewsplitter.h" + +class TrackView : public QScrollArea { + Q_OBJECT public: - TrackView(QWidget* parent = nullptr); + TrackView(Qt::Alignment vertical_alignment = Qt::AlignTop, + QWidget* parent = nullptr); + +protected: + virtual void resizeEvent(QResizeEvent* event) override; private: + TrackViewSplitter* splitter_; + + Qt::Alignment alignment_; + + int last_scrollbar_max_; + + QWidget* top_spacer_; + +private slots: + void ScrollbarRangeChanged(int min, int max); }; diff --git a/app/widget/timelinewidget/trackview/trackviewitem.cpp b/app/widget/timelinewidget/trackview/trackviewitem.cpp new file mode 100644 index 000000000..e61b79201 --- /dev/null +++ b/app/widget/timelinewidget/trackview/trackviewitem.cpp @@ -0,0 +1,44 @@ +#include "trackviewitem.h" + +#include +#include +#include +#include +#include + +TrackViewItem::TrackViewItem(Qt::Alignment alignment, QWidget *parent) : + QWidget(parent), + alignment_(alignment) +{ + QHBoxLayout* layout = new QHBoxLayout(this); + layout->setSpacing(0); + layout->setMargin(0); + + label_ = new QLabel(tr("Track")); + layout->addWidget(label_); + + mute_button_ = CreateMSLButton(tr("M"), Qt::red); + layout->addWidget(mute_button_); + + solo_button_ = CreateMSLButton(tr("S"), Qt::yellow); + layout->addWidget(solo_button_); + + lock_button_ = CreateMSLButton(tr("L"), Qt::gray); + layout->addWidget(lock_button_); + + setMinimumHeight(mute_button_->height()); +} + +QPushButton *TrackViewItem::CreateMSLButton(const QString& text, const QColor& checked_color) const +{ + QPushButton* button = new QPushButton(text); + button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + button->setCheckable(true); + button->setStyleSheet(QStringLiteral("QPushButton::checked { background: %1; }").arg(checked_color.name())); + + int size = button->sizeHint().height(); + size = qRound(size * 0.75); + button->setFixedSize(size, size); + + return button; +} diff --git a/app/widget/timelinewidget/trackview/trackviewitem.h b/app/widget/timelinewidget/trackview/trackviewitem.h new file mode 100644 index 000000000..2d5b6a61f --- /dev/null +++ b/app/widget/timelinewidget/trackview/trackviewitem.h @@ -0,0 +1,28 @@ +#ifndef TRACKVIEWITEM_H +#define TRACKVIEWITEM_H + +#include +#include +#include + +class TrackViewItem : public QWidget +{ + Q_OBJECT +public: + TrackViewItem(Qt::Alignment alignment = Qt::AlignTop, + QWidget* parent = nullptr); + +private: + QPushButton* CreateMSLButton(const QString &text, const QColor &checked_color) const; + + Qt::Alignment alignment_; + + QLabel* label_; + + QPushButton* mute_button_; + QPushButton* solo_button_; + QPushButton* lock_button_; + +}; + +#endif // TRACKVIEWITEM_H diff --git a/app/widget/timelinewidget/trackview/trackviewsplitter.cpp b/app/widget/timelinewidget/trackview/trackviewsplitter.cpp new file mode 100644 index 000000000..1d939c580 --- /dev/null +++ b/app/widget/timelinewidget/trackview/trackviewsplitter.cpp @@ -0,0 +1,109 @@ +#include "trackviewsplitter.h" + +#include +#include + +#include "trackviewitem.h" + +TrackViewSplitter::TrackViewSplitter(Qt::Alignment vertical_alignment, QWidget* parent) : + QSplitter(Qt::Vertical, parent), + alignment_(vertical_alignment) +{ + setHandleWidth(1); + + int initial_height = 0; + + if (alignment_ == Qt::AlignBottom) { + // Add empty spacer so we get a splitter handle after the last element + addWidget(new QWidget()); + } + + for (int i=0;i<3;i++) { + TrackViewItem* w = new TrackViewItem(); + addWidget(w); + + initial_height += w->sizeHint().height() + handleWidth(); + } + + if (alignment_ == Qt::AlignTop) { + // Add empty spacer so we get a splitter handle after the last element + addWidget(new QWidget()); + } + + setFixedHeight(initial_height); +} + +void TrackViewSplitter::HandleReceiver(TrackViewSplitterHandle *h, int diff) +{ + int ele_id = -1; + + for (int i=0;i element_sizes = sizes(); + + int old_ele_sz = element_sizes.at(ele_id); + + // Transform element size by diff + int new_ele_sz = old_ele_sz + diff; + + // Validate it with the widget's minimum size + new_ele_sz = qMax(new_ele_sz, widget(ele_id)->minimumHeight()); + + // Correct diff + diff = new_ele_sz - old_ele_sz; + + // Set new size on element + element_sizes.replace(ele_id, new_ele_sz); + setSizes(element_sizes); + + // Increase height by the difference + setFixedHeight(height() + diff); +} + +QSplitterHandle *TrackViewSplitter::createHandle() +{ + return new TrackViewSplitterHandle(orientation(), this); +} + +TrackViewSplitterHandle::TrackViewSplitterHandle(Qt::Orientation orientation, QSplitter *parent) : + QSplitterHandle(orientation, parent), + dragging_(false) +{ +} + +void TrackViewSplitterHandle::mousePressEvent(QMouseEvent *) +{ +} + +void TrackViewSplitterHandle::mouseMoveEvent(QMouseEvent *) +{ + if (dragging_) { + static_cast(parent())->HandleReceiver(this, QCursor::pos().y() - drag_y_); + } + + drag_y_ = QCursor::pos().y(); + dragging_ = true; +} + +void TrackViewSplitterHandle::mouseReleaseEvent(QMouseEvent *) +{ + dragging_ = false; +} + +void TrackViewSplitterHandle::paintEvent(QPaintEvent *) +{ + QPainter p(this); + p.fillRect(rect(), palette().base()); +} diff --git a/app/widget/timelinewidget/trackview/trackviewsplitter.h b/app/widget/timelinewidget/trackview/trackviewsplitter.h new file mode 100644 index 000000000..803d88bda --- /dev/null +++ b/app/widget/timelinewidget/trackview/trackviewsplitter.h @@ -0,0 +1,39 @@ +#ifndef TRACKVIEWSPLITTER_H +#define TRACKVIEWSPLITTER_H + +#include + +class TrackViewSplitterHandle : public QSplitterHandle +{ + Q_OBJECT +public: + TrackViewSplitterHandle(Qt::Orientation orientation, QSplitter *parent); + +protected: + virtual void mousePressEvent(QMouseEvent *e) override; + virtual void mouseMoveEvent(QMouseEvent *e) override; + virtual void mouseReleaseEvent(QMouseEvent *e) override; + + virtual void paintEvent(QPaintEvent *e) override; + +private: + int drag_y_; + + bool dragging_; +}; + +class TrackViewSplitter : public QSplitter +{ +public: + TrackViewSplitter(Qt::Alignment vertical_alignment, QWidget* parent = nullptr); + + void HandleReceiver(TrackViewSplitterHandle* h, int diff); + +protected: + virtual QSplitterHandle *createHandle() override; + +private: + Qt::Alignment alignment_; +}; + +#endif // TRACKVIEWSPLITTER_H