wrangled QWidgets to allow for resizable tracks with track headers

This commit is contained in:
itsmattkc
2019-12-08 05:13:43 +11:00
parent dd8d1e84b0
commit 50f4e8767d
8 changed files with 286 additions and 21 deletions
@@ -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);
@@ -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
)
@@ -1,29 +1,52 @@
#include "trackview.h"
#include <QDebug>
#include <QResizeEvent>
#include <QScrollBar>
#include <QSplitter>
#include <QVBoxLayout>
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;
}
}
@@ -1,14 +1,32 @@
#ifndef TRACKVIEW_H
#define TRACKVIEW_H
#include <QWidget>
#include <QScrollArea>
#include <QSplitter>
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);
};
@@ -0,0 +1,44 @@
#include "trackviewitem.h"
#include <QDebug>
#include <QHBoxLayout>
#include <QMouseEvent>
#include <QPainter>
#include <QtMath>
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;
}
@@ -0,0 +1,28 @@
#ifndef TRACKVIEWITEM_H
#define TRACKVIEWITEM_H
#include <QLabel>
#include <QPushButton>
#include <QWidget>
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
@@ -0,0 +1,109 @@
#include "trackviewsplitter.h"
#include <QDebug>
#include <QPainter>
#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<count();i++) {
if (handle(i) == h) {
ele_id = i;
break;
}
}
// The handle index is actually always one above the element index
if (alignment_ == Qt::AlignTop) {
ele_id--;
} else if (alignment_ == Qt::AlignBottom) {
diff = -diff;
}
QList<int> 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<TrackViewSplitter*>(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());
}
@@ -0,0 +1,39 @@
#ifndef TRACKVIEWSPLITTER_H
#define TRACKVIEWSPLITTER_H
#include <QSplitter>
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