1 /***
2 
3   Olive - Non-Linear Video Editor
4   Copyright (C) 2019  Olive Team
5 
6   This program is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10 
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 
19 ***/
20 
21 #ifndef LABELSLIDER_H
22 #define LABELSLIDER_H
23 
24 #include <QLabel>
25 #include <QUndoCommand>
26 
27 /**
28  * @brief The LabelSlider class
29  *
30  * A UI element that shows a number and can be dragged to increase/decrease its value or clicked to enter a specific
31  * one.
32  */
33 class LabelSlider : public QLabel
34 {
35   Q_OBJECT
36 public:
37   LabelSlider(QWidget* parent = nullptr);
38 
39   /**
40    * @brief Set the value
41    * @param v
42    *
43    * Value to set to.
44    *
45    * @param userSet
46    *
47    * **TRUE** if this was called through a user action, **FALSE** if this was called through some other way. The
48    * only difference is **TRUE** will emit a signal (valueChanged()) indicating that the value has changed, and
49    * **FALSE** will not.
50    */
51   void SetValue(double v);
52 
53   /**
54    * @brief Set the default value
55    *
56    * If a default value is set, alt+clicking the LabelSlider will return to the default value.
57    *
58    * @param v
59    *
60    * Value to set as default
61    */
62   void SetDefault(double v);
63 
64   /**
65    * @brief Returns the internal value as a double
66    * @return The internal value. This will not respect the `display_type`, i.e. 100% will return as 1.0, 12dB will
67    * return as 400%, and a timecode will return as a frame number.
68    */
69   double value();
70 
71   enum DisplayType {
72     Normal,
73     FrameNumber,
74     Percent,
75     Decibel
76   };
77 
78   /**
79    * @brief Sets the way to display the value
80    *
81    * * `LABELSLIDER_NORMAL` - Shows the value as a normal number
82    * * `LABELSLIDER_FRAMENUMBER` - Shows the number as a timecode according to `config.timecode_view`. By default,
83    * will render hh:mm:ss:ff
84    * * `LABELSLIDER_PERCENT` - Shows the number as a percentage. 1.0 becomes "100%", 0.5 becomes 50%, etc.
85    * * `LABELSLIDER_DECIBLE` - Shows the number as a decibel. 1.0 becomes "0 dB", 2.0 becomes roughly "6 dB", 0.5
86    * becomes roughly "-6 dB", etc.
87    *
88    * @param type
89    *
90    * The display type to set to.
91    */
92   void SetDisplayType(const DisplayType& type);
93 
94   /**
95    * @brief Returns whether the user is currently dragging
96    * @return **TRUE** if the user is dragging, **FALSE** if not.
97    */
98   bool IsDragging();
99 
100   /**
101    * @brief Set the display color
102    * @param c
103    *
104    * Color to set to
105    */
106   void SetColor(QString c = nullptr);
107 
108   /**
109    * @brief Set the display frame rate
110    *
111    * If the `display_type` is set to LABELSLIDER_FRAMENUMBER, this function sets how many frames per second the
112    * timecode will be in.
113    *
114    * @param d
115    */
116   void SetFrameRate(double d);
117 
118   /**
119    * @brief Set how many decimal places to show for a floating-point number
120    *
121    * Defaults to 1
122    */
123   void SetDecimalPlaces(int places);
124 public slots:
125   /**
126    * @brief Set the minimum value
127    *
128    * If a minimum value is set, the value will never go below it. If the user manually sets a value lower than
129    * the minimum, it will automatically snap to the minimum.
130    *
131    * @param v
132    *
133    * Value to set as minimum
134    */
135   void SetMinimum(double v);
136 
137   /**
138    * @brief Set the maximum value
139    *
140    * If a maximum value is set, the value will never go above it. If the user manually sets a value higher than
141    * the maximum, it will automatically snap to the maximum.
142    *
143    * @param v
144    *
145    * Value to set as maximum
146    */
147   void SetMaximum(double v);
148 
149 protected:
150   void mousePressEvent(QMouseEvent *ev);
151   void mouseMoveEvent(QMouseEvent *ev);
152   void mouseReleaseEvent(QMouseEvent *ev);
153 private:
154 
155   /**
156    * @brief Convert the internal value to a displayed string according to `display_type`
157    * @return The internal value as a string
158    */
159   QString ValueToString();
160 
161   double default_value;
162   double internal_value;
163   double drag_start_value;
164 
165   int decimal_places;
166 
167   bool min_enabled;
168   double min_value;
169   bool max_enabled;
170   double max_value;
171 
172   bool drag_start;
173   bool drag_proc;
174   int drag_start_x;
175   int drag_start_y;
176 
177   bool set;
178 
179   DisplayType display_type;
180 
181   double frame_rate;
182 
183   /**
184    * @brief Internal function to set the standard cursor (usually SizeHorCursor)
185    */
186   void SetDefaultCursor();
187 
188   /**
189    * @brief Internal function to set the cursor while dragging (usually NoCursor aka invisible)
190    */
191   void SetActiveCursor();
192 private slots:
193   /**
194    * @brief Context menu slot to be connected to QWidget::customContextMenuRequested(const QPoint&)
195    *
196    * @param pos
197    *
198    * Current cursor position
199    */
200   void ShowContextMenu(const QPoint& pos);
201 
202   /**
203    * @brief Slot to reset current value to the default value
204    */
205   void ResetToDefault();
206 
207   /**
208    * @brief Show prompt asking for value
209    *
210    * Triggered when the user clicks on the LabelSlider without dragging or triggers right click > Edit.
211    * Will show an input dialog asking for a new value to be entered manually. Asks for units in the selected
212    * display type and converts them back to the internal value type.
213    */
214   void ShowDialog();
215 signals:
216   /**
217    * @brief valueChanged signal
218    *
219    * Emitted if the value changed at it was instigated by the user.
220    */
221   void valueChanged(double d);
222 
223   /**
224    * @brief clicked signal
225    *
226    * Emitted if the user clicks on the LabelSlider in any way
227    */
228   void clicked();
229 };
230 
231 #endif // LABELSLIDER_H
232