diff --git a/olive.pro b/olive.pro index 8ce6d9483..0299913c0 100644 --- a/olive.pro +++ b/olive.pro @@ -132,7 +132,8 @@ SOURCES += \ effects/internal/frei0reffect.cpp \ project/effectloaders.cpp \ io/crossplatformlib.cpp \ - effects/internal/vsthost.cpp + effects/internal/vsthost.cpp \ + ui/flowlayout.cpp HEADERS += \ mainwindow.h \ @@ -232,7 +233,8 @@ HEADERS += \ effects/internal/frei0reffect.h \ project/effectloaders.h \ io/crossplatformlib.h \ - effects/internal/vsthost.h + effects/internal/vsthost.h \ + ui/flowlayout.h FORMS += diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 939bc649c..688802df4 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -21,6 +21,7 @@ #include "ui/timelineheader.h" #include "ui/resizablescrollbar.h" #include "ui/audiomonitor.h" +#include "ui/flowlayout.h" #include "mainwindow.h" #include "debug.h" @@ -490,7 +491,21 @@ void Timeline::select_from_playhead() { } void Timeline::resizeEvent(QResizeEvent *) { - if (sequence != nullptr) set_sb_max(); + // adjust maximum scrollbar + if (sequence != nullptr) set_sb_max(); + + + // resize tool button widget to its contents + QList tool_button_children = tool_button_widget->findChildren(); + int total_client_height = 0; + int layout_spacing = tool_button_widget->layout()->spacing(); + for (int i=0;iheight() + layout_spacing; + } + int comp_height = tool_button_widget->height(); + qDebug() << total_client_height << comp_height << layout_spacing; + int cols = qCeil(double(total_client_height)/double(comp_height)); + tool_button_widget->setFixedWidth((tool_button_children.at(0)->width())*cols + layout_spacing*(cols+1)); } void Timeline::delete_in_out(bool ripple) { @@ -1596,14 +1611,15 @@ void Timeline::setup_ui() { horizontalLayout->setSpacing(0); horizontalLayout->setContentsMargins(0, 0, 0, 0); - QWidget* tool_buttons = new QWidget(dockWidgetContents); - tool_buttons->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum); + tool_button_widget = new QWidget(dockWidgetContents); + tool_button_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - QVBoxLayout* tool_buttons_layout = new QVBoxLayout(tool_buttons); + FlowLayout* tool_buttons_layout = new FlowLayout(tool_button_widget); +// tool_buttons_layout->setSizeConstraint(QLayout::SetNoConstraint); tool_buttons_layout->setSpacing(4); tool_buttons_layout->setContentsMargins(0, 0, 0, 0); - toolArrowButton = new QPushButton(tool_buttons); + toolArrowButton = new QPushButton(tool_button_widget); QIcon arrow_icon; arrow_icon.addFile(QStringLiteral(":/icons/arrow.png"), QSize(), QIcon::Normal, QIcon::Off); arrow_icon.addFile(QStringLiteral(":/icons/arrow-disabled.png"), QSize(), QIcon::Disabled, QIcon::Off); @@ -1612,9 +1628,9 @@ void Timeline::setup_ui() { toolArrowButton->setToolTip(tr("Pointer Tool") + " (V)"); toolArrowButton->setProperty("tool", TIMELINE_TOOL_POINTER); connect(toolArrowButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); - tool_buttons_layout->addWidget(toolArrowButton); + tool_buttons_layout->addWidget(toolArrowButton); - toolEditButton = new QPushButton(tool_buttons); + toolEditButton = new QPushButton(tool_button_widget); QIcon icon1; icon1.addFile(QStringLiteral(":/icons/beam.png"), QSize(), QIcon::Normal, QIcon::Off); icon1.addFile(QStringLiteral(":/icons/beam-disabled.png"), QSize(), QIcon::Disabled, QIcon::Off); @@ -1625,7 +1641,7 @@ void Timeline::setup_ui() { connect(toolEditButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); tool_buttons_layout->addWidget(toolEditButton); - toolRippleButton = new QPushButton(tool_buttons); + toolRippleButton = new QPushButton(tool_button_widget); QIcon icon2; icon2.addFile(QStringLiteral(":/icons/ripple.png"), QSize(), QIcon::Normal, QIcon::Off); icon2.addFile(QStringLiteral(":/icons/ripple-disabled.png"), QSize(), QIcon::Disabled, QIcon::Off); @@ -1636,7 +1652,7 @@ void Timeline::setup_ui() { connect(toolRippleButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); tool_buttons_layout->addWidget(toolRippleButton); - toolRazorButton = new QPushButton(tool_buttons); + toolRazorButton = new QPushButton(tool_button_widget); QIcon icon4; icon4.addFile(QStringLiteral(":/icons/razor.png"), QSize(), QIcon::Normal, QIcon::Off); icon4.addFile(QStringLiteral(":/icons/razor-disabled.png"), QSize(), QIcon::Disabled, QIcon::Off); @@ -1647,7 +1663,7 @@ void Timeline::setup_ui() { connect(toolRazorButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); tool_buttons_layout->addWidget(toolRazorButton); - toolSlipButton = new QPushButton(tool_buttons); + toolSlipButton = new QPushButton(tool_button_widget); QIcon icon5; icon5.addFile(QStringLiteral(":/icons/slip.png"), QSize(), QIcon::Normal, QIcon::On); icon5.addFile(QStringLiteral(":/icons/slip-disabled.png"), QSize(), QIcon::Disabled, QIcon::On); @@ -1658,7 +1674,7 @@ void Timeline::setup_ui() { connect(toolSlipButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); tool_buttons_layout->addWidget(toolSlipButton); - toolSlideButton = new QPushButton(tool_buttons); + toolSlideButton = new QPushButton(tool_button_widget); QIcon icon6; icon6.addFile(QStringLiteral(":/icons/slide.png"), QSize(), QIcon::Normal, QIcon::On); icon6.addFile(QStringLiteral(":/icons/slide-disabled.png"), QSize(), QIcon::Disabled, QIcon::On); @@ -1669,7 +1685,7 @@ void Timeline::setup_ui() { connect(toolSlideButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); tool_buttons_layout->addWidget(toolSlideButton); - toolHandButton = new QPushButton(tool_buttons); + toolHandButton = new QPushButton(tool_button_widget); QIcon icon7; icon7.addFile(QStringLiteral(":/icons/hand.png"), QSize(), QIcon::Normal, QIcon::On); icon7.addFile(QStringLiteral(":/icons/hand-disabled.png"), QSize(), QIcon::Disabled, QIcon::On); @@ -1680,7 +1696,7 @@ void Timeline::setup_ui() { connect(toolHandButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); tool_buttons_layout->addWidget(toolHandButton); - toolTransitionButton = new QPushButton(tool_buttons); + toolTransitionButton = new QPushButton(tool_button_widget); QIcon icon8; icon8.addFile(QStringLiteral(":/icons/transition-tool.png"), QSize(), QIcon::Normal, QIcon::On); icon8.addFile(QStringLiteral(":/icons/transition-tool-disabled.png"), QSize(), QIcon::Disabled, QIcon::On); @@ -1690,7 +1706,7 @@ void Timeline::setup_ui() { connect(toolTransitionButton, SIGNAL(clicked(bool)), this, SLOT(transition_tool_click())); tool_buttons_layout->addWidget(toolTransitionButton); - snappingButton = new QPushButton(tool_buttons); + snappingButton = new QPushButton(tool_button_widget); QIcon icon9; icon9.addFile(QStringLiteral(":/icons/magnet.png"), QSize(), QIcon::Normal, QIcon::On); icon9.addFile(QStringLiteral(":/icons/magnet-disabled.png"), QSize(), QIcon::Disabled, QIcon::On); @@ -1701,7 +1717,7 @@ void Timeline::setup_ui() { connect(snappingButton, SIGNAL(toggled(bool)), this, SLOT(snapping_clicked(bool))); tool_buttons_layout->addWidget(snappingButton); - zoomInButton = new QPushButton(tool_buttons); + zoomInButton = new QPushButton(tool_button_widget); QIcon icon10; icon10.addFile(QStringLiteral(":/icons/zoomin.png"), QSize(), QIcon::Normal, QIcon::On); icon10.addFile(QStringLiteral(":/icons/zoomin-disabled.png"), QSize(), QIcon::Disabled, QIcon::On); @@ -1710,7 +1726,7 @@ void Timeline::setup_ui() { connect(zoomInButton, SIGNAL(clicked(bool)), this, SLOT(zoom_in())); tool_buttons_layout->addWidget(zoomInButton); - zoomOutButton = new QPushButton(tool_buttons); + zoomOutButton = new QPushButton(tool_button_widget); QIcon icon11; icon11.addFile(QStringLiteral(":/icons/zoomout.png"), QSize(), QIcon::Normal, QIcon::On); icon11.addFile(QStringLiteral(":/icons/zoomout-disabled.png"), QSize(), QIcon::Disabled, QIcon::On); @@ -1719,7 +1735,7 @@ void Timeline::setup_ui() { connect(zoomOutButton, SIGNAL(clicked(bool)), this, SLOT(zoom_out())); tool_buttons_layout->addWidget(zoomOutButton); - recordButton = new QPushButton(tool_buttons); + recordButton = new QPushButton(tool_button_widget); QIcon icon12; icon12.addFile(QStringLiteral(":/icons/record.png"), QSize(), QIcon::Normal, QIcon::On); icon12.addFile(QStringLiteral(":/icons/record-disabled.png"), QSize(), QIcon::Disabled, QIcon::On); @@ -1729,18 +1745,16 @@ void Timeline::setup_ui() { tool_buttons_layout->addWidget(recordButton); - addButton = new QPushButton(tool_buttons); + addButton = new QPushButton(tool_button_widget); QIcon icon13; icon13.addFile(QStringLiteral(":/icons/add-button.png"), QSize(), QIcon::Normal, QIcon::On); icon13.addFile(QStringLiteral(":/icons/add-button-disabled.png"), QSize(), QIcon::Disabled, QIcon::On); addButton->setIcon(icon13); addButton->setToolTip(tr("Add title, solid, bars, etc.")); connect(addButton, SIGNAL(clicked()), this, SLOT(add_btn_click())); - tool_buttons_layout->addWidget(addButton); + tool_buttons_layout->addWidget(addButton); - tool_buttons_layout->addStretch(); - - horizontalLayout->addWidget(tool_buttons); + horizontalLayout->addWidget(tool_button_widget); timeline_area = new QWidget(dockWidgetContents); QSizePolicy sizePolicy2(QSizePolicy::Minimum, QSizePolicy::Minimum); diff --git a/panels/timeline.h b/panels/timeline.h index 2254bfff9..f126dc50f 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -249,6 +249,7 @@ private: QPushButton* zoomOutButton; QPushButton* recordButton; QPushButton* addButton; + QWidget* tool_button_widget; }; #endif // TIMELINE_H diff --git a/ui/flowlayout.cpp b/ui/flowlayout.cpp new file mode 100644 index 000000000..243fd5099 --- /dev/null +++ b/ui/flowlayout.cpp @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +#include "flowlayout.h" +FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) + : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing) +{ + setContentsMargins(margin, margin, margin, margin); +} + +FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing) + : m_hSpace(hSpacing), m_vSpace(vSpacing) +{ + setContentsMargins(margin, margin, margin, margin); +} + +FlowLayout::~FlowLayout() +{ + QLayoutItem *item; + while ((item = takeAt(0))) + delete item; +} + +void FlowLayout::addItem(QLayoutItem *item) +{ + itemList.append(item); +} + +int FlowLayout::horizontalSpacing() const +{ + if (m_hSpace >= 0) { + return m_hSpace; + } else { + return smartSpacing(QStyle::PM_LayoutHorizontalSpacing); + } +} + +int FlowLayout::verticalSpacing() const +{ + if (m_vSpace >= 0) { + return m_vSpace; + } else { + return smartSpacing(QStyle::PM_LayoutVerticalSpacing); + } +} + +int FlowLayout::count() const +{ + return itemList.size(); +} + +QLayoutItem *FlowLayout::itemAt(int index) const +{ + return itemList.value(index); +} + +QLayoutItem *FlowLayout::takeAt(int index) +{ + if (index >= 0 && index < itemList.size()) + return itemList.takeAt(index); + else + return 0; +} + +Qt::Orientations FlowLayout::expandingDirections() const +{ + return 0; +} + +bool FlowLayout::hasHeightForWidth() const +{ + return true; +} + +int FlowLayout::heightForWidth(int width) const +{ + int height = doLayout(QRect(0, 0, width, 0), true); + return height; +} + +void FlowLayout::setGeometry(const QRect &rect) +{ + QLayout::setGeometry(rect); + doLayout(rect, false); +} + +QSize FlowLayout::sizeHint() const +{ + return minimumSize(); +} + +QSize FlowLayout::minimumSize() const +{ + QSize size; + QLayoutItem *item; + foreach (item, itemList) + size = size.expandedTo(item->minimumSize()); + + size += QSize(2*margin(), 2*margin()); + return size; +} + +int FlowLayout::doLayout(const QRect &rect, bool testOnly) const +{ + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); + int x = effectiveRect.x(); + int y = effectiveRect.y(); + int lineHeight = 0; + + QLayoutItem *item; + foreach (item, itemList) { + QWidget *wid = item->widget(); + int spaceX = horizontalSpacing(); + if (spaceX == -1) + spaceX = wid->style()->layoutSpacing( + QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); + int spaceY = verticalSpacing(); + if (spaceY == -1) + spaceY = wid->style()->layoutSpacing( + QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); + int nextX = x + item->sizeHint().width() + spaceX; + if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) { + x = effectiveRect.x(); + y = y + lineHeight + spaceY; + nextX = x + item->sizeHint().width() + spaceX; + lineHeight = 0; + } + + if (!testOnly) + item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); + + x = nextX; + lineHeight = qMax(lineHeight, item->sizeHint().height()); + } + return y + lineHeight - rect.y() + bottom; +} +int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const +{ + QObject *parent = this->parent(); + if (!parent) { + return -1; + } else if (parent->isWidgetType()) { + QWidget *pw = static_cast(parent); + return pw->style()->pixelMetric(pm, 0, pw); + } else { + return static_cast(parent)->spacing(); + } +} diff --git a/ui/flowlayout.h b/ui/flowlayout.h new file mode 100644 index 000000000..5531318a1 --- /dev/null +++ b/ui/flowlayout.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef FLOWLAYOUT_H +#define FLOWLAYOUT_H + +#include +#include +#include +class FlowLayout : public QLayout +{ +public: + explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1); + explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); + ~FlowLayout(); + + void addItem(QLayoutItem *item) override; + int horizontalSpacing() const; + int verticalSpacing() const; + Qt::Orientations expandingDirections() const override; + bool hasHeightForWidth() const override; + int heightForWidth(int) const override; + int count() const override; + QLayoutItem *itemAt(int index) const override; + QSize minimumSize() const override; + void setGeometry(const QRect &rect) override; + QSize sizeHint() const override; + QLayoutItem *takeAt(int index) override; + +private: + int doLayout(const QRect &rect, bool testOnly) const; + int smartSpacing(QStyle::PixelMetric pm) const; + + QList itemList; + int m_hSpace; + int m_vSpace; +}; + +#endif // FLOWLAYOUT_H