From b2d632598159d4ea26ab7ef2d1552c13279064a8 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 2 Mar 2019 10:48:52 -0800 Subject: [PATCH] added context menu to labelslider --- ui/labelslider.cpp | 463 ++++++++++++++++++++++++--------------------- ui/labelslider.h | 143 ++++++++------ 2 files changed, 329 insertions(+), 277 deletions(-) diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp index eeba9c34b..9791def51 100644 --- a/ui/labelslider.cpp +++ b/ui/labelslider.cpp @@ -29,313 +29,342 @@ #include #include #include +#include LabelSlider::LabelSlider(QWidget* parent) : QLabel(parent) { - // set a default frame rate - fallback, shouldn't ever really be used - frame_rate = 30; + // 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; - set_color(); - set_default_cursor(); - internal_value = -1; - set = false; - display_type = LABELSLIDER_NORMAL; + decimal_places = 1; + drag_start = false; + drag_proc = false; + min_enabled = false; + max_enabled = false; + set_color(); + set_default_cursor(); + internal_value = -1; + set = false; + display_type = LABELSLIDER_NORMAL; - set_default_value(0); + set_default_value(0); + + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&))); } void LabelSlider::set_frame_rate(double d) { - frame_rate = d; + frame_rate = d; } void LabelSlider::set_display_type(int type) { - display_type = type; - setText(valueToString()); + display_type = type; + setText(valueToString()); } void LabelSlider::set_value(double v, bool userSet) { - 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; - } + 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()); - if (userSet) emit valueChanged(); - } + setText(valueToString()); + if (userSet) emit valueChanged(); + } } bool LabelSlider::is_set() { - return set; + return set; } bool LabelSlider::is_dragging() { - return drag_proc; + return drag_proc; } QString LabelSlider::valueToString() { - double v = internal_value; - if (qIsNaN(v)) { - return "---"; - } else { - switch (display_type) { - case LABELSLIDER_FRAMENUMBER: - return frame_to_timecode(long(v), olive::CurrentConfig.timecode_view, frame_rate); - case LABELSLIDER_PERCENT: - return QString::number((v*100), 'f', decimal_places).append("%"); - case LABELSLIDER_DECIBEL: - { - QString db_str; + double v = internal_value; + if (qIsNaN(v)) { + return "---"; + } else { + switch (display_type) { + case LABELSLIDER_FRAMENUMBER: + return frame_to_timecode(long(v), olive::CurrentConfig.timecode_view, frame_rate); + case LABELSLIDER_PERCENT: + return QString::number((v*100), 'f', decimal_places).append("%"); + case LABELSLIDER_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); - } + // -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"); + // add "dB" suffix + db_str.append(" dB"); - return db_str; - } - } - return QString::number(v, 'f', decimal_places); - } + return db_str; + } + } + return QString::number(v, 'f', decimal_places); + } } double LabelSlider::getPreviousValue() { - return previous_value; + return previous_value; } void LabelSlider::set_previous_value() { - previous_value = internal_value; + previous_value = internal_value; } void LabelSlider::set_color(QString c) { - if (c.isEmpty()) c = "#ffc000"; - setStyleSheet("QLabel{color:" + c + ";text-decoration:underline;}QLabel:disabled{color:#808080;}"); + if (c.isEmpty()) c = "#ffc000"; + setStyleSheet("QLabel{color:" + c + ";text-decoration:underline;}QLabel:disabled{color:#808080;}"); } double LabelSlider::value() { - return internal_value; + return internal_value; } void LabelSlider::set_default_value(double v) { - default_value = v; - if (!set) { - set_value(v, false); - set = false; - } + default_value = v; + if (!set) { + set_value(v, false); + set = false; + } } void LabelSlider::set_minimum_value(double v) { - min_value = v; - min_enabled = true; + min_value = v; + min_enabled = true; } void LabelSlider::set_maximum_value(double v) { - max_value = v; - max_enabled = true; + max_value = v; + max_enabled = true; } void LabelSlider::mousePressEvent(QMouseEvent *ev) { - // if primary button is clicked - if (ev->button() == Qt::LeftButton && !drag_start) { + // 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; + // 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) { + // alt + click sets labelslider to default value + if (ev->modifiers() & Qt::AltModifier) { - // if the value is not already default, and there is a default to set - if (!qFuzzyCompare(internal_value, default_value) - && !qIsNaN(default_value)) { - - // cache current value - set_previous_value(); - - // set back to default - set_value(default_value, true); - - } - - } 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 - set_active_cursor(); - - drag_start = true; - drag_start_x = cursor().pos().x(); - drag_start_y = cursor().pos().y(); - } - - emit clicked(); + // reset to default + reset_to_default_value(); } else { - // handler if the user clicks with a non-primary button - // prevents mouse from getting stuck in "dragging" mode - mouseReleaseEvent(ev); + // 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 + set_active_cursor(); + + 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 + 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; + // 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()); + // 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; + // ctrl + drag drags in smaller increments + if (event->modifiers() & Qt::ControlModifier) diff *= 0.01; - if (display_type == LABELSLIDER_PERCENT) { - // we'll also need to drag in smaller increments for a percent value + if (display_type == LABELSLIDER_PERCENT) { + // we'll also need to drag in smaller increments for a percent value - diff *= 0.01; - } + diff *= 0.01; + } - // determine what the new value will be - double new_value; + // determine what the new value will be + double new_value; - if (display_type == LABELSLIDER_DECIBEL) { - // we move in terms of dB for decibel display + if (display_type == LABELSLIDER_DECIBEL) { + // we move in terms of dB for decibel display - new_value = db_to_amplitude(amplitude_to_db(internal_value) + diff); + new_value = db_to_amplitude(amplitude_to_db(internal_value) + diff); - } else { - // for most display types, just add the mouse difference + } else { + // for most display types, just add the mouse difference - new_value = internal_value + diff; - } + new_value = internal_value + diff; + } - // set internal value - set_value(new_value, true); + // set internal value + set_value(new_value, true); - // keep the cursor in the same location while dragging - cursor().setPos(drag_start_x, drag_start_y); - } + // keep the cursor in the same location while dragging + cursor().setPos(drag_start_x, drag_start_y); + } } void LabelSlider::mouseReleaseEvent(QMouseEvent*) { - if (drag_start) { + if (drag_start) { - // unhide cursor - set_default_cursor(); + // unhide cursor + set_default_cursor(); - drag_start = false; + drag_start = false; - if (drag_proc) { - // if we just finished fully dragging + if (drag_proc) { + // if we just finished fully dragging - drag_proc = false; + drag_proc = false; - previous_value = drag_start_value; + previous_value = drag_start_value; - emit valueChanged(); + emit valueChanged(); - } else { + } else { - // 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 + prompt_for_value(); - double d = internal_value; - - if (display_type == LABELSLIDER_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 == LABELSLIDER_PERCENT) { - shown_value *= 100; - } else if (display_type == LABELSLIDER_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 == LABELSLIDER_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 == LABELSLIDER_PERCENT) { - d *= 0.01; - } else if (display_type == LABELSLIDER_DECIBEL) { - d = db_to_amplitude(d); - } - } - - // if the value actually changed, trigger a change event - if (!qFuzzyCompare(d, internal_value)) { - set_previous_value(); - set_value(d, true); - } - } } + } } void LabelSlider::set_default_cursor() { - setCursor(Qt::SizeHorCursor); + setCursor(Qt::SizeHorCursor); } void LabelSlider::set_active_cursor() { - setCursor(Qt::BlankCursor); + setCursor(Qt::BlankCursor); +} + +void LabelSlider::show_context_menu(const QPoint &pos) +{ + QMenu menu(this); + + menu.addAction(tr("&Edit"), this, SLOT(prompt_for_value())); + + menu.addSeparator(); + + menu.addAction(tr("&Reset to Default"), this, SLOT(reset_to_default_value())); + + menu.exec(mapToGlobal(pos)); +} + +void LabelSlider::reset_to_default_value() +{ + // if the value is not already default, and there is a default to set + if (!qFuzzyCompare(internal_value, default_value) + && !qIsNaN(default_value)) { + + // cache current value + set_previous_value(); + + // set back to default + set_value(default_value, true); + + } +} + +void LabelSlider::prompt_for_value() +{ + // 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 == LABELSLIDER_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 == LABELSLIDER_PERCENT) { + shown_value *= 100; + } else if (display_type == LABELSLIDER_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 == LABELSLIDER_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 == LABELSLIDER_PERCENT) { + d *= 0.01; + } else if (display_type == LABELSLIDER_DECIBEL) { + d = db_to_amplitude(d); + } + } + + // if the value actually changed, trigger a change event + if (!qFuzzyCompare(d, internal_value)) { + set_previous_value(); + set_value(d, true); + } } diff --git a/ui/labelslider.h b/ui/labelslider.h index db0d68e21..ae0eae0c0 100644 --- a/ui/labelslider.h +++ b/ui/labelslider.h @@ -25,10 +25,10 @@ #include enum LabelSliderDisplayType { - LABELSLIDER_NORMAL, - LABELSLIDER_FRAMENUMBER, - LABELSLIDER_PERCENT, - LABELSLIDER_DECIBEL + LABELSLIDER_NORMAL, + LABELSLIDER_FRAMENUMBER, + LABELSLIDER_PERCENT, + LABELSLIDER_DECIBEL }; /** @@ -39,11 +39,11 @@ enum LabelSliderDisplayType { */ class LabelSlider : public QLabel { - Q_OBJECT + Q_OBJECT public: - LabelSlider(QWidget* parent = nullptr); + LabelSlider(QWidget* parent = nullptr); - /** + /** * @brief Set the display frame rate * * If the `display_type` is set to LABELSLIDER_FRAMENUMBER, this function sets how many frames per second the @@ -51,9 +51,9 @@ public: * * @param d */ - void set_frame_rate(double d); + void set_frame_rate(double d); - /** + /** * @brief Sets the way to display the value * * * `LABELSLIDER_NORMAL` - Shows the value as a normal number @@ -67,9 +67,9 @@ public: * * The display type to set to. Should be a member of `enum LabelSliderDisplayType`. */ - void set_display_type(int type); + void set_display_type(int type); - /** + /** * @brief Set the value * @param v * @@ -81,9 +81,9 @@ public: * only difference is **TRUE** will emit a signal (valueChanged()) indicating that the value has changed, and * **FALSE** will not. */ - void set_value(double v, bool userSet); + void set_value(double v, bool userSet); - /** + /** * @brief Set the default value * * If a default value is set, alt+clicking the LabelSlider will return to the default value. @@ -92,9 +92,9 @@ public: * * Value to set as default */ - void set_default_value(double v); + void set_default_value(double v); - /** + /** * @brief Set the minimum value * * If a minimum value is set, the value will never go below it. If the user manually sets a value lower than @@ -104,9 +104,9 @@ public: * * Value to set as minimum */ - void set_minimum_value(double v); + void set_minimum_value(double v); - /** + /** * @brief Set the maximum value * * If a maximum value is set, the value will never go above it. If the user manually sets a value higher than @@ -116,16 +116,16 @@ public: * * Value to set as maximum */ - void set_maximum_value(double v); + void set_maximum_value(double v); - /** + /** * @brief Returns the internal value as a double * @return The internal value. This will not respect the `display_type`, i.e. 100% will return as 1.0, 12dB will * return as 400%, and a timecode will return as a frame number. */ - double value(); + double value(); - /** + /** * @brief Returns whether a value has been set or not * * If a value has been entered by any means (i.e. if set_value() was called), this will be **TRUE**. If set_value() @@ -136,21 +136,21 @@ public: * * @return **TRUE** if a value has been set, **FALSE** if not. */ - bool is_set(); + bool is_set(); - /** + /** * @brief Returns whether the user is currently dragging * @return **TRUE** if the user is dragging, **FALSE** if not. */ - bool is_dragging(); + bool is_dragging(); - /** + /** * @brief Convert the internal value to a displayed string according to `display_type` * @return The internal value as a string */ - QString valueToString(); + QString valueToString(); - /** + /** * @brief Returns whatever value was set before the last set_value() * * For various reasons (largely undo capabilities) it is helpful to retrieve whatever the value was before the @@ -159,79 +159,102 @@ public: * * @return The previous value */ - double getPreviousValue(); + double getPreviousValue(); - /** + /** * @brief Updates previous value * * Called internally to store the current value as the previous value in anticipation of an upcoming value change. * Can also be called externally (mainly for dragged EffectGizmos) in anticipation of an external change. */ - void set_previous_value(); + void set_previous_value(); - /** + /** * @brief Set the display color * @param c * * Color to set to */ - void set_color(QString c = nullptr); + void set_color(QString c = nullptr); - /** + /** * @brief Set how many decimal places to show for a floating-point number * * Defaults to 1 */ - int decimal_places; + int decimal_places; protected: - void mousePressEvent(QMouseEvent *ev); - void mouseMoveEvent(QMouseEvent *ev); - void mouseReleaseEvent(QMouseEvent *ev); + void mousePressEvent(QMouseEvent *ev); + void mouseMoveEvent(QMouseEvent *ev); + void mouseReleaseEvent(QMouseEvent *ev); private: - double default_value; - double internal_value; - double drag_start_value; - double previous_value; + double default_value; + double internal_value; + double drag_start_value; + double previous_value; - bool min_enabled; - double min_value; - bool max_enabled; - double max_value; + bool min_enabled; + double min_value; + bool max_enabled; + double max_value; - bool drag_start; - bool drag_proc; - int drag_start_x; - int drag_start_y; + bool drag_start; + bool drag_proc; + int drag_start_x; + int drag_start_y; - bool set; + bool set; - int display_type; + int display_type; - double frame_rate; + double frame_rate; - /** + /** * @brief Internal function to set the standard cursor (usually SizeHorCursor) */ - void set_default_cursor(); + void set_default_cursor(); - /** + /** * @brief Internal function to set the cursor while dragging (usually NoCursor aka invisible) */ - void set_active_cursor(); + void set_active_cursor(); +private slots: + /** + * @brief Context menu slot to be connected to QWidget::customContextMenuRequested(const QPoint&) + * + * @param pos + * + * Current cursor position + */ + void show_context_menu(const QPoint& pos); + + /** + * @brief Slot to reset current value to the default value + */ + void reset_to_default_value(); + + /** + * @brief Show prompt asking for value + * + * Triggered when the user clicks on the LabelSlider without dragging or triggers right click > Edit. + * Will show an input dialog asking for a new value to be entered manually. Asks for units in the selected + * display type and converts them back to the internal value type. + */ + void prompt_for_value(); signals: - /** + /** * @brief valueChanged signal * * Emitted if the value changed at it was instigated by the user. */ - void valueChanged(); + void valueChanged(); - /** + /** * @brief clicked signal * * Emitted if the user clicks on the LabelSlider in any way */ - void clicked(); + void clicked(); }; #endif // LABELSLIDER_H