slider: reworked sliderbase and derivatives

Mostly cleaning up code, SliderBase was fairly messy.
This commit is contained in:
itsmattkc
2021-04-17 12:49:21 +10:00
parent f1d325629a
commit 9328539373
38 changed files with 1068 additions and 855 deletions
+26 -7
View File
@@ -5,23 +5,42 @@
namespace olive {
rational rational::fromDouble(const double &flt)
rational rational::fromDouble(const double &flt, bool* ok)
{
// Use FFmpeg function for the time being
return av_d2q(flt, INT_MAX);
AVRational r = av_d2q(flt, INT_MAX);
if (r.den == 0) {
// If den == 0, we were unable to convert to a rational
if (ok) {
*ok = false;
}
return rational();
} else {
// Otherwise, assume we received a real rational
if (ok) {
*ok = true;
}
return r;
}
}
rational rational::fromString(const QString &str)
rational rational::fromString(const QString &str, bool* ok)
{
QStringList elements = str.split('/');
switch (elements.size()) {
case 0:
return rational();
case 1:
return rational(elements.first().toLongLong());
return rational(elements.first().toLongLong(ok));
case 2:
return rational(elements.at(0).toLongLong(ok), elements.at(1).toLongLong(ok));
default:
return rational(elements.at(0).toLongLong(), elements.at(1).toLongLong());
if (ok) {
*ok = false;
}
return rational();
}
}
+2 -2
View File
@@ -61,9 +61,9 @@ public:
reduce();
}
static rational fromDouble(const double& flt);
static rational fromDouble(const double& flt, bool *ok = nullptr);
static rational fromString(const QString& str);
static rational fromString(const QString& str, bool* ok = nullptr);
//Assignment Operators
const rational& operator=(const rational &rhs);
+6
View File
@@ -233,6 +233,12 @@ err_fatal:
return 0;
}
rational Timecode::timecode_to_time(const QString &timecode, const rational &timebase, const Timecode::Display &display, bool *ok)
{
int64_t timestamp = timecode_to_timestamp(timecode, timebase, display, ok);
return timestamp_to_time(timestamp, timebase);
}
rational Timecode::snap_time_to_timebase(const rational &time, const rational &timebase)
{
// Just convert to a timestamp in timebase units and back
+1
View File
@@ -53,6 +53,7 @@ public:
static QString timestamp_to_timecode(const int64_t &timestamp, const rational& timebase, const Display &display, bool show_plus_if_positive = false);
static int64_t timecode_to_timestamp(const QString& timecode, const rational& timebase, const Display& display, bool *ok = nullptr);
static rational timecode_to_time(const QString& timecode, const rational& timebase, const Display& display, bool *ok = nullptr);
static rational snap_time_to_timebase(const rational& time, const rational& timebase);
@@ -101,10 +101,11 @@ PreferencesGeneralTab::PreferencesGeneralTab()
timeline_layout->addWidget(new QLabel(tr("Default Still Image Length:")), row, 0);
default_still_length_ = new FloatSlider();
default_still_length_->SetMinimum(0.1);
default_still_length_ = new RationalSlider();
default_still_length_->SetMinimum(rational(100, 1000));
default_still_length_->SetTimebase(rational(100, 1000));
default_still_length_->SetFormat(tr("%1 seconds"));
default_still_length_->SetValue(Config::Current()["DefaultStillLength"].value<rational>().toDouble());
default_still_length_->SetValue(Config::Current()["DefaultStillLength"].value<rational>());
timeline_layout->addWidget(default_still_length_);
row++;
@@ -168,7 +169,7 @@ void PreferencesGeneralTab::Accept(MultiUndoCommand *command)
Config::Current()[QStringLiteral("Autoscroll")] = autoscroll_method_->currentData();
Config::Current()[QStringLiteral("DefaultStillLength")] = QVariant::fromValue(rational::fromDouble(default_still_length_->GetValue()));
Config::Current()[QStringLiteral("DefaultStillLength")] = QVariant::fromValue(default_still_length_->GetValue());
QString set_language = language_combobox_->currentData().toString();
if (QLocale::system().name() == set_language) {
@@ -27,7 +27,7 @@
#include "dialog/configbase/configdialogbase.h"
#include "node/project/sequence/sequence.h"
#include "widget/slider/floatslider.h"
#include "widget/slider/rationalslider.h"
#include "widget/slider/integerslider.h"
namespace olive {
@@ -49,7 +49,7 @@ private:
QCheckBox* rectified_waveforms_;
FloatSlider* default_still_length_;
RationalSlider* default_still_length_;
QCheckBox* autorecovery_enabled_;
+6 -1
View File
@@ -25,6 +25,7 @@
#include "node/output/track/track.h"
#include "transition/transition.h"
#include "widget/slider/floatslider.h"
#include "widget/slider/rationalslider.h"
namespace olive {
@@ -43,11 +44,15 @@ Block::Block() :
out_transition_(nullptr)
{
AddInput(kLengthInput, NodeValue::kRational, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
SetInputProperty(kLengthInput, "min", QVariant::fromValue(rational(0, 1)));
SetInputProperty(kLengthInput, QStringLiteral("min"), QVariant::fromValue(rational(0, 1)));
SetInputProperty(kLengthInput, QStringLiteral("view"), RationalSlider::kTime);
SetInputProperty(kLengthInput, QStringLiteral("viewlock"), true);
IgnoreInvalidationsFrom(kLengthInput);
IgnoreHashingFrom(kLengthInput);
AddInput(kMediaInInput, NodeValue::kRational, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
SetInputProperty(kMediaInInput, QStringLiteral("view"), RationalSlider::kTime);
SetInputProperty(kMediaInInput, QStringLiteral("viewlock"), true);
IgnoreHashingFrom(kMediaInInput);
AddInput(kEnabledInput, NodeValue::kBoolean, true, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
+13 -18
View File
@@ -160,35 +160,30 @@ void MenuShared::AddItemsForClipEditMenu(Menu *m)
m->addAction(clip_nest_item_);
}
void MenuShared::AddItemsForTimeRulerMenu(Menu *m, const rational& timebase)
void MenuShared::AddItemsForTimeRulerMenu(Menu *m)
{
// If a menu is already created (such as the view menu) we need to remove the instance
// of dropframe or non-dropframe timecode that is already there to avoid double displays
if (m->actions().contains(view_timecode_view_dropframe_item_)) {
m->removeAction(view_timecode_view_dropframe_item_);
}
if (m->actions().contains(view_timecode_view_nondropframe_item_)) {
m->removeAction(view_timecode_view_nondropframe_item_);
}
if (Timecode::TimebaseIsDropFrame(timebase)) {
m->addAction(view_timecode_view_dropframe_item_);
m->addAction(view_timecode_view_nondropframe_item_);
} else {
m->addAction(view_timecode_view_nondropframe_item_);
}
m->addAction(view_timecode_view_seconds_item_);
m->addAction(view_timecode_view_frames_item_);
m->addAction(view_timecode_view_milliseconds_item_);
}
void MenuShared::AboutToShowTimeRulerActions()
void MenuShared::AboutToShowTimeRulerActions(const rational& timebase)
{
QList<QAction*> timecode_display_actions = frame_view_mode_group_->actions();
Timecode::Display current_timecode_display = Core::instance()->GetTimecodeDisplay();
// Only show the drop-frame option if the timebase is drop-frame
view_timecode_view_dropframe_item_->setVisible(!timebase.isNull() && Timecode::TimebaseIsDropFrame(timebase));
if (!view_timecode_view_dropframe_item_->isVisible() && current_timecode_display == Timecode::kTimecodeDropFrame) {
// If the current setting is drop-frame, correct to non-drop frame
current_timecode_display = Timecode::kTimecodeNonDropFrame;
}
foreach (QAction* a, timecode_display_actions) {
if (a->data() == Core::instance()->GetTimecodeDisplay()) {
if (a->data() == current_timecode_display) {
a->setChecked(true);
break;
}
+2 -2
View File
@@ -46,9 +46,9 @@ public:
void AddItemsForInOutMenu(Menu* m);
void AddColorCodingMenu(Menu* m);
void AddItemsForClipEditMenu(Menu* m);
void AddItemsForTimeRulerMenu(Menu* m, const rational& timebase);
void AddItemsForTimeRulerMenu(Menu* m);
void AboutToShowTimeRulerActions();
void AboutToShowTimeRulerActions(const rational& timebase);
static MenuShared* instance();
@@ -238,7 +238,7 @@ void NodeParamViewWidgetBridge::SetInputValueInternal(const QVariant &value, int
}
}
void NodeParamViewWidgetBridge::ProcessSlider(SliderBase *slider, const QVariant &value)
void NodeParamViewWidgetBridge::ProcessSlider(NumericSliderBase *slider, const QVariant &value)
{
rational node_time = GetCurrentTimeAsNodeTime();
@@ -406,7 +406,7 @@ void NodeParamViewWidgetBridge::CreateSliders(int count)
{
for (int i=0;i<count;i++) {
T* fs = new T();
fs->SetDefaultValue(input_.GetSplitDefaultValueForTrack(i));
fs->SliderBase::SetDefaultValue(input_.GetSplitDefaultValueForTrack(i));
fs->SetLadderElementCount(2);
widgets_.append(fs);
connect(fs, &T::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
@@ -758,6 +758,22 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString& input, const QStr
}
}
if (data_type == NodeValue::kRational) {
if (key == QStringLiteral("view")) {
RationalSlider::DisplayType display_type = static_cast<RationalSlider::DisplayType>(value.toInt());
foreach (QWidget* w, widgets_) {
static_cast<RationalSlider*>(w)->SetDisplayType(display_type);
}
} else if (key == QStringLiteral("viewlock")) {
bool locked = value.toBool();
foreach (QWidget* w, widgets_) {
static_cast<RationalSlider*>(w)->SetLockDisplayType(locked);
}
}
}
// Parameters for files
if (data_type == NodeValue::kFile) {
FileField* ff = static_cast<FileField*>(widgets_.first());
@@ -24,7 +24,7 @@
#include <QObject>
#include "node/inputdragger.h"
#include "widget/slider/sliderbase.h"
#include "widget/slider/base/numericsliderbase.h"
#include "widget/timetarget/timetarget.h"
namespace olive {
@@ -64,7 +64,7 @@ private:
void SetInputValueInternal(const QVariant& value, int track, MultiUndoCommand *command);
void ProcessSlider(SliderBase* slider, const QVariant& value);
void ProcessSlider(NumericSliderBase* slider, const QVariant& value);
template <typename T>
void CreateSliders(int count);
+2 -6
View File
@@ -14,6 +14,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(base)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
widget/slider/floatslider.h
@@ -22,12 +24,6 @@ set(OLIVE_SOURCES
widget/slider/integerslider.cpp
widget/slider/rationalslider.h
widget/slider/rationalslider.cpp
widget/slider/sliderbase.h
widget/slider/sliderbase.cpp
widget/slider/sliderlabel.h
widget/slider/sliderlabel.cpp
widget/slider/sliderladder.h
widget/slider/sliderladder.cpp
widget/slider/stringslider.h
widget/slider/stringslider.cpp
widget/slider/timeslider.h
+30
View File
@@ -0,0 +1,30 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2020 Olive Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
widget/slider/base/decimalsliderbase.h
widget/slider/base/decimalsliderbase.cpp
widget/slider/base/numericsliderbase.h
widget/slider/base/numericsliderbase.cpp
widget/slider/base/sliderbase.h
widget/slider/base/sliderbase.cpp
widget/slider/base/sliderlabel.h
widget/slider/base/sliderlabel.cpp
widget/slider/base/sliderladder.h
widget/slider/base/sliderladder.cpp
PARENT_SCOPE
)
@@ -0,0 +1,63 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "decimalsliderbase.h"
namespace olive {
#define super NumericSliderBase
DecimalSliderBase::DecimalSliderBase(QWidget *parent) :
super(parent),
decimal_places_(2),
autotrim_decimal_places_(false)
{
}
void DecimalSliderBase::SetAutoTrimDecimalPlaces(bool e)
{
autotrim_decimal_places_ = e;
UpdateLabel();
}
QString DecimalSliderBase::FloatToString(double val, int decimal_places, bool autotrim_decimal_places)
{
QString s = QString::number(val, 'f', decimal_places);
if (autotrim_decimal_places) {
while (s.endsWith('0')
&& s.at(s.size() - 2).isDigit()) {
s = s.left(s.size() - 1);
}
}
return s;
}
void DecimalSliderBase::SetDecimalPlaces(int i)
{
decimal_places_ = i;
UpdateLabel();
}
}
@@ -0,0 +1,50 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef DECIMALSLIDERBASE_H
#define DECIMALSLIDERBASE_H
#include "numericsliderbase.h"
namespace olive {
class DecimalSliderBase : public NumericSliderBase
{
public:
DecimalSliderBase(QWidget* parent = nullptr);
int GetDecimalPlaces() const { return decimal_places_; }
void SetDecimalPlaces(int i);
bool GetAutoTrimDecimalPlaces() const { return autotrim_decimal_places_; };
void SetAutoTrimDecimalPlaces(bool e);
static QString FloatToString(double val, int decimal_places, bool autotrim_decimal_places);
private:
int decimal_places_;
bool autotrim_decimal_places_;
};
}
#endif // DECIMALSLIDERBASE_H
@@ -0,0 +1,203 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "numericsliderbase.h"
#include "common/qtutils.h"
#include "config/config.h"
namespace olive {
NumericSliderBase::NumericSliderBase(QWidget *parent) :
SliderBase(parent),
drag_ladder_(nullptr),
ladder_element_count_(0),
dragged_(false),
has_min_(false),
has_max_(false),
dragged_diff_(0),
drag_multiplier_(1.0),
setting_drag_value_(false)
{
// Numeric sliders are draggable, so we have a cursor that indicates that
setCursor(Qt::SizeHorCursor);
connect(label(), &SliderLabel::LabelPressed, this, &NumericSliderBase::LabelPressed);
}
void NumericSliderBase::SetDragMultiplier(const double &d)
{
drag_multiplier_ = d;
}
void NumericSliderBase::LabelPressed()
{
// Generate width hint
drag_ladder_ = new SliderLadder(drag_multiplier_, ladder_element_count_, GetFormattedValueToString(99999999));
drag_ladder_->SetValue(GetFormattedValueToString());
drag_ladder_->show();
drag_start_value_ = GetValueInternal();
QMetaObject::invokeMethod(this, "RepositionLadder", Qt::QueuedConnection);
connect(drag_ladder_, &SliderLadder::DraggedByValue, this, &NumericSliderBase::LadderDragged);
connect(drag_ladder_, &SliderLadder::Released, this, &NumericSliderBase::LadderReleased);
}
void NumericSliderBase::LadderDragged(int value, double multiplier)
{
dragged_ = true;
dragged_diff_ += value * drag_multiplier_ * multiplier;
// Store current value to try and prevent any unnecessary signalling if the value doesn't change
QVariant pre_set_value = GetValueInternal();
setting_drag_value_ = true;
SetValueInternal(AdjustDragDistanceInternal(drag_start_value_, dragged_diff_));
setting_drag_value_ = false;
if (GetValueInternal() != pre_set_value) {
// We retrieve the value instead of storing it ourselves because SetValueInternal may do extra
// processing (such as clamping).
drag_ladder_->SetValue(GetFormattedValueToString());
if (!UsingLadders()) {
RepositionLadder();
}
ValueSignalEvent(GetValueInternal());
}
}
void NumericSliderBase::LadderReleased()
{
drag_ladder_->deleteLater();
drag_ladder_ = nullptr;
dragged_diff_ = 0;
if (dragged_) {
// This was a drag, send another value changed event
ValueSignalEvent(GetValueInternal());
dragged_ = false;
} else {
ShowEditor();
}
}
void NumericSliderBase::RepositionLadder()
{
if (drag_ladder_) {
if (UsingLadders()) {
drag_ladder_->move(QCursor::pos() - QPoint(drag_ladder_->width()/2, drag_ladder_->height()/2));
} else {
QPoint label_global_pos = label()->mapToGlobal(label()->pos());
int text_width = QtUtils::QFontMetricsWidth(label()->fontMetrics(), label()->text());
if (label()->alignment() & Qt::AlignRight) {
label_global_pos.setX(label_global_pos.x() + label()->width() - text_width);
} else if (label()->alignment() & Qt::AlignHCenter) {
label_global_pos.setX(label_global_pos.x() + label()->width()/2 - text_width/2);
}
int ladder_x = label_global_pos.x() + text_width / 2 - drag_ladder_->width() / 2;
int ladder_y = label_global_pos.y() + label()->height() / 2 - drag_ladder_->height() / 2;
drag_ladder_->move(ladder_x, ladder_y);
}
drag_ladder_->StartListeningToMouseInput();
}
}
bool NumericSliderBase::IsDragging() const
{
return drag_ladder_;
}
bool NumericSliderBase::UsingLadders() const
{
return ladder_element_count_ > 0 && Config::Current()[QStringLiteral("UseSliderLadders")].toBool();
}
QVariant NumericSliderBase::AdjustValue(const QVariant &value) const
{
// Clamps between min/max
if (has_min_ && ValueLessThan(value, min_value_)) {
return min_value_;
} else if (has_max_ && ValueGreaterThan(value, max_value_)) {
return max_value_;
}
return value;
}
void NumericSliderBase::SetOffset(const QVariant &v)
{
offset_ = v;
UpdateLabel();
}
QVariant NumericSliderBase::AdjustDragDistanceInternal(const QVariant &start, const double &drag) const
{
return start.toDouble() + drag;
}
void NumericSliderBase::SetMinimumInternal(const QVariant &v)
{
min_value_ = v;
has_min_ = true;
// Limit value by this new minimum value
if (ValueLessThan(GetValueInternal(), min_value_)) {
SetValueInternal(min_value_);
}
}
void NumericSliderBase::SetMaximumInternal(const QVariant &v)
{
max_value_ = v;
has_max_ = true;
// Limit value by this new maximum value
if (ValueGreaterThan(GetValueInternal(), max_value_)) {
SetValueInternal(max_value_);
}
}
bool NumericSliderBase::ValueGreaterThan(const QVariant &lhs, const QVariant &rhs) const
{
return lhs.toDouble() > rhs.toDouble();
}
bool NumericSliderBase::ValueLessThan(const QVariant &lhs, const QVariant &rhs) const
{
return lhs.toDouble() < rhs.toDouble();
}
bool NumericSliderBase::CanSetValue() const
{
return !IsDragging() || setting_drag_value_;
}
}
+103
View File
@@ -0,0 +1,103 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef NUMERICSLIDERBASE_H
#define NUMERICSLIDERBASE_H
#include "sliderbase.h"
namespace olive {
class NumericSliderBase : public SliderBase
{
Q_OBJECT
public:
NumericSliderBase(QWidget *parent = nullptr);
void SetLadderElementCount(int b)
{
ladder_element_count_ = b;
}
void SetDragMultiplier(const double& d);
void SetOffset(const QVariant& v);
bool IsDragging() const;
protected:
const QVariant& GetOffset() const
{
return offset_;
}
virtual QVariant AdjustDragDistanceInternal(const QVariant &start, const double &drag) const;
void SetMinimumInternal(const QVariant& v);
void SetMaximumInternal(const QVariant& v);
virtual bool ValueGreaterThan(const QVariant& lhs, const QVariant& rhs) const;
virtual bool ValueLessThan(const QVariant& lhs, const QVariant& rhs) const;
virtual bool CanSetValue() const override;
private:
bool UsingLadders() const;
virtual QVariant AdjustValue(const QVariant& value) const override;
SliderLadder* drag_ladder_;
int ladder_element_count_;
bool dragged_;
bool has_min_;
QVariant min_value_;
bool has_max_;
QVariant max_value_;
double dragged_diff_;
QVariant drag_start_value_;
QVariant offset_;
double drag_multiplier_;
bool setting_drag_value_;
private slots:
void LabelPressed();
void RepositionLadder();
void LadderDragged(int value, double multiplier);
void LadderReleased();
};
}
#endif // NUMERICSLIDERBASE_H
+230
View File
@@ -0,0 +1,230 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "sliderbase.h"
#include <QDebug>
#include <QEvent>
#include <QMessageBox>
#include "common/qtutils.h"
#include "core.h"
#include "window/mainwindow/mainwindow.h"
namespace olive {
#define super QStackedWidget
SliderBase::SliderBase(QWidget *parent) :
super(parent),
tristate_(false),
format_plural_(false)
{
// Standard (non-numeric) sliders are not draggable, so we indicate as such
setCursor(Qt::PointingHandCursor);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
label_ = new SliderLabel(this);
addWidget(label_);
editor_ = new FocusableLineEdit(this);
addWidget(editor_);
connect(label_, &SliderLabel::focused, this, &SliderBase::ShowEditor);
connect(label_, &SliderLabel::RequestReset, this, &SliderBase::ResetValue);
connect(editor_, &FocusableLineEdit::Confirmed, this, &SliderBase::LineEditConfirmed);
connect(editor_, &FocusableLineEdit::Cancelled, this, &SliderBase::LineEditCancelled);
}
void SliderBase::SetAlignment(Qt::Alignment alignment)
{
label_->setAlignment(alignment);
}
bool SliderBase::IsTristate() const
{
return tristate_;
}
void SliderBase::SetTristate()
{
tristate_ = true;
UpdateLabel();
}
const QVariant &SliderBase::GetValueInternal() const
{
return value_;
}
void SliderBase::SetValueInternal(const QVariant &v)
{
if (!CanSetValue()) {
return;
}
value_ = AdjustValue(v);
// Disable tristate
tristate_ = false;
UpdateLabel();
}
void SliderBase::SetDefaultValue(const QVariant &v)
{
default_value_ = v;
}
void SliderBase::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
UpdateLabel();
}
super::changeEvent(e);
}
void SliderBase::UpdateLabel()
{
label_->setText(tristate_ ? tr("---") : GetFormattedValueToString());
}
QVariant SliderBase::AdjustValue(const QVariant &value) const
{
return value;
}
bool SliderBase::CanSetValue() const
{
return true;
}
void SliderBase::ValueSignalEvent(const QVariant &value)
{
Q_UNUSED(value)
}
void SliderBase::ShowEditor()
{
// This was a simple click
// Load label's text into editor
editor_->setText(ValueToString(value_));
// Show editor
setCurrentWidget(editor_);
// Select all text in the editor
editor_->setFocus();
editor_->selectAll();
}
void SliderBase::LineEditConfirmed()
{
bool is_valid = true;
QVariant test_val = StringToValue(editor_->text(), &is_valid);
// Ensure editor doesn't signal that the focus is lost
editor_->blockSignals(true);
label_->blockSignals(true);
if (is_valid) {
SetValueInternal(test_val);
setCurrentWidget(label_);
ValueSignalEvent(value_);
} else {
QMessageBox::critical(this,
tr("Invalid Value"),
tr("The entered value is not valid for this field."),
QMessageBox::Ok);
// Refocus editor
editor_->setFocus();
}
editor_->blockSignals(false);
label_->blockSignals(false);
}
void SliderBase::LineEditCancelled()
{
// Ensure editor doesn't signal that the focus is lost
editor_->blockSignals(true);
label_->blockSignals(true);
// Set widget back to label
setCurrentWidget(label_);
editor_->blockSignals(false);
label_->blockSignals(false);
}
void SliderBase::ResetValue()
{
if (default_value_.isValid()) {
SetValueInternal(default_value_);
ValueSignalEvent(value_);
}
}
void SliderBase::SetFormat(const QString &s, const bool plural)
{
custom_format_ = s;
format_plural_ = plural;
UpdateLabel();
}
void SliderBase::ClearFormat()
{
custom_format_.clear();
UpdateLabel();
}
bool SliderBase::IsFormatPlural() const
{
return format_plural_;
}
QString SliderBase::GetFormat() const
{
if (custom_format_.isEmpty()) {
return QStringLiteral("%1");
} else {
return custom_format_;
}
}
QString SliderBase::GetFormattedValueToString() const
{
return GetFormattedValueToString(GetValueInternal());
}
QString SliderBase::GetFormattedValueToString(const QVariant &v) const
{
if (format_plural_) {
return tr(GetFormat().toUtf8().constData(), nullptr, v.toInt());
} else {
return GetFormat().arg(ValueToString(v));
}
}
}
@@ -28,84 +28,57 @@
#include "widget/focusablelineedit/focusablelineedit.h"
namespace olive {
class SliderBase : public QStackedWidget
{
Q_OBJECT
public:
enum Mode {
kString,
kInteger,
kFloat,
kRational
};
SliderBase(Mode mode, QWidget* parent = nullptr);
void SetDragMultiplier(const double& d);
void SetRequireValidInput(bool e);
SliderBase(QWidget* parent = nullptr);
void SetAlignment(Qt::Alignment alignment);
void SetDefaultValue(const QVariant& v);
const QVariant& GetOffset() const
{
return offset_;
}
void SetOffset(const QVariant& v);
bool IsTristate() const;
void SetTristate();
bool IsDragging() const;
void SetFormat(const QString& s, const bool plural=false);
void SetFormat(const QString& s, const bool plural = false);
void ClearFormat();
bool IsFormatPlural() const;
void SetLadderElementCount(int b)
{
ladder_element_count_ = b;
}
void SetDefaultValue(const QVariant& v);
signals:
void ValueChanged(QVariant v);
QString GetFormattedValueToString(const QVariant& v) const;
public slots:
void ShowEditor();
protected slots:
void UpdateLabel();
protected:
const QVariant& Value() const;
const QVariant& GetValueInternal() const;
void SetValue(const QVariant& v);
void SetMinimumInternal(const QVariant& v);
void SetMaximumInternal(const QVariant& v);
void UpdateLabel(const QVariant& v);
QLabel* label() { return label_; }
virtual double AdjustDragDistanceInternal(const double& start, const double& drag);
virtual QString ValueToString(const QVariant &v) = 0;
virtual QVariant StringToValue(const QString& s, bool* ok) = 0;
virtual void changeEvent(QEvent* e) override;
void ForceLabelUpdate();
double drag_multiplier_;
private:
const QVariant& ClampValue(const QVariant& v);
void SetValueInternal(const QVariant& v);
QString GetFormat() const;
bool UsingLadders() const;
QString GetFormattedValueToString() const;
SliderLabel* label() { return label_; }
virtual QString ValueToString(const QVariant &v) const = 0;
virtual QVariant StringToValue(const QString& s, bool* ok) const = 0;
virtual QVariant AdjustValue(const QVariant& value) const;
virtual bool CanSetValue() const;
virtual void ValueSignalEvent(const QVariant& value) = 0;
virtual void changeEvent(QEvent* e) override;
private:
SliderLabel* label_;
FocusableLineEdit* editor_;
@@ -113,51 +86,19 @@ private:
QVariant value_;
QVariant default_value_;
bool has_min_;
QVariant min_value_;
bool has_max_;
QVariant max_value_;
Mode mode_;
double dragged_diff_;
QVariant temp_dragged_value_;
QVariant clamped_temp_dragged_value_;
QVariant offset_;
bool require_valid_input_;
bool tristate_;
QString custom_format_;
bool format_plural_;
SliderLadder* drag_ladder_;
int ladder_element_count_;
bool dragged_;
private slots:
void ShowEditor();
void LabelPressed();
void LadderDragged(int value, double multiplier);
void LadderReleased();
void LineEditConfirmed();
void LineEditCancelled();
void ResetValue();
void RepositionLadder();
};
}
@@ -63,6 +63,15 @@ void SliderLabel::mousePressEvent(QMouseEvent *e)
}
}
void SliderLabel::mouseReleaseEvent(QMouseEvent *e)
{
if (e->button() == Qt::LeftButton) {
if (!(e->modifiers() & Qt::AltModifier)) {
emit LabelReleased();
}
}
}
void SliderLabel::focusInEvent(QFocusEvent *event)
{
QWidget::focusInEvent(event);
@@ -34,13 +34,17 @@ public:
SliderLabel(QWidget* parent);
protected:
virtual void mousePressEvent(QMouseEvent *ev) override;
virtual void mousePressEvent(QMouseEvent *e) override;
virtual void mouseReleaseEvent(QMouseEvent *e) override;
virtual void focusInEvent(QFocusEvent *event) override;
signals:
void LabelPressed();
void LabelReleased();
void focused();
void RequestReset();
@@ -38,8 +38,7 @@
namespace olive {
SliderLadder::SliderLadder(double drag_multiplier, int nb_outer_values, QString width_hint, QWidget* parent) :
QFrame(parent, Qt::Popup),
width_hint_(width_hint)
QFrame(parent, Qt::Popup)
{
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setMargin(0);
@@ -53,17 +52,17 @@ SliderLadder::SliderLadder(double drag_multiplier, int nb_outer_values, QString
}
for (int i=nb_outer_values-1;i>=0;i--) {
elements_.append(new SliderLadderElement(qPow(10, i + 1) * drag_multiplier, width_hint_));
elements_.append(new SliderLadderElement(qPow(10, i + 1) * drag_multiplier, width_hint));
}
// Create center entry
SliderLadderElement* start_element = new SliderLadderElement(drag_multiplier, width_hint_);
SliderLadderElement* start_element = new SliderLadderElement(drag_multiplier, width_hint);
active_element_ = elements_.size();
start_element->SetHighlighted(true);
elements_.append(start_element);
for (int i=0;i<nb_outer_values;i++) {
elements_.append(new SliderLadderElement(qPow(10, -i - 1) * drag_multiplier, width_hint_));
elements_.append(new SliderLadderElement(qPow(10, -i - 1) * drag_multiplier, width_hint));
}
foreach (SliderLadderElement* e, elements_) {
@@ -232,7 +231,7 @@ bool SliderLadder::UsingLadders() const
return elements_.size() > 1;
}
SliderLadderElement::SliderLadderElement(const double &multiplier, QString width_hint, QWidget *parent) :
SliderLadderElement::SliderLadderElement(const double &multiplier, QString width_hint, QWidget *parent) :
QWidget(parent),
multiplier_(multiplier),
highlighted_(false),
@@ -94,8 +94,6 @@ private:
QTimer drag_timer_;
QString width_hint_;
private slots:
void TimerUpdate();
+22 -42
View File
@@ -26,25 +26,28 @@
namespace olive {
#define super DecimalSliderBase
FloatSlider::FloatSlider(QWidget *parent) :
SliderBase(kFloat, parent),
display_type_(kNormal),
decimal_places_(1),
autotrim_decimal_places_(false)
super(parent),
display_type_(kNormal)
{
SetValue(0.0);
connect(this, SIGNAL(ValueChanged(QVariant)), this, SLOT(ConvertValue(QVariant)));
}
double FloatSlider::GetValue()
double FloatSlider::GetValue() const
{
return Value().toDouble();
return GetValueInternal().toDouble();
}
void FloatSlider::SetValue(const double &d)
{
SliderBase::SetValue(d);
SetValueInternal(d);
}
void FloatSlider::SetDefaultValue(const double &d)
{
super::SetDefaultValue(d);
}
void FloatSlider::SetMinimum(const double &d)
@@ -57,13 +60,6 @@ void FloatSlider::SetMaximum(const double &d)
SetMaximumInternal(d);
}
void FloatSlider::SetDecimalPlaces(int i)
{
decimal_places_ = i;
ForceLabelUpdate();
}
void FloatSlider::SetDisplayType(const FloatSlider::DisplayType &type)
{
display_type_ = type;
@@ -81,13 +77,6 @@ void FloatSlider::SetDisplayType(const FloatSlider::DisplayType &type)
}
}
void FloatSlider::SetAutoTrimDecimalPlaces(bool e)
{
autotrim_decimal_places_ = e;
ForceLabelUpdate();
}
QString FloatSlider::ValueToString(double val, FloatSlider::DisplayType display, int decimal_places, bool autotrim_decimal_places)
{
switch (display) {
@@ -110,24 +99,15 @@ QString FloatSlider::ValueToString(double val, FloatSlider::DisplayType display,
break;
}
QString s = QString::number(val, 'f', decimal_places);
if (autotrim_decimal_places) {
while (s.endsWith('0')
&& s.at(s.size() - 2).isDigit()) {
s = s.left(s.size() - 1);
}
}
return s;
return FloatToString(val, decimal_places, autotrim_decimal_places);
}
QString FloatSlider::ValueToString(const QVariant &v)
QString FloatSlider::ValueToString(const QVariant &v) const
{
return ValueToString(v.toDouble() + GetOffset().toDouble(), display_type_, decimal_places_, autotrim_decimal_places_);
return ValueToString(v.toDouble() + GetOffset().toDouble(), display_type_, GetDecimalPlaces(), GetAutoTrimDecimalPlaces());
}
QVariant FloatSlider::StringToValue(const QString &s, bool *ok)
QVariant FloatSlider::StringToValue(const QString &s, bool *ok) const
{
switch (display_type_) {
case kNormal:
@@ -171,7 +151,7 @@ QVariant FloatSlider::StringToValue(const QString &s, bool *ok)
return s.toDouble(ok) - GetOffset().toDouble();
}
double FloatSlider::AdjustDragDistanceInternal(const double &start, const double &drag)
QVariant FloatSlider::AdjustDragDistanceInternal(const QVariant &start, const double &drag) const
{
switch (display_type_) {
case kNormal:
@@ -179,22 +159,22 @@ double FloatSlider::AdjustDragDistanceInternal(const double &start, const double
break;
case kDecibel:
{
double current_db = LinearToDecibel(start);
double current_db = LinearToDecibel(start.toDouble());
current_db += drag;
double adjusted_linear = DecibelToLinear(current_db);
return adjusted_linear;
}
case kPercentage:
return SliderBase::AdjustDragDistanceInternal(start, drag * 0.01);
return super::AdjustDragDistanceInternal(start, drag * 0.01);
}
return SliderBase::AdjustDragDistanceInternal(start, drag);
return super::AdjustDragDistanceInternal(start, drag);
}
void FloatSlider::ConvertValue(QVariant v)
void FloatSlider::ValueSignalEvent(const QVariant &value)
{
emit ValueChanged(v.toDouble());
emit ValueChanged(value.toDouble());
}
double FloatSlider::LinearToDecibel(double linear)
+10 -17
View File
@@ -21,11 +21,11 @@
#ifndef FLOATSLIDER_H
#define FLOATSLIDER_H
#include "sliderbase.h"
#include "base/decimalsliderbase.h"
namespace olive {
class FloatSlider : public SliderBase
class FloatSlider : public DecimalSliderBase
{
Q_OBJECT
public:
@@ -37,35 +37,32 @@ public:
kPercentage
};
double GetValue();
double GetValue() const;
void SetValue(const double& d);
void SetDefaultValue(const double& d);
void SetMinimum(const double& d);
void SetMaximum(const double& d);
void SetDecimalPlaces(int i);
void SetDisplayType(const DisplayType& type);
void SetAutoTrimDecimalPlaces(bool e);
static QString ValueToString(double val, DisplayType display, int decimal_places, bool autotrim_decimal_places);
protected:
virtual QString ValueToString(const QVariant& v) override;
virtual QString ValueToString(const QVariant& v) const override;
virtual QVariant StringToValue(const QString& s, bool* ok) override;
virtual QVariant StringToValue(const QString& s, bool* ok) const override;
virtual double AdjustDragDistanceInternal(const double& start, const double& drag) override;
virtual QVariant AdjustDragDistanceInternal(const QVariant &start, const double &drag) const override;
virtual void ValueSignalEvent(const QVariant &value) override;
signals:
void ValueChanged(double);
private slots:
void ConvertValue(QVariant v);
private:
static double LinearToDecibel(double linear);
@@ -73,10 +70,6 @@ private:
DisplayType display_type_;
int decimal_places_;
bool autotrim_decimal_places_;
};
}
+19 -9
View File
@@ -22,22 +22,22 @@
namespace olive {
#define super NumericSliderBase
IntegerSlider::IntegerSlider(QWidget* parent) :
SliderBase(kInteger, parent)
super(parent)
{
SetValue(0);
connect(this, SIGNAL(ValueChanged(QVariant)), this, SLOT(ConvertValue(QVariant)));
}
int64_t IntegerSlider::GetValue()
{
return Value().toLongLong();
return GetValueInternal().toLongLong();
}
void IntegerSlider::SetValue(const int64_t &v)
{
SliderBase::SetValue(QVariant::fromValue(v));
SetValueInternal(QVariant::fromValue(v));
}
void IntegerSlider::SetMinimum(const int64_t &d)
@@ -50,12 +50,17 @@ void IntegerSlider::SetMaximum(const int64_t &d)
SetMaximumInternal(QVariant::fromValue(d));
}
QString IntegerSlider::ValueToString(const QVariant &v)
void IntegerSlider::SetDefaultValue(const int64_t &d)
{
super::SetDefaultValue(QVariant::fromValue(d));
}
QString IntegerSlider::ValueToString(const QVariant &v) const
{
return QString::number(v.toLongLong() + GetOffset().toLongLong());
}
QVariant IntegerSlider::StringToValue(const QString &s, bool *ok)
QVariant IntegerSlider::StringToValue(const QString &s, bool *ok) const
{
bool valid;
@@ -76,9 +81,14 @@ QVariant IntegerSlider::StringToValue(const QString &s, bool *ok)
return QVariant();
}
void IntegerSlider::ConvertValue(QVariant v)
void IntegerSlider::ValueSignalEvent(const QVariant &value)
{
emit ValueChanged(v.toInt());
emit ValueChanged(value.toInt());
}
QVariant IntegerSlider::AdjustDragDistanceInternal(const QVariant &start, const double &drag) const
{
return qRound64(super::AdjustDragDistanceInternal(start, drag).toDouble());
}
}
+11 -7
View File
@@ -21,11 +21,11 @@
#ifndef INTEGERSLIDER_H
#define INTEGERSLIDER_H
#include "sliderbase.h"
#include "base/numericsliderbase.h"
namespace olive {
class IntegerSlider : public SliderBase
class IntegerSlider : public NumericSliderBase
{
Q_OBJECT
public:
@@ -39,16 +39,20 @@ public:
void SetMaximum(const int64_t& d);
protected:
virtual QString ValueToString(const QVariant& v) override;
void SetDefaultValue(const int64_t& d);
virtual QVariant StringToValue(const QString& s, bool* ok) override;
protected:
virtual QString ValueToString(const QVariant& v) const override;
virtual QVariant StringToValue(const QString& s, bool* ok) const override;
virtual void ValueSignalEvent(const QVariant &value) override;
virtual QVariant AdjustDragDistanceInternal(const QVariant &start, const double &drag) const override;
signals:
void ValueChanged(int64_t);
private slots:
void ConvertValue(QVariant v);
};
}
+99 -81
View File
@@ -1,16 +1,21 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "rationalslider.h"
@@ -22,40 +27,33 @@
namespace olive {
#define super DecimalSliderBase
RationalSlider::RationalSlider(QWidget *parent) :
SliderBase(SliderBase::kRational, parent),
display_type_(kTimecode),
decimal_places_(2),
autotrim_decimal_places_(false),
super(parent),
lock_display_type_(false)
{
connect(this, SIGNAL(ValueChanged(QVariant)), this, SLOT(ConvertValue(QVariant)));
connect(Core::instance(), &Core::TimecodeDisplayChanged, this, &RationalSlider::ChangeTimecodeDisplayType);
connect(SliderBase::label(), &SliderLabel::customContextMenuRequested, this, &RationalSlider::changeDisplayType);
connect(Core::instance(), &Core::TimecodeDisplayChanged, this, &RationalSlider::UpdateLabel);
connect(SliderBase::label(), &SliderLabel::customContextMenuRequested, this, &RationalSlider::ShowDisplayTypeMenu);
SetDisplayType(display_type_);
SetDisplayType(kFloat);
SetValue(rational(0, 0));
}
rational RationalSlider::GetValue()
{
return Value().value<rational>();
return GetValueInternal().value<rational>();
}
void RationalSlider::SetValue(const rational &d)
{
SliderBase::SetValue(QVariant::fromValue(d));
SetValueInternal(QVariant::fromValue(d));
}
void RationalSlider::SetDefaultValue(const rational &r)
{
SliderBase::SetDefaultValue(QVariant::fromValue(r));
}
void RationalSlider::SetDefaultValue(const QVariant &v) {
rational r = v.value<rational>();
SetDefaultValue(r);
super::SetDefaultValue(QVariant::fromValue(r));
}
void RationalSlider::SetMinimum(const rational &d)
@@ -68,42 +66,19 @@ void RationalSlider::SetMaximum(const rational &d)
SetMaximumInternal(QVariant::fromValue(d));
}
void RationalSlider::SetDecimalPlaces(int i)
{
decimal_places_ = i;
ForceLabelUpdate();
}
void RationalSlider::SetTimebase(const rational &timebase)
{
timebase_ = timebase;
// Refresh label since we have a new timebase to generate a timecode with
UpdateLabel(Value());
}
void RationalSlider::SetAutoTrimDecimalPlaces(bool e) {
autotrim_decimal_places_ = e;
ForceLabelUpdate();
UpdateLabel();
}
void RationalSlider::SetDisplayType(const RationalSlider::DisplayType &type)
{
display_type_ = type;
switch (display_type_) {
case kTimecode:
ClearFormat();
break;
case kTimestamp:
SetFormat("%1 Frames");
break;
case kFloat:
SetFormat("%1 s");
break;
}
UpdateLabel();
}
void RationalSlider::SetLockDisplayType(bool e)
@@ -111,87 +86,130 @@ void RationalSlider::SetLockDisplayType(bool e)
lock_display_type_ = e;
}
bool RationalSlider::LockDisplayType()
bool RationalSlider::GetLockDisplayType()
{
return lock_display_type_;
}
QString RationalSlider::ValueToString(const QVariant &v)
void RationalSlider::DisableDisplayType(RationalSlider::DisplayType type)
{
double time = v.value<rational>().toDouble() + GetOffset().value<rational>().toDouble();
disabled_.append(type);
}
QString RationalSlider::ValueToString(const QVariant &v) const
{
double val = v.value<rational>().toDouble() + GetOffset().value<rational>().toDouble();
switch (display_type_) {
case kTimecode:
case kTime:
return Timecode::time_to_timecode(v.value<rational>(), timebase_, Core::instance()->GetTimecodeDisplay());
case kTimestamp:
return QString::number(Timecode::time_to_timestamp(time, timebase_));
case kFloat:
{
QString s = QString::number(time, 'f', decimal_places_);
return FloatToString(val, GetDecimalPlaces(), GetAutoTrimDecimalPlaces());
case kRational:
return v.value<rational>().toString();
}
if (autotrim_decimal_places_) {
while (s.endsWith('0') && s.at(s.size() - 2).isDigit()) {
s = s.left(s.size() - 1);
}
}
return s;
}
}
return v.toString();
}
QVariant RationalSlider::StringToValue(const QString &s, bool *ok)
QVariant RationalSlider::StringToValue(const QString &s, bool *ok) const
{
rational r;
*ok = false;
switch (display_type_) {
case kTimecode:
case kTime:
{
int t = Timecode::timecode_to_timestamp(s, timebase_, Core::instance()->GetTimecodeDisplay(), ok);
r = rational(t, timebase_.denominator());
r = Timecode::timecode_to_time(s, timebase_, Core::instance()->GetTimecodeDisplay(), ok);
break;
}
case kTimestamp:
r = rational(s.toInt(ok), timebase_.denominator());
break;
case kFloat:
r = rational::fromDouble(s.toDouble(ok));
if (!r.isNull()) {
*ok = true;
}
{
// First, convert to a double
double d = s.toDouble(ok);
if (!(*ok)) {
break;
}
return QVariant::fromValue(r - GetOffset().value<rational>());
// If double conversion succeeded, convert to a rational
r = rational::fromDouble(d, ok);
break;
}
case kRational:
r = rational::fromString(s, ok);
break;
}
//return QVariant::fromValue(r - GetOffset().value<rational>());
return QVariant::fromValue(r);
}
double RationalSlider::AdjustDragDistanceInternal(const double &start, const double &drag)
QVariant RationalSlider::AdjustDragDistanceInternal(const QVariant &start, const double &drag) const
{
// Assume we want smallest increment to be timebase or 1 frame
return start + drag*timebase_.toDouble();
return QVariant::fromValue(start.value<rational>() + rational::fromDouble(drag)*timebase_);
}
void RationalSlider::ConvertValue(QVariant v)
void RationalSlider::ValueSignalEvent(const QVariant &v)
{
emit ValueChanged(v.value<rational>());
}
void RationalSlider::changeDisplayType()
bool RationalSlider::ValueGreaterThan(const QVariant &lhs, const QVariant &rhs) const
{
if (!LockDisplayType()) {
Menu m(this);
MenuShared::instance()->AddItemsForTimeRulerMenu(&m, timebase_);
MenuShared::instance()->AboutToShowTimeRulerActions();
return lhs.value<rational>() > rhs.value<rational>();
}
bool RationalSlider::ValueLessThan(const QVariant &lhs, const QVariant &rhs) const
{
return lhs.value<rational>() < rhs.value<rational>();
}
void RationalSlider::ShowDisplayTypeMenu()
{
Menu m(this);
if (!GetLockDisplayType()) {
if (!disabled_.contains(kFloat)) {
QAction* float_action = m.addAction(tr("Float"));
float_action->setData(kFloat);
connect(float_action, &QAction::triggered, this, &RationalSlider::SetDisplayTypeFromMenu);
}
if (!disabled_.contains(kRational)) {
QAction* rational_action = m.addAction(tr("Rational"));
rational_action->setData(kRational);
connect(rational_action, &QAction::triggered, this, &RationalSlider::SetDisplayTypeFromMenu);
}
if (!disabled_.contains(kTime)) {
QAction* time_action = m.addAction(tr("Time"));
time_action->setData(kTime);
connect(time_action, &QAction::triggered, this, &RationalSlider::SetDisplayTypeFromMenu);
}
}
if (display_type_ == kTime) {
if (!m.actions().isEmpty()) {
m.addSeparator();
}
MenuShared::instance()->AddItemsForTimeRulerMenu(&m);
MenuShared::instance()->AboutToShowTimeRulerActions(timebase_);
}
if (!m.actions().isEmpty()) {
m.exec(QCursor::pos());
ForceLabelUpdate();
UpdateLabel();
}
}
void RationalSlider::ChangeTimecodeDisplayType()
void RationalSlider::SetDisplayTypeFromMenu()
{
ForceLabelUpdate();
QAction* action = static_cast<QAction*>(sender());
DisplayType type = static_cast<DisplayType>(action->data().toInt());
SetDisplayType(type);
}
}
+30 -33
View File
@@ -1,25 +1,29 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef RATIONALSLIDER_H
#define RATIONALSLIDER_H
#include "sliderbase.h"
#include <QMouseEvent>
#include "base/decimalsliderbase.h"
#include "common/rational.h"
namespace olive {
@@ -30,7 +34,7 @@ namespace olive {
* A slider that can display rationals as either timecode (drop or non-drop), a timestamp (frames),
* or a float (seconds).
*/
class RationalSlider : public SliderBase
class RationalSlider : public DecimalSliderBase
{
Q_OBJECT
public:
@@ -38,9 +42,9 @@ public:
* @brief enum containing the possibly display types
*/
enum DisplayType {
kTimecode,
kTimestamp,
kFloat
kTime,
kFloat,
kRational
};
RationalSlider(QWidget* parent = nullptr);
@@ -60,11 +64,6 @@ public:
*/
void SetDefaultValue(const rational& r);
/**
* @brief Sets the sliders default value
*/
void SetDefaultValue(const QVariant& v);
/**
* @brief Sets the sliders minimum value
*/
@@ -75,11 +74,6 @@ public:
*/
void SetMaximum(const rational& d);
/**
* @brief Sets the number of decimal places the slider shows when displaying a float
*/
void SetDecimalPlaces(int i);
/**
* @brief Sets the sliders timebase which is also the minimum increment of the slider
*/
@@ -98,40 +92,43 @@ public:
/**
* @brief Get whether the user can change the display type or not
*/
bool LockDisplayType();
bool GetLockDisplayType();
void SetAutoTrimDecimalPlaces(bool e);
/**
* @brief Hide display type in menu
*/
void DisableDisplayType(DisplayType type);
protected:
virtual QString ValueToString(const QVariant& v) override;
virtual QString ValueToString(const QVariant& v) const override;
virtual QVariant StringToValue(const QString& s, bool* ok) override;
virtual QVariant StringToValue(const QString& s, bool* ok) const override;
virtual double AdjustDragDistanceInternal(const double& start, const double& drag) override;
virtual QVariant AdjustDragDistanceInternal(const QVariant &start, const double &drag) const override;
virtual void ValueSignalEvent(const QVariant& v) override;
virtual bool ValueGreaterThan(const QVariant& lhs, const QVariant& rhs) const override;
virtual bool ValueLessThan(const QVariant& lhs, const QVariant& rhs) const override;
signals:
void ValueChanged(rational);
private slots:
void ConvertValue(QVariant v);
void ShowDisplayTypeMenu();
void changeDisplayType();
/**
* @brief Changes the timecodes display type (e.g. drop frome to none drop frame)
*/
void ChangeTimecodeDisplayType();
void SetDisplayTypeFromMenu();
private:
DisplayType display_type_;
int decimal_places_;
bool autotrim_decimal_places_;
rational timebase_;
bool lock_display_type_;
QVector<DisplayType> disabled_;
};
}
-470
View File
@@ -1,470 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "sliderbase.h"
#include <QDebug>
#include <QEvent>
#include <QMessageBox>
#include "common/qtutils.h"
#include "core.h"
#include "window/mainwindow/mainwindow.h"
namespace olive {
SliderBase::SliderBase(Mode mode, QWidget *parent) :
QStackedWidget(parent),
drag_multiplier_(1.0),
has_min_(false),
has_max_(false),
mode_(mode),
dragged_diff_(0),
require_valid_input_(true),
tristate_(false),
format_plural_(false),
drag_ladder_(nullptr),
ladder_element_count_(0),
dragged_(false)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
label_ = new SliderLabel(this);
addWidget(label_);
editor_ = new FocusableLineEdit(this);
addWidget(editor_);
connect(label_, &SliderLabel::LabelPressed, this, &SliderBase::LabelPressed);
connect(label_, &SliderLabel::focused, this, &SliderBase::ShowEditor);
connect(label_, &SliderLabel::RequestReset, this, &SliderBase::ResetValue);
connect(editor_, &FocusableLineEdit::Confirmed, this, &SliderBase::LineEditConfirmed);
connect(editor_, &FocusableLineEdit::Cancelled, this, &SliderBase::LineEditCancelled);
// Set valid cursor based on mode
switch (mode_) {
case kString:
setCursor(Qt::PointingHandCursor);
break;
case kInteger:
case kFloat:
case kRational:
setCursor(Qt::SizeHorCursor);
break;
}
}
void SliderBase::SetDragMultiplier(const double &d)
{
drag_multiplier_ = d;
}
void SliderBase::SetRequireValidInput(bool e)
{
require_valid_input_ = e;
}
void SliderBase::SetAlignment(Qt::Alignment alignment)
{
label_->setAlignment(alignment);
}
bool SliderBase::IsTristate() const
{
return tristate_;
}
void SliderBase::SetTristate()
{
tristate_ = true;
UpdateLabel(0);
}
bool SliderBase::IsDragging() const
{
return drag_ladder_;
}
void SliderBase::SetFormat(const QString &s, const bool plural)
{
custom_format_ = s;
format_plural_ = plural;
ForceLabelUpdate();
}
void SliderBase::ClearFormat()
{
custom_format_.clear();
ForceLabelUpdate();
}
bool SliderBase::IsFormatPlural() const
{
return format_plural_;
}
void SliderBase::ForceLabelUpdate()
{
UpdateLabel(Value());
}
const QVariant &SliderBase::Value() const
{
if (IsDragging()) {
return clamped_temp_dragged_value_;
}
return value_;
}
void SliderBase::SetValue(const QVariant &v)
{
if (IsDragging()) {
return;
}
value_ = ClampValue(v);
// Disable tristate
tristate_ = false;
UpdateLabel(value_);
}
void SliderBase::SetDefaultValue(const QVariant &v)
{
default_value_ = v;
}
void SliderBase::SetOffset(const QVariant &v)
{
offset_ = v;
UpdateLabel(value_);
}
void SliderBase::SetMinimumInternal(const QVariant &v)
{
min_value_ = v;
has_min_ = true;
// Limit value by this new minimum value
if (mode_ == kRational) {
if (value_.value<rational>().toDouble() < min_value_.value<rational>().toDouble()) {
SetValue(min_value_);
}
} else {
if (value_.toDouble() < min_value_.toDouble()) {
SetValue(min_value_);
}
}
}
void SliderBase::SetMaximumInternal(const QVariant &v)
{
max_value_ = v;
has_max_ = true;
// Limit value by this new maximum value
if (mode_ == kRational) {
if (value_.value<rational>().toDouble() > max_value_.value<rational>().toDouble()) {
SetValue(max_value_);
}
} else {
if (value_.toDouble() > max_value_.toDouble()) {
SetValue(max_value_);
}
}
}
void SliderBase::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
UpdateLabel(value_);
}
QStackedWidget::changeEvent(e);
}
const QVariant &SliderBase::ClampValue(const QVariant &v)
{
double value, min, max;
if (mode_ == kRational) {
value = v.value<rational>().toDouble();
min = min_value_.value<rational>().toDouble();
max = max_value_.value<rational>().toDouble();
} else {
value = v.toDouble();
min = min_value_.toDouble();
max = max_value_.toDouble();
}
if (has_min_ && value < min) {
return min_value_;
}else if (has_max_ && value > max) {
return max_value_;
}
return v;
}
QString SliderBase::GetFormat() const
{
if (custom_format_.isEmpty()) {
return QStringLiteral("%1");
} else {
return custom_format_;
}
}
bool SliderBase::UsingLadders() const
{
return ladder_element_count_ > 0 && Config::Current()[QStringLiteral("UseSliderLadders")].toBool();
}
void SliderBase::UpdateLabel(const QVariant &v)
{
if (tristate_) {
label_->setText("---");
} else if (format_plural_) {
label_->setText(tr(GetFormat().toUtf8().constData(), nullptr, v.toInt()));
} else {
label_->setText(GetFormat().arg(ValueToString(v)));
}
}
double SliderBase::AdjustDragDistanceInternal(const double &start, const double &drag)
{
return start + drag;
}
QString SliderBase::ValueToString(const QVariant &v)
{
return v.toString();
}
QVariant SliderBase::StringToValue(const QString &s, bool *ok)
{
*ok = true;
return s;
}
void SliderBase::ShowEditor()
{
// This was a simple click
// Load label's text into editor
editor_->setText(ValueToString(value_));
// Show editor
setCurrentWidget(editor_);
// Select all text in the editor
editor_->setFocus();
editor_->selectAll();
}
void SliderBase::LabelPressed()
{
switch (mode_) {
case kString:
// No dragging supported for strings
break;
case kInteger:
case kFloat:
case kRational:
{
if (mode_ == kRational) {
drag_ladder_ = new SliderLadder(drag_multiplier_, ladder_element_count_, "00:00:00:00");
} else {
drag_ladder_ = new SliderLadder(drag_multiplier_, ladder_element_count_, "00000000");
}
drag_ladder_->SetValue(ValueToString(value_));
drag_ladder_->show();
QMetaObject::invokeMethod(this, "RepositionLadder", Qt::QueuedConnection);
connect(drag_ladder_, &SliderLadder::DraggedByValue, this, &SliderBase::LadderDragged);
connect(drag_ladder_, &SliderLadder::Released, this, &SliderBase::LadderReleased);
break;
}
}
}
void SliderBase::LadderDragged(int value, double multiplier)
{
dragged_ = true;
switch (mode_) {
case kString:
// No dragging supported for strings
break;
case kInteger:
case kFloat:
{
dragged_diff_ += value * drag_multiplier_ * multiplier;
double drag_val = AdjustDragDistanceInternal(value_.toDouble(), dragged_diff_);
// Update temporary value
if (mode_ == kInteger) {
temp_dragged_value_ = qRound(drag_val);
} else {
temp_dragged_value_ = drag_val;
}
clamped_temp_dragged_value_ = ClampValue(temp_dragged_value_);
UpdateLabel(clamped_temp_dragged_value_);
drag_ladder_->SetValue(ValueToString(clamped_temp_dragged_value_));
if (!UsingLadders()) {
RepositionLadder();
}
emit ValueChanged(clamped_temp_dragged_value_);
break;
}
case kRational:
{
dragged_diff_ += value * drag_multiplier_ * multiplier;
double drag_val = AdjustDragDistanceInternal(value_.value<rational>().toDouble(), dragged_diff_);
rational d_v;
d_v = rational::fromDouble(drag_val);
temp_dragged_value_.setValue(d_v);
clamped_temp_dragged_value_ = ClampValue(temp_dragged_value_);
UpdateLabel(temp_dragged_value_);
drag_ladder_->SetValue(ValueToString(clamped_temp_dragged_value_));
if (!Config::Current()[QStringLiteral("UseSliderLadders")].toBool()) {
RepositionLadder();
}
emit ValueChanged(clamped_temp_dragged_value_);
break;
}
}
}
void SliderBase::LadderReleased()
{
drag_ladder_->deleteLater();
drag_ladder_ = nullptr;
dragged_diff_ = 0;
if (dragged_) {
// This was a drag
switch (mode_) {
case kString:
// No-op
break;
case kInteger:
SetValue(clamped_temp_dragged_value_.toInt());
break;
case kFloat:
SetValue(clamped_temp_dragged_value_.toDouble());
break;
case kRational:
SetValue(temp_dragged_value_);
}
emit ValueChanged(value_);
dragged_ = false;
} else {
ShowEditor();
}
}
void SliderBase::LineEditConfirmed()
{
bool is_valid = true;
QVariant test_val = StringToValue(editor_->text(), &is_valid);
// Ensure editor doesn't signal that the focus is lost
editor_->blockSignals(true);
label_->blockSignals(true);
if (is_valid) {
SetValue(test_val);
setCurrentWidget(label_);
emit ValueChanged(value_);
} else if (require_valid_input_ && !IsTristate()) {
QMessageBox::critical(this,
tr("Invalid Value"),
tr("The entered value is not valid for this field."),
QMessageBox::Ok);
// Refocus editor
editor_->setFocus();
}
editor_->blockSignals(false);
label_->blockSignals(false);
}
void SliderBase::LineEditCancelled()
{
// Ensure editor doesn't signal that the focus is lost
editor_->blockSignals(true);
label_->blockSignals(true);
// Set widget back to label
setCurrentWidget(label_);
editor_->blockSignals(false);
label_->blockSignals(false);
}
void SliderBase::ResetValue()
{
if (!default_value_.isNull()) {
SetValue(default_value_);
emit ValueChanged(value_);
}
}
void SliderBase::RepositionLadder()
{
if (drag_ladder_) {
if (UsingLadders()) {
drag_ladder_->move(QCursor::pos() - QPoint(drag_ladder_->width()/2, drag_ladder_->height()/2));
} else {
QPoint label_global_pos = label_->mapToGlobal(label_->pos());
int text_width = QtUtils::QFontMetricsWidth(label_->fontMetrics(), label_->text());
int ladder_x = label_global_pos.x() + text_width / 2 - drag_ladder_->width() / 2;
int ladder_y = label_global_pos.y() + label_->height() / 2 - drag_ladder_->height() / 2;
drag_ladder_->move(ladder_x, ladder_y);
}
drag_ladder_->StartListeningToMouseInput();
}
}
}
+21 -8
View File
@@ -22,33 +22,46 @@
namespace olive {
#define super SliderBase
StringSlider::StringSlider(QWidget* parent) :
SliderBase(kString, parent)
super(parent)
{
SetValue(QString());
connect(this, SIGNAL(ValueChanged(QVariant)), this, SLOT(ConvertValue(QVariant)));
connect(label(), &SliderLabel::LabelReleased, this, &SliderBase::ShowEditor);
}
QString StringSlider::GetValue()
QString StringSlider::GetValue() const
{
return Value().toString();
return GetValueInternal().toString();
}
void StringSlider::SetValue(const QString &v)
{
SliderBase::SetValue(v);
SetValueInternal(v);
}
QString StringSlider::ValueToString(const QVariant &v)
void StringSlider::SetDefaultValue(const QString &v)
{
super::SetDefaultValue(v);
}
QString StringSlider::ValueToString(const QVariant &v) const
{
QString vstr = v.toString();
return (vstr.isEmpty()) ? tr("(none)") : vstr;
}
void StringSlider::ConvertValue(QVariant v)
QVariant StringSlider::StringToValue(const QString &s, bool *ok) const
{
emit ValueChanged(v.toString());
*ok = true;
return s;
}
void StringSlider::ValueSignalEvent(const QVariant &value)
{
emit ValueChanged(value.toString());
}
}
+11 -7
View File
@@ -21,7 +21,7 @@
#ifndef STRINGSLIDER_H
#define STRINGSLIDER_H
#include "sliderbase.h"
#include "base/sliderbase.h"
namespace olive {
@@ -33,18 +33,22 @@ public:
void SetDragMultiplier(const double& d) = delete;
QString GetValue();
QString GetValue() const;
void SetValue(const QString& v);
protected:
virtual QString ValueToString(const QVariant& value) override;
void SetDefaultValue(const QString& v);
signals:
void ValueChanged(QString);
void ValueChanged(const QString& str);
protected:
virtual QString ValueToString(const QVariant& value) const override;
virtual QVariant StringToValue(const QString &s, bool *ok) const override;
virtual void ValueSignalEvent(const QVariant &value) override;
private slots:
void ConvertValue(QVariant v);
};
}
+8 -12
View File
@@ -25,13 +25,14 @@
namespace olive {
#define super IntegerSlider
TimeSlider::TimeSlider(QWidget *parent) :
IntegerSlider(parent)
super(parent)
{
SetMinimum(0);
SetValue(0);
connect(Core::instance(), &Core::TimecodeDisplayChanged, this, &TimeSlider::TimecodeDisplayChanged);
connect(Core::instance(), &Core::TimecodeDisplayChanged, this, &TimeSlider::UpdateLabel);
}
void TimeSlider::SetTimebase(const rational &timebase)
@@ -39,14 +40,14 @@ void TimeSlider::SetTimebase(const rational &timebase)
timebase_ = timebase;
// Refresh label since we have a new timebase to generate a timecode with
UpdateLabel(Value());
UpdateLabel();
}
QString TimeSlider::ValueToString(const QVariant &v)
QString TimeSlider::ValueToString(const QVariant &v) const
{
if (timebase_.isNull()) {
// We can't generate a timecode without a timebase, so we just return the number
return IntegerSlider::ValueToString(v);
return super::ValueToString(v);
}
return Timecode::timestamp_to_timecode(v.toLongLong() + GetOffset().toLongLong(),
@@ -54,14 +55,9 @@ QString TimeSlider::ValueToString(const QVariant &v)
Core::instance()->GetTimecodeDisplay());
}
QVariant TimeSlider::StringToValue(const QString &s, bool *ok)
QVariant TimeSlider::StringToValue(const QString &s, bool *ok) const
{
return QVariant::fromValue(Timecode::timecode_to_timestamp(s, timebase_, Core::instance()->GetTimecodeDisplay(), ok) - GetOffset().toLongLong());
}
void TimeSlider::TimecodeDisplayChanged()
{
UpdateLabel(Value());
}
}
+2 -5
View File
@@ -35,16 +35,13 @@ public:
void SetTimebase(const rational& timebase);
protected:
virtual QString ValueToString(const QVariant& v) override;
virtual QString ValueToString(const QVariant& v) const override;
virtual QVariant StringToValue(const QString& s, bool* ok) override;
virtual QVariant StringToValue(const QString& s, bool* ok) const override;
private:
rational timebase_;
private slots:
void TimecodeDisplayChanged();
};
}
+2 -2
View File
@@ -306,8 +306,8 @@ void TimeRuler::ShowContextMenu()
{
Menu m(this);
MenuShared::instance()->AddItemsForTimeRulerMenu(&m, timebase());
MenuShared::instance()->AboutToShowTimeRulerActions();
MenuShared::instance()->AddItemsForTimeRulerMenu(&m);
MenuShared::instance()->AboutToShowTimeRulerActions(timebase());
m.exec(QCursor::pos());
}
+8 -6
View File
@@ -97,11 +97,13 @@ VideoParamEdit::VideoParamEdit(QWidget* parent) :
connect(frame_rate_combobox_, static_cast<void (FrameRateComboBox::*)(int)>(&FrameRateComboBox::currentIndexChanged), this, &VideoParamEdit::Changed);
layout->addWidget(frame_rate_combobox_, row, 1);
// FIXME: Replace with rational slider
frame_rate_slider_ = new FloatSlider();
frame_rate_slider_ = new RationalSlider();
frame_rate_slider_->SetMinimum(0);
frame_rate_slider_->SetDecimalPlaces(2);
connect(frame_rate_slider_, &FloatSlider::ValueChanged, this, &VideoParamEdit::Changed);
frame_rate_slider_->SetDecimalPlaces(3);
frame_rate_slider_->SetAutoTrimDecimalPlaces(true);
frame_rate_slider_->SetTimebase(rational(1, 1000)); // Drag interval
frame_rate_slider_->DisableDisplayType(RationalSlider::kTime);
connect(frame_rate_slider_, &RationalSlider::ValueChanged, this, &VideoParamEdit::Changed);
layout->addWidget(frame_rate_slider_, row, 1);
row++;
@@ -277,7 +279,7 @@ VideoParams VideoParamEdit::GetVideoParams() const
rational using_frame_rate;
if (mask_ & kFrameRateIsArbitrary) {
using_frame_rate = rational::fromDouble(frame_rate_slider_->GetValue());
using_frame_rate = frame_rate_slider_->GetValue();
} else {
using_frame_rate = frame_rate_combobox_->GetFrameRate();
}
@@ -316,7 +318,7 @@ void VideoParamEdit::SetVideoParams(const VideoParams &p)
depth_slider_->SetValue(p.depth());
frame_rate_combobox_->SetFrameRate(p.frame_rate());
frame_rate_slider_->SetValue(p.frame_rate().toDouble());
frame_rate_slider_->SetValue(p.frame_rate());
timebase_temp_ = p.time_base();
pixel_aspect_combobox_->SetPixelAspectRatio(p.pixel_aspect_ratio());
+2 -2
View File
@@ -27,8 +27,8 @@
#include "node/color/colormanager/colormanager.h"
#include "render/videoparams.h"
#include "widget/slider/floatslider.h"
#include "widget/slider/integerslider.h"
#include "widget/slider/rationalslider.h"
#include "widget/standardcombos/frameratecombobox.h"
#include "widget/standardcombos/interlacedcombobox.h"
#include "widget/standardcombos/pixelaspectratiocombobox.h"
@@ -145,7 +145,7 @@ private:
IntegerSlider* depth_slider_;
QLabel* frame_rate_lbl_;
FrameRateComboBox* frame_rate_combobox_;
FloatSlider* frame_rate_slider_;
RationalSlider* frame_rate_slider_;
QLabel* pixel_aspect_lbl_;
PixelAspectRatioComboBox* pixel_aspect_combobox_;
QLabel* interlaced_lbl_;
+2 -2
View File
@@ -308,12 +308,12 @@ void MainMenu::ViewMenuAboutToShow()
if (p) {
if (p->timebase().denominator() != 0) {
view_menu_->addSeparator();
MenuShared::instance()->AddItemsForTimeRulerMenu(view_menu_, p->timebase());
MenuShared::instance()->AddItemsForTimeRulerMenu(view_menu_);
}
}
// Ensure checked timecode display mode is correct
MenuShared::instance()->AboutToShowTimeRulerActions();
MenuShared::instance()->AboutToShowTimeRulerActions(p->timebase());
}
void MainMenu::ToolsMenuAboutToShow()