51 _prefRangePen(Qt::NoPen), |
51 _prefRangePen(Qt::NoPen), |
52 _markerBrush(QColor(255,255,255)), |
52 _markerBrush(QColor(255,255,255)), |
53 _markerTextIsValue(false), |
53 _markerTextIsValue(false), |
54 indicatorTextFont("Arial", 10, QFont::Normal) // Previously we just did the indicator text in 'default' font |
54 indicatorTextFont("Arial", 10, QFont::Normal) // Previously we just did the indicator text in 'default' font |
55 { |
55 { |
56 // Ensure this->heightInPixels is properly initialised |
56 // Fixed minimum size. |
57 // this->recalculateHeightInPixels(); |
57 this->setMinimumSize(60, 20); |
58 |
58 this->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ); |
59 // In principle we want to set our min/max sizes etc here. However, if, say, a maximumSize property has been set |
59 |
60 // for this object in a Designer UI File (eg ui/mainWindow.ui) then that setting will override this one, because it |
60 // There no particular reason to limit our horizontal size, so, in principle, this call asks that there be no such |
61 // will be applied later (in fact pretty much straight after this constructor returns). So we also make this call |
61 // (practical) limit. |
62 // inside setValue(), which will be invoked _after_ the setter calls that were auto-generated from the Designer UI |
62 this->setMaximumWidth(QWIDGETSIZE_MAX); |
63 // File. |
63 |
64 this->setSizes(); |
64 // Generate mouse move events whenever mouse movers over widget. |
65 |
65 this->setMouseTracking(true); |
66 // Generate mouse move events whenever mouse movers over widget. |
66 |
67 this->setMouseTracking(true); |
67 this->repaint(); |
68 |
68 } |
69 this->repaint(); |
69 |
70 } |
|
71 |
70 |
72 /** |
71 /** |
73 * @brief Set the normal limits in the _prexXxx values and calculate |
72 * @brief Set the normal limits in the _prexXxx values and calculate |
74 * the real drawing limits so that we can see if a value is slightly |
73 * the real drawing limits so that we can see if a value is slightly |
75 * out of range. |
74 * out of range. |
147 { |
143 { |
148 _markerTextIsValue = val; |
144 _markerTextIsValue = val; |
149 update(); |
145 update(); |
150 } |
146 } |
151 |
147 |
152 |
|
153 void RangedSlider::recalculateHeightInPixels() const { |
|
154 // |
|
155 // We need to be able to tell Qt about our minimum and preferred size in pixels. This is something that's going |
|
156 // to depend on the dots-per-inch (DPI) resolution of the monitor we're being displayed on. Advice at |
|
157 // https://doc.qt.io/qt-5/highdpi.html is that, for best High DPI display support, we should replace hard-coded |
|
158 // sizes in layouts and drawing code with values calculated from font metrics or screen size. For this widget, we |
|
159 // use font sizes (as described in more detail later in this comment) as it seems simpler and the height of the |
|
160 // widget really is determined by the size of the text it contains. |
|
161 // |
|
162 // In theory, someone might be running the app on a system with multiple screens with different DPI resolutions, |
|
163 // so, in principle we ought to do redo size calculations every time the widget is moved, in case it moves from one |
|
164 // screen to another and the resolution changes. In practice, I'm not sure how big a requirement this is. So, for |
|
165 // now, have just tried to organise things so that it would, in principle, be possible to implement such behaviour |
|
166 // in future. |
|
167 // |
|
168 // We want height to be fixed, as the slider does not get more readable if you make it taller. So minimum and |
|
169 // preferred height are the same. |
|
170 // |
|
171 // For width, We are OK for them to expand and contract horizontally, within reason, as the size of the main window |
|
172 // changes. Minimum and preferred widths are a bit of a rule-of-thumb, but 2× and 4× height are a sensible stab. |
|
173 // |
|
174 // Firstly we have to determine what the fixed height is. We could query the DPI resolution and size of the current |
|
175 // screen, but the simplest thing is to use font sizes. The slider is basically two lines of characters high. Top |
|
176 // line is the "indicator" text that sits above the slider visual in the middle of the "preferred range". Bottom |
|
177 // line is the slider visual and the "value" text that sits to the right of the slider visual. The fonts for both |
|
178 // bits of text are set in device-independent points in the constructor, and we can just query their height etc in |
|
179 // pixels. |
|
180 // |
|
181 // Secondly, the way we tell Qt about minimum and preferred sizes is slightly different: |
|
182 // • setMinimumSize() tells Qt not to make us smaller than the specified size when resizing windows etc, HOWEVER |
|
183 // it does not determine what size we are initially drawn |
|
184 // • instead, Qt calls sizeHint() when doing initial layout, and we must override this to supply our desired |
|
185 // initial dimensions. NB: Although it makes no sense, there is nothing to stop this method returning dimensions |
|
186 // below the minimums already set via setMinimumSize(). (AIUI, sizeHint() is also called on resize events to |
|
187 // find our preferred dimensions.) |
|
188 // |
|
189 // The final wrinkle is that the height of the font sort of depends what you mean. Strictly, using the inter-line |
|
190 // spacing (= height plus leading, though the latter is often 0) gives you enough space to show any character of the |
|
191 // font. It is helpful for the indicator text to have a bit of space below it before we draw the graphical bit, and |
|
192 // it's not a large font in any case. However, for large value text font we don't necessarily need all this space |
|
193 // because we currently only show digits and decimal points, which don't require space below the baseline. However, |
|
194 // assumptions about space below the baseline are locale-specific, so, say, using ascent() instead of lineSpacing() |
|
195 // could end up painting us into a corner. |
|
196 // |
|
197 //QFontMetrics indicatorTextFontMetrics(this->indicatorTextFont); |
|
198 // this->heightInPixels = this->height(); |
|
199 return; |
|
200 } |
|
201 |
|
202 void RangedSlider::setSizes() { |
|
203 // Fixed minimum size. |
|
204 this->setMinimumSize(60, 20); |
|
205 this->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ); |
|
206 |
|
207 // There no particular reason to limit our horizontal size, so, in principle, this call asks that there be no such |
|
208 // (practical) limit. |
|
209 this->setMaximumWidth(QWIDGETSIZE_MAX); |
|
210 |
|
211 return; |
|
212 } |
|
213 |
|
214 //QSize RangedSlider::sizeHint() const |
|
215 //{ |
|
216 // this->recalculateHeightInPixels(); |
|
217 // return QSize(4 * this->heightInPixels, this->heightInPixels); |
|
218 //} |
|
219 |
148 |
220 void RangedSlider::mouseMoveEvent(QMouseEvent* event) |
149 void RangedSlider::mouseMoveEvent(QMouseEvent* event) |
221 { |
150 { |
222 event->accept(); |
151 event->accept(); |
223 |
152 |