369 lines
8.6 KiB
C++
369 lines
8.6 KiB
C++
/***
|
|
|
|
Olive - Non-Linear Video Editor
|
|
Copyright (C) 2019 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 "labelslider.h"
|
|
|
|
#include <QMouseEvent>
|
|
#include <QInputDialog>
|
|
#include <QApplication>
|
|
#include <QMenu>
|
|
|
|
#include "undo/undo.h"
|
|
#include "panels/viewer.h"
|
|
#include "global/config.h"
|
|
#include "global/math.h"
|
|
#include "global/debug.h"
|
|
#include "ui/styling.h"
|
|
#include "ui/menu.h"
|
|
|
|
LabelSlider::LabelSlider(QWidget* parent) : QLabel(parent) {
|
|
// set a default frame rate - fallback, shouldn't ever really be used
|
|
frame_rate = 30;
|
|
|
|
decimal_places = 1;
|
|
drag_start = false;
|
|
drag_proc = false;
|
|
min_enabled = false;
|
|
max_enabled = false;
|
|
SetColor();
|
|
SetDefaultCursor();
|
|
internal_value = -1;
|
|
set = false;
|
|
display_type = Normal;
|
|
|
|
SetDefault(0);
|
|
|
|
setContextMenuPolicy(Qt::CustomContextMenu);
|
|
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(ShowContextMenu(const QPoint&)));
|
|
}
|
|
|
|
void LabelSlider::SetFrameRate(double d) {
|
|
frame_rate = d;
|
|
}
|
|
|
|
void LabelSlider::SetDecimalPlaces(int places)
|
|
{
|
|
decimal_places = places;
|
|
}
|
|
|
|
void LabelSlider::SetDisplayType(const DisplayType& type) {
|
|
display_type = type;
|
|
setText(ValueToString());
|
|
}
|
|
|
|
void LabelSlider::SetValue(double v) {
|
|
set = true;
|
|
if (!qFuzzyCompare(v, internal_value)) {
|
|
if (min_enabled && v < min_value) {
|
|
internal_value = min_value;
|
|
} else if (max_enabled && v > max_value) {
|
|
internal_value = max_value;
|
|
} else {
|
|
internal_value = v;
|
|
}
|
|
|
|
setText(ValueToString());
|
|
}
|
|
}
|
|
|
|
bool LabelSlider::IsDragging() {
|
|
return drag_proc;
|
|
}
|
|
|
|
QString LabelSlider::ValueToString() {
|
|
double v = internal_value;
|
|
if (qIsNaN(v)) {
|
|
return "---";
|
|
} else {
|
|
switch (display_type) {
|
|
case FrameNumber:
|
|
return frame_to_timecode(long(v), olive::CurrentConfig.timecode_view, frame_rate);
|
|
case Percent:
|
|
return QString::number((v*100), 'f', decimal_places).append("%");
|
|
case Decibel:
|
|
{
|
|
QString db_str;
|
|
|
|
// -96 dB is considered -infinity
|
|
if (amplitude_to_db(v) <= -96) {
|
|
// hex sequence for -infinity
|
|
db_str = "-\xE2\x88\x9E";
|
|
} else {
|
|
db_str = QString::number(amplitude_to_db(v), 'f', decimal_places);
|
|
}
|
|
|
|
// add "dB" suffix
|
|
db_str.append(" dB");
|
|
|
|
return db_str;
|
|
}
|
|
default:
|
|
return QString::number(v, 'f', decimal_places);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LabelSlider::SetColor(QString c) {
|
|
if (c.isEmpty()) {
|
|
if (olive::styling::UseDarkIcons()) {
|
|
c = "#0080ff";
|
|
} else {
|
|
c = "#ffc000";
|
|
}
|
|
}
|
|
setStyleSheet("QLabel{color:" + c + ";text-decoration:underline;}QLabel:disabled{color:#808080;}");
|
|
}
|
|
|
|
double LabelSlider::value() {
|
|
return internal_value;
|
|
}
|
|
|
|
void LabelSlider::SetDefault(double v) {
|
|
default_value = v;
|
|
if (!set) {
|
|
SetValue(v);
|
|
set = false;
|
|
}
|
|
}
|
|
|
|
void LabelSlider::SetMinimum(double v) {
|
|
min_value = v;
|
|
min_enabled = true;
|
|
}
|
|
|
|
void LabelSlider::SetMaximum(double v) {
|
|
max_value = v;
|
|
max_enabled = true;
|
|
}
|
|
|
|
void LabelSlider::mousePressEvent(QMouseEvent *ev) {
|
|
// if primary button is clicked
|
|
if (ev->button() == Qt::LeftButton && !drag_start) {
|
|
|
|
// store initial value to be compared while dragging
|
|
drag_start_value = internal_value;
|
|
|
|
// alt + click sets labelslider to default value
|
|
if (ev->modifiers() & Qt::AltModifier) {
|
|
|
|
// reset to default
|
|
ResetToDefault();
|
|
|
|
} else {
|
|
|
|
// if value isn't valid, we set to a "default" of 0
|
|
if (qIsNaN(internal_value)) internal_value = 0;
|
|
|
|
// hide the cursor and store information about it for dragging
|
|
SetActiveCursor();
|
|
|
|
drag_start = true;
|
|
drag_start_x = cursor().pos().x();
|
|
drag_start_y = cursor().pos().y();
|
|
}
|
|
|
|
emit clicked();
|
|
|
|
} else {
|
|
|
|
// handler if the user clicks with a non-primary button
|
|
// prevents mouse from getting stuck in "dragging" mode
|
|
mouseReleaseEvent(ev);
|
|
|
|
}
|
|
}
|
|
|
|
void LabelSlider::mouseMoveEvent(QMouseEvent* event) {
|
|
if (drag_start) {
|
|
// if we're dragging
|
|
|
|
// we don't actually start fully dragging until the cursor has moved
|
|
// while the mouse is down, this helps prevent accidental drags
|
|
drag_proc = true;
|
|
|
|
// get amount cursor moved by
|
|
double diff = (cursor().pos().x()-drag_start_x) + (drag_start_y-cursor().pos().y());
|
|
|
|
// ctrl + drag drags in smaller increments
|
|
if (event->modifiers() & Qt::ControlModifier) diff *= 0.01;
|
|
|
|
if (display_type == Percent) {
|
|
// we'll also need to drag in smaller increments for a percent value
|
|
|
|
diff *= 0.01;
|
|
}
|
|
|
|
// determine what the new value will be
|
|
double new_value;
|
|
|
|
if (display_type == Decibel) {
|
|
// we move in terms of dB for decibel display
|
|
|
|
new_value = db_to_amplitude(amplitude_to_db(internal_value) + diff);
|
|
|
|
} else {
|
|
// for most display types, just add the mouse difference
|
|
|
|
new_value = internal_value + diff;
|
|
}
|
|
|
|
// set internal value
|
|
SetValue(new_value);
|
|
emit valueChanged(internal_value);
|
|
|
|
// keep the cursor in the same location while dragging
|
|
cursor().setPos(drag_start_x, drag_start_y);
|
|
}
|
|
}
|
|
|
|
void LabelSlider::mouseReleaseEvent(QMouseEvent*) {
|
|
if (drag_start) {
|
|
|
|
// unhide cursor
|
|
SetDefaultCursor();
|
|
|
|
drag_start = false;
|
|
|
|
if (drag_proc) {
|
|
// if we just finished fully dragging
|
|
|
|
drag_proc = false;
|
|
|
|
emit valueChanged(internal_value);
|
|
|
|
} else {
|
|
|
|
ShowDialog();
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void LabelSlider::SetDefaultCursor() {
|
|
setCursor(Qt::SizeHorCursor);
|
|
}
|
|
|
|
void LabelSlider::SetActiveCursor() {
|
|
setCursor(Qt::BlankCursor);
|
|
}
|
|
|
|
void LabelSlider::ShowContextMenu(const QPoint &pos)
|
|
{
|
|
Menu menu(this);
|
|
|
|
menu.addAction(tr("&Edit"), this, SLOT(ShowDialog()));
|
|
|
|
menu.addSeparator();
|
|
|
|
menu.addAction(tr("&Reset to Default"), this, SLOT(ResetToDefault()));
|
|
|
|
menu.exec(mapToGlobal(pos));
|
|
}
|
|
|
|
void LabelSlider::ResetToDefault()
|
|
{
|
|
// if the value is not already default, and there is a default to set
|
|
if (!qFuzzyCompare(internal_value, default_value)
|
|
&& !qIsNaN(default_value)) {
|
|
|
|
// set back to default
|
|
SetValue(default_value);
|
|
emit valueChanged(internal_value);
|
|
|
|
}
|
|
}
|
|
|
|
void LabelSlider::ShowDialog()
|
|
{
|
|
// if the user didn't actually drag, and just clicked in one place,
|
|
// we instead present a dialog prompt for the user to enter a
|
|
// specific value
|
|
|
|
double d = internal_value;
|
|
|
|
if (display_type == FrameNumber) {
|
|
|
|
// ask the user to enter a timecode
|
|
QString s = QInputDialog::getText(
|
|
this,
|
|
tr("Set Value"),
|
|
tr("New value:"),
|
|
QLineEdit::Normal,
|
|
ValueToString()
|
|
);
|
|
if (s.isEmpty()) return;
|
|
|
|
// parse string timecode to a frame number
|
|
d = timecode_to_frame(s, olive::CurrentConfig.timecode_view, frame_rate);
|
|
|
|
} else {
|
|
|
|
// ask the user to enter a normal number value
|
|
bool ok;
|
|
|
|
// value to show
|
|
double shown_value = internal_value;
|
|
if (display_type == Percent) {
|
|
shown_value *= 100;
|
|
} else if (display_type == Decibel) {
|
|
shown_value = amplitude_to_db(shown_value);
|
|
}
|
|
|
|
// set correct minimum value
|
|
double shown_minimum_value;
|
|
if (min_enabled) {
|
|
// if this field has a minimum value set, use it
|
|
shown_minimum_value = min_value;
|
|
} else if (display_type == Decibel) {
|
|
// minimum decibel amount is -96db
|
|
shown_minimum_value = -96;
|
|
} else {
|
|
// lowest possible minimum integer
|
|
shown_minimum_value = INT_MIN;
|
|
}
|
|
|
|
// percentages are stored 0.0 - 1.0 but displayed as 0% - 100%
|
|
d = QInputDialog::getDouble(
|
|
this,
|
|
tr("Set Value"),
|
|
tr("New value:"),
|
|
shown_value,
|
|
shown_minimum_value,
|
|
(max_enabled) ? max_value : INT_MAX,
|
|
decimal_places,
|
|
&ok
|
|
);
|
|
if (!ok) return;
|
|
|
|
// convert shown value back to internal value
|
|
if (display_type == Percent) {
|
|
d *= 0.01;
|
|
} else if (display_type == Decibel) {
|
|
d = db_to_amplitude(d);
|
|
}
|
|
}
|
|
|
|
// if the value actually changed, trigger a change event
|
|
if (!qFuzzyCompare(d, internal_value)) {
|
|
SetValue(d);
|
|
emit valueChanged(internal_value);
|
|
}
|
|
}
|