From 3e6bc54f484ba089180e7953c18db43838f1ea6d Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 1 Jul 2019 17:53:52 -0700 Subject: [PATCH] more project management updates --- app/panel/project/project.cpp | 9 ++ app/panel/project/project.h | 3 + app/project/item/footage/footage.cpp | 116 +++++++++++++++--- app/project/item/footage/footage.h | 31 ++++- app/project/item/item.cpp | 10 ++ app/project/item/item.h | 5 + app/project/projectviewmodel.cpp | 2 + app/ui/icons/icons.cpp | 11 +- app/ui/icons/icons.h | 7 +- app/ui/style/css/olive-dark.css | 6 + app/ui/style/css/olive-light.css | 6 + app/ui/style/css/olive-mid.css | 6 + app/widget/projectexplorer/CMakeLists.txt | 2 + .../projectexplorer/projectexplorer.cpp | 23 +++- app/widget/projectexplorer/projectexplorer.h | 16 ++- .../projectexplorertreeview.cpp | 20 +++ .../projectexplorer/projectexplorertreeview.h | 25 ++++ 17 files changed, 277 insertions(+), 21 deletions(-) create mode 100644 app/widget/projectexplorer/projectexplorertreeview.cpp create mode 100644 app/widget/projectexplorer/projectexplorertreeview.h diff --git a/app/panel/project/project.cpp b/app/panel/project/project.cpp index 23d2cdfb2..03d1f1254 100644 --- a/app/panel/project/project.cpp +++ b/app/panel/project/project.cpp @@ -22,6 +22,7 @@ #include +#include "core.h" #include "widget/projecttoolbar/projecttoolbar.h" ProjectPanel::ProjectPanel(QWidget *parent) : @@ -41,6 +42,7 @@ ProjectPanel::ProjectPanel(QWidget *parent) : // Set up main explorer object explorer_ = new ProjectExplorer(this); layout->addWidget(explorer_); + connect(explorer_, SIGNAL(DoubleClickedItem(Item*)), this, SLOT(ItemDoubleClickSlot(Item*))); // Set toolbar's view to the explorer's view toolbar->SetView(explorer_->view_type()); @@ -85,3 +87,10 @@ void ProjectPanel::Retranslate() SetSubtitle(project()->name()); } } + +void ProjectPanel::ItemDoubleClickSlot(Item *item) +{ + if (item == nullptr) { + olive::core.StartImportFootage(); + } +} diff --git a/app/panel/project/project.h b/app/panel/project/project.h index 3de458076..b2954aceb 100644 --- a/app/panel/project/project.h +++ b/app/panel/project/project.h @@ -41,6 +41,9 @@ private: void Retranslate(); ProjectExplorer* explorer_; + +private slots: + void ItemDoubleClickSlot(Item* item); }; #endif // PROJECT_PANEL_H diff --git a/app/project/item/footage/footage.cpp b/app/project/item/footage/footage.cpp index 656fbd3ac..36ae6b9d2 100644 --- a/app/project/item/footage/footage.cpp +++ b/app/project/item/footage/footage.cpp @@ -20,11 +20,13 @@ #include "footage.h" +#include + #include "ui/icons/icons.h" -Footage::Footage() : - status_(kUnprobed) +Footage::Footage() { + Clear(); } Footage::~Footage() @@ -41,19 +43,9 @@ void Footage::set_status(const Footage::Status &status) { status_ = status; - switch (status_) { - case kUnprobed: - // FIXME Set a waiting icon - set_icon(QIcon()); - break; - case kReady: - // FIXME Set a ready icon - set_icon(QIcon()); - break; - case kInvalid: - set_icon(olive::icon::Error); - break; - } + UpdateIcon(); + + UpdateTooltip(); } void Footage::Clear() @@ -123,3 +115,97 @@ void Footage::ClearStreams() // Empty array streams_.clear(); } + +bool Footage::HasStreamsOfType(const Stream::Type type) +{ + // Return true if any streams are video streams + for (int i=0;itype() == type) { + return true; + } + } + + return false; +} + +void Footage::UpdateIcon() +{ + switch (status_) { + case kUnprobed: + // FIXME Set a waiting icon + set_icon(QIcon()); + break; + case kReady: + if (HasStreamsOfType(Stream::kVideo)) { + + // Prioritize the video icon + set_icon(olive::icon::Video); + + // FIXME: When image sources can be reliably picked up, use image icon instead + // Perhaps all image sources can be left to OpenImageIO meaning only video sources need to be here + + } else if (HasStreamsOfType(Stream::kAudio)) { + + // Otherwise assume it's audio only + set_icon(olive::icon::Audio); + + } else { + + // FIXME Icon/indicator for a media file with no video or audio streams? + // The footage should probably be deemed kInvalid in this state + + } + break; + case kInvalid: + set_icon(olive::icon::Error); + break; + } +} + +void Footage::UpdateTooltip() +{ + switch (status_) { + case kUnprobed: + set_tooltip(QCoreApplication::translate("Footage", "Waiting for probe")); + break; + case kReady: + { + QString tip = QCoreApplication::translate("Footage", "Filename: %1"); + + if (!streams_.isEmpty()) { + tip.append("\n"); + + for (int i=0;itype() == Stream::kVideo) { + VideoStream* vs = static_cast(s); + + tip.append( + QCoreApplication::translate("Footage", + "\nVideo %1: %2x%3").arg(QString::number(i), + QString::number(vs->width()), + QString::number(vs->height())) + ); + } else if (streams_.at(i)->type() == Stream::kAudio) { + AudioStream* as = static_cast(s); + + tip.append( + QCoreApplication::translate("Footage", + "\nAudio %1: %2 channels %3 Hz").arg(QString::number(i), + QString::number(as->channels()), + QString::number(as->sample_rate())) + ); + } + } + } + + set_tooltip(tip); + } + break; + case kInvalid: + set_tooltip(QCoreApplication::translate("Footage", "An error occurred probing this footage")); + break; + } +} diff --git a/app/project/item/footage/footage.h b/app/project/item/footage/footage.h index 7ad641e3d..0d2d86cfc 100644 --- a/app/project/item/footage/footage.h +++ b/app/project/item/footage/footage.h @@ -81,7 +81,11 @@ public: /** * @brief Set ready state * - * This should only be set by olive::ProbeMedia. Sets the ready state (see ready()). + * This should only be set by olive::ProbeMedia. Sets the Footage's current status to a member of enum + * Footage::Status. + * + * This function also runs UpdateIcon() and UpdateTooltip(). If you need to override the tooltip (e.g. for an error + * message), you must run set_tooltip() *after* running set_status(); */ void set_status(const Status& status); @@ -178,6 +182,31 @@ private: */ void ClearStreams(); + /** + * @brief Check if this footage has streams of a certain type + * + * @param type + * + * The stream type to check for + */ + bool HasStreamsOfType(const Stream::Type type); + + /** + * @brief Update the icon based on the Footage status + * + * For kUnprobed and kError an appropriate icon will be shown. For kReady, this function will determine what the + * dominant type of media in this Footage is (video/audio/image) and set the icon accordingly based on that. + */ + void UpdateIcon(); + + /** + * @brief Update the tooltip based on the Footage status + * + * For kUnprobed and kError, this sets an appropriate generic message. For kReady, this function will set + * basic information about the Footage in the tooltip (based on the results of a previous probe). + */ + void UpdateTooltip(); + /** * @brief Internal filename string */ diff --git a/app/project/item/item.cpp b/app/project/item/item.cpp index b841a3163..0d9c9d446 100644 --- a/app/project/item/item.cpp +++ b/app/project/item/item.cpp @@ -73,6 +73,16 @@ void Item::set_name(const QString &n) name_ = n; } +const QString &Item::tooltip() const +{ + return tooltip_; +} + +void Item::set_tooltip(const QString &t) +{ + tooltip_ = t; +} + const QIcon &Item::icon() { return icon_; diff --git a/app/project/item/item.h b/app/project/item/item.h index 94645085f..fff65e557 100644 --- a/app/project/item/item.h +++ b/app/project/item/item.h @@ -74,6 +74,9 @@ public: const QString& name() const; void set_name(const QString& n); + const QString& tooltip() const; + void set_tooltip(const QString& t); + const QIcon& icon(); void set_icon(const QIcon& icon); @@ -89,6 +92,8 @@ private: QIcon icon_; + QString tooltip_; + }; #endif // ITEM_H diff --git a/app/project/projectviewmodel.cpp b/app/project/projectviewmodel.cpp index 861a316bd..79c517e10 100644 --- a/app/project/projectviewmodel.cpp +++ b/app/project/projectviewmodel.cpp @@ -148,6 +148,8 @@ QVariant ProjectViewModel::data(const QModelIndex &index, int role) const return internal_item->icon(); } break; + case Qt::ToolTipRole: + return internal_item->tooltip(); } return QVariant(); diff --git a/app/ui/icons/icons.cpp b/app/ui/icons/icons.cpp index 8ae54caa9..e980430b9 100644 --- a/app/ui/icons/icons.cpp +++ b/app/ui/icons/icons.cpp @@ -52,13 +52,16 @@ QIcon olive::icon::ToolSlip; QIcon olive::icon::ToolSlide; QIcon olive::icon::ToolHand; QIcon olive::icon::ToolTransition; +QIcon olive::icon::Folder; +QIcon olive::icon::Video; +QIcon olive::icon::Audio; +QIcon olive::icon::Image; QIcon olive::icon::Snapping; QIcon olive::icon::ZoomIn; QIcon olive::icon::ZoomOut; QIcon olive::icon::Record; QIcon olive::icon::Add; QIcon olive::icon::Error; -QIcon olive::icon::Folder; void olive::icon::LoadAll() { @@ -87,13 +90,17 @@ void olive::icon::LoadAll() ToolHand = Create("hand"); ToolTransition = Create("transition-tool"); + Folder = Create("folder"); + Video = Create("videosource"); + Audio = Create("audiosource"); + Image = Create("imagesource"); + Snapping = Create("magnet"); ZoomIn = Create("zoomin"); ZoomOut = Create("zoomout"); Record = Create("record"); Add = Create("add-button"); Error = Create("error"); - Folder = Create("folder"); } QIcon olive::icon::Create(const QString &name) diff --git a/app/ui/icons/icons.h b/app/ui/icons/icons.h index 53b4a84ac..a73d17768 100644 --- a/app/ui/icons/icons.h +++ b/app/ui/icons/icons.h @@ -54,6 +54,12 @@ extern QIcon ToolSlide; extern QIcon ToolHand; extern QIcon ToolTransition; +// Project Icons +extern QIcon Folder; +extern QIcon Video; +extern QIcon Audio; +extern QIcon Image; + // Miscellaneous Icons extern QIcon Snapping; extern QIcon ZoomIn; @@ -61,7 +67,6 @@ extern QIcon ZoomOut; extern QIcon Record; extern QIcon Add; extern QIcon Error; -extern QIcon Folder; /** * @brief Create an icon object loaded from file diff --git a/app/ui/style/css/olive-dark.css b/app/ui/style/css/olive-dark.css index 16c4143a9..469f43912 100644 --- a/app/ui/style/css/olive-dark.css +++ b/app/ui/style/css/olive-dark.css @@ -85,3 +85,9 @@ QPushButton::checked { QMenu::separator { background: #353535; } + +/* ToolTips use dark */ +QToolTip { + background: #191919;; + color: #ffffff; +} diff --git a/app/ui/style/css/olive-light.css b/app/ui/style/css/olive-light.css index cc2dd3bc4..66d623a1b 100644 --- a/app/ui/style/css/olive-light.css +++ b/app/ui/style/css/olive-light.css @@ -85,3 +85,9 @@ QPushButton::checked { QMenu::separator { background: #d0d0d0; } + +/* ToolTips use dark */ +QToolTip { + background: #f0f0f0;; + color: #000000; +} diff --git a/app/ui/style/css/olive-mid.css b/app/ui/style/css/olive-mid.css index fba368a26..8340b2294 100644 --- a/app/ui/style/css/olive-mid.css +++ b/app/ui/style/css/olive-mid.css @@ -85,3 +85,9 @@ QPushButton::checked { QMenu::separator { background: #808080; } + +/* ToolTips use dark */ +QToolTip { + background: #c0c0c0;; + color: #000000; +} diff --git a/app/widget/projectexplorer/CMakeLists.txt b/app/widget/projectexplorer/CMakeLists.txt index f6a8d656e..aeb1d258a 100644 --- a/app/widget/projectexplorer/CMakeLists.txt +++ b/app/widget/projectexplorer/CMakeLists.txt @@ -18,5 +18,7 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/projectexplorer/projectexplorer.h widget/projectexplorer/projectexplorer.cpp + widget/projectexplorer/projectexplorertreeview.h + widget/projectexplorer/projectexplorertreeview.cpp PARENT_SCOPE ) diff --git a/app/widget/projectexplorer/projectexplorer.cpp b/app/widget/projectexplorer/projectexplorer.cpp index 9b76ec24f..e66b3e822 100644 --- a/app/widget/projectexplorer/projectexplorer.cpp +++ b/app/widget/projectexplorer/projectexplorer.cpp @@ -20,13 +20,16 @@ #include "projectexplorer.h" +#include + ProjectExplorer::ProjectExplorer(QWidget *parent) : QStackedWidget(parent), view_type_(olive::TreeView), model_(this) { - tree_view_ = new QTreeView(this); + tree_view_ = new ProjectExplorerTreeView(this); tree_view_->setModel(&model_); + connect(tree_view_, SIGNAL(DoubleClickedView(const QModelIndex&)), this, SLOT(DoubleClickViewSlot(const QModelIndex&))); addWidget(tree_view_); } @@ -40,6 +43,24 @@ void ProjectExplorer::set_view_type(olive::ProjectViewType type) view_type_ = type; } +void ProjectExplorer::DoubleClickViewSlot(const QModelIndex &index) +{ + if (index.isValid()) { + + // Retrieve source item from index + Item* i = static_cast(index.internalPointer()); + + // Emit a signal + emit DoubleClickedItem(i); + + } else { + + // Emit nullptr since no item was actually clicked on + emit DoubleClickedItem(nullptr); + + } +} + Project *ProjectExplorer::project() { return model_.project(); diff --git a/app/widget/projectexplorer/projectexplorer.h b/app/widget/projectexplorer/projectexplorer.h index 93fe6747d..76c8c52c2 100644 --- a/app/widget/projectexplorer/projectexplorer.h +++ b/app/widget/projectexplorer/projectexplorer.h @@ -27,6 +27,7 @@ #include "project/project.h" #include "project/projectviewmodel.h" #include "project/projectviewtype.h" +#include "widget/projectexplorer/projectexplorertreeview.h" /** * @brief The ProjectExplorer class @@ -52,12 +53,25 @@ public: public slots: void set_view_type(olive::ProjectViewType type); +signals: + /** + * @brief Emitted when an Item is double clicked + * + * @param item + * + * The Item that was double clicked, or nullptr if empty area was double clicked + */ + void DoubleClickedItem(Item* item); + private: - QTreeView* tree_view_; + ProjectExplorerTreeView* tree_view_; olive::ProjectViewType view_type_; ProjectViewModel model_; + +private slots: + void DoubleClickViewSlot(const QModelIndex& index); }; #endif // PROJECTEXPLORER_H diff --git a/app/widget/projectexplorer/projectexplorertreeview.cpp b/app/widget/projectexplorer/projectexplorertreeview.cpp new file mode 100644 index 000000000..4bcd96f80 --- /dev/null +++ b/app/widget/projectexplorer/projectexplorertreeview.cpp @@ -0,0 +1,20 @@ +#include "projectexplorertreeview.h" + +#include + +ProjectExplorerTreeView::ProjectExplorerTreeView(QWidget *parent) : + QTreeView(parent) +{ +} + +void ProjectExplorerTreeView::mouseDoubleClickEvent(QMouseEvent *event) +{ + // Perform default double click functions + QTreeView::mouseDoubleClickEvent(event); + + // Get the index at whatever position was double clicked + QModelIndex index = indexAt(event->pos()); + + // Emit the signal with this index + emit DoubleClickedView(index); +} diff --git a/app/widget/projectexplorer/projectexplorertreeview.h b/app/widget/projectexplorer/projectexplorertreeview.h new file mode 100644 index 000000000..f0de12eb7 --- /dev/null +++ b/app/widget/projectexplorer/projectexplorertreeview.h @@ -0,0 +1,25 @@ +#ifndef PROJECTEXPLORERTREEVIEW_H +#define PROJECTEXPLORERTREEVIEW_H + +#include + +/** + * @brief The ProjectExplorerTreeView class + * + * A fairly simple subclass of QTreeView that provides a double clicked signal whether the index is valid or not + * (QAbstractItemView has a doubleClicked() signal but it's only emitted with a valid index). + */ +class ProjectExplorerTreeView : public QTreeView +{ + Q_OBJECT +public: + ProjectExplorerTreeView(QWidget* parent); + +protected: + virtual void mouseDoubleClickEvent(QMouseEvent *event) override; + +signals: + void DoubleClickedView(const QModelIndex& index); +}; + +#endif // PROJECTEXPLORERTREEVIEW_H