From f2013a6f3d7d8e3d4297414800fb8ff18732e081 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 8 Dec 2019 00:11:47 +1100 Subject: [PATCH] created time slider UI widget Based on the integer slider, this can be used to interactively control time. --- .../nodeparamviewwidgetbridge.cpp | 2 +- app/widget/slider/CMakeLists.txt | 2 + app/widget/slider/floatslider.cpp | 11 ++++ app/widget/slider/floatslider.h | 5 ++ app/widget/slider/integerslider.cpp | 25 +++++++- app/widget/slider/integerslider.h | 11 ++-- app/widget/slider/sliderbase.cpp | 60 +++++++------------ app/widget/slider/sliderbase.h | 8 +++ app/widget/slider/stringslider.cpp | 6 ++ app/widget/slider/stringslider.h | 3 + app/widget/slider/timeslider.cpp | 31 ++++++++++ app/widget/slider/timeslider.h | 24 ++++++++ 12 files changed, 140 insertions(+), 48 deletions(-) create mode 100644 app/widget/slider/timeslider.cpp create mode 100644 app/widget/slider/timeslider.h diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index 311a4b5ed..99bd91444 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -58,7 +58,7 @@ void NodeParamViewWidgetBridge::CreateWidgets() { IntegerSlider* slider = new IntegerSlider(); widgets_.append(slider); - connect(slider, SIGNAL(ValueChanged(int)), this, SLOT(WidgetCallback())); + connect(slider, SIGNAL(ValueChanged(int64_t)), this, SLOT(WidgetCallback())); break; } case NodeParam::kFloat: diff --git a/app/widget/slider/CMakeLists.txt b/app/widget/slider/CMakeLists.txt index b58325bb3..37bd57931 100644 --- a/app/widget/slider/CMakeLists.txt +++ b/app/widget/slider/CMakeLists.txt @@ -28,5 +28,7 @@ set(OLIVE_SOURCES widget/slider/sliderlineedit.cpp widget/slider/stringslider.h widget/slider/stringslider.cpp + widget/slider/timeslider.h + widget/slider/timeslider.cpp PARENT_SCOPE ) diff --git a/app/widget/slider/floatslider.cpp b/app/widget/slider/floatslider.cpp index f351da7d5..7d1dad694 100644 --- a/app/widget/slider/floatslider.cpp +++ b/app/widget/slider/floatslider.cpp @@ -53,6 +53,17 @@ void FloatSlider::SetDecimalPlaces(int i) UpdateLabel(Value()); } +QString FloatSlider::ValueToString(const QVariant &v) +{ + return QString::number(v.toDouble(), 'f', decimal_places_); +} + +QVariant FloatSlider::StringToValue(const QString &s, bool *ok) +{ + // Allow both floats and integers for either modes + return s.toDouble(ok); +} + void FloatSlider::ConvertValue(QVariant v) { emit ValueChanged(v.toDouble()); diff --git a/app/widget/slider/floatslider.h b/app/widget/slider/floatslider.h index 1f9c4b6f2..337c62310 100644 --- a/app/widget/slider/floatslider.h +++ b/app/widget/slider/floatslider.h @@ -39,6 +39,11 @@ public: void SetDecimalPlaces(int i); +protected: + virtual QString ValueToString(const QVariant& v) override; + + virtual QVariant StringToValue(const QString& s, bool* ok) override; + signals: void ValueChanged(double); diff --git a/app/widget/slider/integerslider.cpp b/app/widget/slider/integerslider.cpp index 511f2b581..d5dd940c1 100644 --- a/app/widget/slider/integerslider.cpp +++ b/app/widget/slider/integerslider.cpp @@ -31,21 +31,40 @@ int IntegerSlider::GetValue() return Value().toInt(); } -void IntegerSlider::SetValue(const int &v) +void IntegerSlider::SetValue(const int64_t &v) { SliderBase::SetValue(v); } -void IntegerSlider::SetMinimum(const int &d) +void IntegerSlider::SetMinimum(const int64_t &d) { SetMinimumInternal(d); } -void IntegerSlider::SetMaximum(const int &d) +void IntegerSlider::SetMaximum(const int64_t &d) { SetMaximumInternal(d); } +QVariant IntegerSlider::StringToValue(const QString &s, bool *ok) +{ + bool valid; + + // Allow both floats and integers for either modes + double decimal_val = s.toDouble(&valid); + + if (ok) { + *ok = valid; + } + + if (valid) { + // But for an integer, we round it + return qRound(decimal_val); + } + + return QVariant(); +} + void IntegerSlider::ConvertValue(QVariant v) { emit ValueChanged(v.toInt()); diff --git a/app/widget/slider/integerslider.h b/app/widget/slider/integerslider.h index f5f78116c..f57fd7883 100644 --- a/app/widget/slider/integerslider.h +++ b/app/widget/slider/integerslider.h @@ -31,14 +31,17 @@ public: int GetValue(); - void SetValue(const int& v); + void SetValue(const int64_t& v); - void SetMinimum(const int& d); + void SetMinimum(const int64_t& d); - void SetMaximum(const int& d); + void SetMaximum(const int64_t& d); + +protected: + virtual QVariant StringToValue(const QString& s, bool* ok) override; signals: - void ValueChanged(int); + void ValueChanged(int64_t); private slots: void ConvertValue(QVariant v); diff --git a/app/widget/slider/sliderbase.cpp b/app/widget/slider/sliderbase.cpp index 53b5442ed..f20d884d6 100644 --- a/app/widget/slider/sliderbase.cpp +++ b/app/widget/slider/sliderbase.cpp @@ -31,7 +31,8 @@ SliderBase::SliderBase(Mode mode, QWidget *parent) : has_min_(false), has_max_(false), mode_(mode), - dragged_(false) + dragged_(false), + require_valid_input_(true) { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); @@ -66,6 +67,11 @@ void SliderBase::SetDragMultiplier(const double &d) drag_multiplier_ = d; } +void SliderBase::SetRequireValidInput(bool e) +{ + require_valid_input_ = e; +} + const QVariant &SliderBase::Value() { if (dragged_) { @@ -127,26 +133,18 @@ const QVariant &SliderBase::ClampValue(const QVariant &v) void SliderBase::UpdateLabel(const QVariant &v) { - switch (mode_) { - case kString: - { - QString vstr = v.toString(); + label_->setText(ValueToString(v)); +} - if (vstr.isEmpty()) { - label_->setText(tr("(none)")); - } else { - label_->setText(vstr); - } - break; - } - case kInteger: - label_->setText(v.toString()); - break; - case kFloat: - // For floats, we show a limited number of decimal places - label_->setText(QString::number(v.toDouble(), 'f', decimal_places_)); - break; - } +QString SliderBase::ValueToString(const QVariant &v) +{ + return v.toString(); +} + +QVariant SliderBase::StringToValue(const QString &s, bool *ok) +{ + *ok = true; + return s; } void SliderBase::LabelPressed() @@ -224,25 +222,7 @@ void SliderBase::LabelDragged(int i) void SliderBase::LineEditConfirmed() { bool is_valid = true; - QVariant test_val; - - // Check whether the entered value is valid for this mode - switch (mode_) { - case kString: - // Anything goes for a string - test_val = editor_->text(); - break; - case kInteger: - case kFloat: - // Allow both floats and integers for either modes - test_val = editor_->text().toDouble(&is_valid); - - if (is_valid && mode_ == kInteger) { - // But for an integer, we round it - test_val = qRound(test_val.toDouble()); - } - break; - } + QVariant test_val = StringToValue(editor_->text(), &is_valid); // Ensure editor doesn't signal that the focus is lost editor_->blockSignals(true); @@ -253,7 +233,7 @@ void SliderBase::LineEditConfirmed() setCurrentWidget(label_); emit ValueChanged(value_); - } else { + } else if (require_valid_input_) { QMessageBox::critical(this, tr("Invalid Value"), tr("The entered value is not valid for this field."), diff --git a/app/widget/slider/sliderbase.h b/app/widget/slider/sliderbase.h index 15964315c..d79dde4e5 100644 --- a/app/widget/slider/sliderbase.h +++ b/app/widget/slider/sliderbase.h @@ -40,6 +40,8 @@ public: void SetDragMultiplier(const double& d); + void SetRequireValidInput(bool e); + signals: void ValueChanged(QVariant v); @@ -54,6 +56,10 @@ protected: void UpdateLabel(const QVariant& v); + virtual QString ValueToString(const QVariant &v); + + virtual QVariant StringToValue(const QString& s, bool* ok); + virtual void changeEvent(QEvent* e) override; int decimal_places_; @@ -83,6 +89,8 @@ private: QVariant temp_dragged_value_; + bool require_valid_input_; + private slots: void LabelPressed(); diff --git a/app/widget/slider/stringslider.cpp b/app/widget/slider/stringslider.cpp index 23d01262f..5f52f2fee 100644 --- a/app/widget/slider/stringslider.cpp +++ b/app/widget/slider/stringslider.cpp @@ -36,6 +36,12 @@ void StringSlider::SetValue(const QString &v) SliderBase::SetValue(v); } +QString StringSlider::ValueToString(const QVariant &v) +{ + QString vstr = v.toString(); + return (vstr.isEmpty()) ? tr("(none)") : vstr; +} + void StringSlider::ConvertValue(QVariant v) { emit ValueChanged(v.toString()); diff --git a/app/widget/slider/stringslider.h b/app/widget/slider/stringslider.h index 020a46f9e..f086d334a 100644 --- a/app/widget/slider/stringslider.h +++ b/app/widget/slider/stringslider.h @@ -35,6 +35,9 @@ public: void SetValue(const QString& v); +protected: + virtual QString ValueToString(const QVariant& value) override; + signals: void ValueChanged(QString); diff --git a/app/widget/slider/timeslider.cpp b/app/widget/slider/timeslider.cpp new file mode 100644 index 000000000..7f91aecc9 --- /dev/null +++ b/app/widget/slider/timeslider.cpp @@ -0,0 +1,31 @@ +#include "timeslider.h" + +#include "common/timecodefunctions.h" + +TimeSlider::TimeSlider(QWidget *parent) : + IntegerSlider(parent) +{ + SetMinimum(0); +} + +void TimeSlider::SetTimebase(const rational &timebase) +{ + timebase_ = timebase; +} + +QString TimeSlider::ValueToString(const QVariant &v) +{ + if (timebase_.isNull()) { + // We can't generate a timecode without a timebase, so we just return the number + return IntegerSlider::ValueToString(v); + } + + return olive::timestamp_to_timecode(v.toLongLong(), + timebase_, + olive::CurrentTimecodeDisplay()); +} + +QVariant TimeSlider::StringToValue(const QString &s, bool *ok) +{ + return olive::timecode_to_timestamp(s, timebase_, olive::CurrentTimecodeDisplay(), ok); +} diff --git a/app/widget/slider/timeslider.h b/app/widget/slider/timeslider.h new file mode 100644 index 000000000..331572d96 --- /dev/null +++ b/app/widget/slider/timeslider.h @@ -0,0 +1,24 @@ +#ifndef TIMESLIDER_H +#define TIMESLIDER_H + +#include "common/rational.h" +#include "integerslider.h" + +class TimeSlider : public IntegerSlider +{ +public: + TimeSlider(QWidget* parent = nullptr); + + void SetTimebase(const rational& timebase); + +protected: + virtual QString ValueToString(const QVariant& v) override; + + virtual QVariant StringToValue(const QString& s, bool* ok) override; + +private: + rational timebase_; + +}; + +#endif // TIMESLIDER_H