Perceptual Color

gradientslider.cpp
1// SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com>
2// SPDX-License-Identifier: BSD-2-Clause OR MIT
3
4// Own headers
5// First the interface, which forces the header to be self-contained.
6#include "gradientslider.h"
7// Second, the private implementation.
8#include "gradientslider_p.h" // IWYU pragma: associated
9
10#include "abstractdiagram.h"
11#include "constpropagatingrawpointer.h"
12#include "constpropagatinguniquepointer.h"
13#include "gradientimageparameters.h"
14#include "helperconstants.h"
15#include <helper.h>
16#include <qevent.h>
17#include <qguiapplication.h>
18#include <qimage.h>
19#include <qpainter.h>
20#include <qpen.h>
21#include <qpoint.h>
22#include <qsharedpointer.h>
23#include <qsizepolicy.h>
24#include <qtransform.h>
25#include <qwidget.h>
26
27namespace PerceptualColor
28{
29/** @brief Constructs a vertical slider.
30 * @param colorSpace The color space within which this widget should operate.
31 * Can be created with @ref RgbColorSpaceFactory.
32 * Can be created with @ref RgbColorSpaceFactory.
33 * @param parent parent widget (if any) */
36 , d_pointer(new GradientSliderPrivate(this))
37{
38 d_pointer->initialize(colorSpace, Qt::Orientation::Vertical);
39}
40
41/** @brief Constructs a slider.
42 * @param colorSpace The color space within which this widget should operate.
43 * Can be created with @ref RgbColorSpaceFactory.
44 * @param orientation The orientation parameter determines whether
45 * the slider is horizontal or vertical; the valid values
46 * are <tt>Qt::Vertical</tt> and <tt>Qt::Horizontal</tt>.
47 * @param parent parent widget (if any) */
50 , d_pointer(new GradientSliderPrivate(this))
51{
52 d_pointer->initialize(colorSpace, orientation);
53}
54
55/** @brief Default destructor */
59
60/** @brief Constructor
61 *
62 * @param backLink Pointer to the object from which <em>this</em> object
63 * is the private implementation. */
64GradientSliderPrivate::GradientSliderPrivate(GradientSlider *backLink)
65 : m_firstColorCieLchD50A{0, 0, 0, 0} // dummy value
66 , m_secondColorCieLchD50A{0, 0, 0, 0} // dummy value
67 , q_pointer(backLink)
68{
69}
70
71/** @brief Basic initialization.
72 *
73 * Code that is shared between the various overloaded constructors
74 * of @ref GradientSlider.
75 *
76 * @note This function requires that @ref q_pointer points to a completely
77 * initialized object. Therefore, this function may <em>not</em> be called
78 * within the constructor of @ref GradientSliderPrivate because in this
79 * moment the @ref GradientSlider object is still not fully initialized.
80 * However, a call from the <em>function body</em> of a constructor of
81 * @ref GradientSlider should be okay.
82 *
83 * @param colorSpace the color space
84 * @param orientation determines whether the slider is horizontal or
85 * vertical */
86void GradientSliderPrivate::initialize(const QSharedPointer<RgbColorSpace> &colorSpace, Qt::Orientation orientation)
87{
88 q_pointer->setFocusPolicy(Qt::StrongFocus);
89 m_gradientImageParameters.rgbColorSpace = colorSpace;
90 setOrientationWithoutSignalAndForceNewSizePolicy(orientation);
91 constexpr GenericColor first{75, 65, 90, 1};
92 constexpr GenericColor second{50, 75, 45, 1};
93 q_pointer->setColors(first, second);
94
95 // Connections
96 q_pointer->connect( //
97 &m_gradientImage, //
98 &AsyncImageProvider<GradientImageParameters>::interlacingPassCompleted, //
99 q_pointer,
101}
102
103// No documentation here (documentation of properties
104// and its getters are in the header)
106{
107 return d_pointer->m_firstColorCieLchD50A;
108}
109
110/** @brief Setter for @ref firstColorCieLchD50A property.
111 *
112 * @param newFirstColorCieLchD50A the new @ref firstColorCieLchD50A */
113void GradientSlider::setFirstColorCieLchD50A(const PerceptualColor::GenericColor &newFirstColorCieLchD50A)
114{
115 if (!(d_pointer->m_firstColorCieLchD50A == newFirstColorCieLchD50A)) {
116 d_pointer->m_firstColorCieLchD50A = newFirstColorCieLchD50A;
117 d_pointer->m_gradientImageParameters.setFirstColorCieLchD50A(newFirstColorCieLchD50A);
118 d_pointer->m_gradientImage.setImageParameters( //
119 d_pointer->m_gradientImageParameters);
120 update();
121 Q_EMIT firstColorCieLchD50AChanged(newFirstColorCieLchD50A);
122 }
123}
124
125// No documentation here (documentation of properties
126// and its getters are in the header)
128{
129 return d_pointer->m_secondColorCieLchD50A;
130}
131
132/** @brief Setter for @ref secondColorCieLchD50A property.
133 *
134 * @param newSecondColorCieLchD50A the new @ref secondColorCieLchD50A */
135void GradientSlider::setSecondColorCieLchD50A(const PerceptualColor::GenericColor &newSecondColorCieLchD50A)
136{
137 if (!(d_pointer->m_secondColorCieLchD50A == newSecondColorCieLchD50A)) {
138 d_pointer->m_secondColorCieLchD50A = newSecondColorCieLchD50A;
139 d_pointer->m_gradientImageParameters.setSecondColorCieLchD50A(newSecondColorCieLchD50A);
140 d_pointer->m_gradientImage.setImageParameters( //
141 d_pointer->m_gradientImageParameters);
142 update();
143 Q_EMIT secondColorCieLchD50AChanged(newSecondColorCieLchD50A);
144 }
145}
146
147/** @brief Setter for both, @ref firstColorCieLchD50A property and @ref secondColorCieLchD50A
148 * property.
149 *
150 * @param newFirstColorCieLchD50A the new @ref firstColorCieLchD50A
151 * @param newSecondColorCieLchD50A the new @ref secondColorCieLchD50A */
152void GradientSlider::setColors(const PerceptualColor::GenericColor &newFirstColorCieLchD50A, const PerceptualColor::GenericColor &newSecondColorCieLchD50A)
153{
154 setFirstColorCieLchD50A(newFirstColorCieLchD50A);
155 setSecondColorCieLchD50A(newSecondColorCieLchD50A);
156 update();
157}
158
159/** @brief React on a resize event.
160 *
161 * Reimplemented from base class.
162 *
163 * @param event The corresponding resize event */
165{
166 Q_UNUSED(event)
167 d_pointer->m_gradientImageParameters.setGradientLength( //
168 d_pointer->physicalPixelLength());
169 d_pointer->m_gradientImageParameters.setGradientThickness(
170 // Normally, this should not change, but maybe on Hight-DPI
171 // devices there might be some differences.
172 d_pointer->physicalPixelThickness());
173 d_pointer->m_gradientImage.setImageParameters( //
174 d_pointer->m_gradientImageParameters);
175 update();
176}
177
178/** @brief Recommended size for the widget
179 *
180 * Reimplemented from base class.
181 *
182 * @returns Recommended size for the widget.
183 *
184 * @sa @ref sizeHint() */
186{
187 QSize result = minimumSizeHint();
188 if (d_pointer->m_orientation == Qt::Orientation::Horizontal) {
189 result.setWidth( //
190 qRound(result.width() * scaleFromMinumumSizeHintToSizeHint));
191 } else {
192 result.setHeight( //
193 qRound(result.height() * scaleFromMinumumSizeHintToSizeHint));
194 }
195 return result;
196}
197
198/** @brief Recommended minimum size for the widget.
199 *
200 * Reimplemented from base class.
201 *
202 * @returns Recommended minimum size for the widget.
203 *
204 * @sa @ref minimumSizeHint() */
206{
207 QSize result;
208 if (d_pointer->m_orientation == Qt::Orientation::Horizontal) {
211 } else {
212 result.setWidth(gradientThickness());
214 }
215 return result;
216}
217
218// No documentation here (documentation of properties
219// and its getters are in the header)
221{
222 return d_pointer->m_singleStep;
223}
224
225/** @brief Setter for @ref singleStep property.
226 *
227 * @param newSingleStep the new @ref singleStep. Is bound to the valid
228 * range of the property. */
229void GradientSlider::setSingleStep(qreal newSingleStep)
230{
231 // Do not use negative value
232 const qreal boundedSingleStep = qBound<qreal>(0.0, newSingleStep, 1.0);
233 if (boundedSingleStep != d_pointer->m_singleStep) {
234 d_pointer->m_singleStep = boundedSingleStep;
235 Q_EMIT singleStepChanged(d_pointer->m_singleStep);
236 }
237}
238
239// No documentation here (documentation of properties
240// and its getters are in the header)
242{
243 return d_pointer->m_pageStep;
244}
245
246/** @brief Setter for @ref pageStep property.
247 *
248 * @param newPageStep the new @ref pageStep. Is bound to the valid
249 * range of the property. */
250void GradientSlider::setPageStep(qreal newPageStep)
251{
252 // Do not use negative altkluge
253 const qreal boundedNewPageStep = qBound<qreal>(0.0, newPageStep, 1.0);
254 if (boundedNewPageStep != d_pointer->m_pageStep) {
255 d_pointer->m_pageStep = boundedNewPageStep;
256 Q_EMIT pageStepChanged(d_pointer->m_pageStep);
257 }
258}
259
260// No documentation here (documentation of properties
261// and its getters are in the header)
263{
264 return d_pointer->m_value;
265}
266
267/** @brief Setter for @ref value property.
268 *
269 * @param newValue the new @ref value. Is bound to the valid
270 * range of the property. */
271void GradientSlider::setValue(qreal newValue)
272{
273 qreal temp = qBound<qreal>(0, newValue, 1);
274 if (d_pointer->m_value != temp) {
275 d_pointer->m_value = temp;
276 update();
277 Q_EMIT valueChanged(temp);
278 }
279}
280
281/** @brief React on a mouse press event.
282 *
283 * Reimplemented from base class.
284 *
285 * @param event The corresponding mouse event */
287{
288 setValue(d_pointer->fromWidgetPixelPositionToValue(event->pos()));
289}
290
291/** @brief React on a mouse release event.
292 *
293 * Reimplemented from base class.
294 *
295 * @param event The corresponding mouse event */
297{
298 setValue(d_pointer->fromWidgetPixelPositionToValue(event->pos()));
299}
300
301/** @brief React on a mouse move event.
302 *
303 * Reimplemented from base class.
304 *
305 * @param event The corresponding mouse event */
307{
308 setValue(d_pointer->fromWidgetPixelPositionToValue(event->pos()));
309}
310
311/** @brief React on a mouse wheel event.
312 *
313 * Reimplemented from base class.
314 *
315 * @param event The corresponding mouse event */
317{
318 qreal steps = standardWheelStepCount(event);
319 // Only react on good old vertical wheels, and not on horizontal wheels
320 if (steps != 0) {
321 qreal stepSize;
322 if ( //
325 ) {
326 stepSize = pageStep();
327 } else {
328 stepSize = singleStep();
329 }
330 setValue(d_pointer->m_value + steps * stepSize);
331 } else {
332 // Don’t accept the event and let it up to the default treatment:
333 event->ignore();
334 }
335}
336
337/** @brief React on key press events.
338 *
339 * Reimplemented from base class.
340 *
341 * The user can change the @ref value of this widget by the following
342 * key strokes:
343 *
344 * - Qt::Key_Up and Qt::Key_Plus increments a @ref singleStep.
345 * - Qt::Key_Down and Qt::Key_Minus decrements a @ref singleStep.
346 * - Qt::Key_Left increments and Qt::Key_Right increment or decrement
347 * a @ref singleStep, depending on the layout direction (LTR or RTL).
348 * - Qt::Key_PageUp increments a @ref pageStep
349 * - Qt::Key_PageDown decrements a @ref pageStep
350 * - Qt::Key_Home increments to the maximum @ref value
351 * - Qt::Key_End decrements to the minimum @ref value
352 *
353 * @param event the event */
355{
356 switch (event->key()) {
357 case Qt::Key_Up:
358 case Qt::Key_Plus:
359 setValue(d_pointer->m_value + d_pointer->m_singleStep);
360 break;
361 case Qt::Key_Down:
362 case Qt::Key_Minus:
363 setValue(d_pointer->m_value - d_pointer->m_singleStep);
364 break;
365 case Qt::Key_Left:
366 if (layoutDirection() == Qt::LayoutDirection::LeftToRight) {
367 setValue(d_pointer->m_value - d_pointer->m_singleStep);
368 } else {
369 setValue(d_pointer->m_value + d_pointer->m_singleStep);
370 }
371 break;
372 case Qt::Key_Right:
373 if (layoutDirection() == Qt::LayoutDirection::LeftToRight) {
374 setValue(d_pointer->m_value + d_pointer->m_singleStep);
375 } else {
376 setValue(d_pointer->m_value - d_pointer->m_singleStep);
377 }
378 break;
379 case Qt::Key_PageUp:
380 setValue(d_pointer->m_value + d_pointer->m_pageStep);
381 break;
382 case Qt::Key_PageDown:
383 setValue(d_pointer->m_value - d_pointer->m_pageStep);
384 break;
385 case Qt::Key_Home:
386 setValue(0);
387 break;
388 case Qt::Key_End:
389 setValue(1);
390 break;
391 default:
392 /* Quote from Qt documentation:
393 *
394 * “If you reimplement this handler, it is very important that
395 * you call the base class implementation if you do not act
396 * upon the key.
397 *
398 * The default implementation closes popup widgets if the
399 * user presses the key sequence for QKeySequence::Cancel
400 * (typically the Escape key). Otherwise the event is
401 * ignored, so that the widget’s parent can interpret it.“ */
403 }
404}
405
406// No documentation here (documentation of properties
407// and its getters are in the header)
409{
410 return d_pointer->m_orientation;
411}
412
413/** @brief Forces a new orientation and a corresponding size policy.
414 *
415 * @param newOrientation The new orientation for the widget.
416 *
417 * @post The new orientation is stored. The signal
418 * @ref GradientSlider::orientationChanged is <em>not</em> emitted.
419 * The <tt>sizePolicy</tt> property is updated corresponding to the
420 * <em>new</em> orientation; this happens even if the new
421 * orientation is identical to the old @ref m_orientation! */
422void GradientSliderPrivate::setOrientationWithoutSignalAndForceNewSizePolicy(Qt::Orientation newOrientation)
423{
424 if (newOrientation == Qt::Orientation::Vertical) {
425 q_pointer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
426 } else {
427 q_pointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
428 }
429 m_orientation = newOrientation;
430 m_gradientImageParameters.setGradientLength(physicalPixelLength());
431 m_gradientImageParameters.setGradientThickness(
432 // Normally, this should not change, but maybe on Hight-DPI
433 // devices there are some differences.
434 physicalPixelThickness());
435 m_gradientImage.setImageParameters(m_gradientImageParameters);
436 // Notify the layout system the the geometry has changed
437 q_pointer->updateGeometry();
438 q_pointer->update();
439}
440
441/** @brief Setter for @ref orientation property.
442 *
443 * @param newOrientation the new @ref orientation. */
445{
446 if (newOrientation != d_pointer->m_orientation) {
447 d_pointer->setOrientationWithoutSignalAndForceNewSizePolicy( //
448 newOrientation);
449 Q_EMIT orientationChanged(d_pointer->m_orientation);
450 }
451}
452
453/** @brief The rounded length of the widget
454 * measured in <em>physical pixels</em>.
455 *
456 * @returns The rounded length of the widget
457 * measured in <em>physical pixels</em>.
458 *
459 * This is a convenience function to access
460 * @ref GradientSlider::physicalPixelSize(). The length is the
461 * size of the widget in the direction of the gradient.
462 *
463 * @sa @ref physicalPixelThickness() */
464int GradientSliderPrivate::physicalPixelLength() const
465{
466 if (m_orientation == Qt::Orientation::Vertical) {
467 return q_pointer->physicalPixelSize().height();
468 } else {
469 return q_pointer->physicalPixelSize().width();
470 }
471}
472
473/** @brief The rounded thickness of the widget
474 * measured in <em>physical pixels</em>.
475 *
476 * @returns The rounded thickness of the widget
477 * measured in <em>physical pixels</em>.
478 *
479 * This is a convenience function to access
480 * @ref GradientSlider::physicalPixelSize(). The thickness is the
481 * size of the widget orthogonal to the direction of the gradient.
482 *
483 * @sa @ref physicalPixelLength() */
484int GradientSliderPrivate::physicalPixelThickness() const
485{
486 if (m_orientation == Qt::Orientation::Horizontal) {
487 return q_pointer->physicalPixelSize().height();
488 } else {
489 return q_pointer->physicalPixelSize().width();
490 }
491}
492
493/** @brief Converts widget pixel positions to @ref GradientSlider::value
494 * @param pixelPosition The position of a pixel of the widget coordinate
495 * system. The given value does not necessarily need to
496 * be within the actual displayed widget. It might even be negative.
497 * @returns The corresponding @ref GradientSlider::value for the (center of
498 * the) given widget pixel position.
499 * @sa @ref measurementdetails */
500qreal GradientSliderPrivate::fromWidgetPixelPositionToValue(QPoint pixelPosition)
501{
502 // We are interested in the point in the middle of the given pixel.
503 const QPointF coordinatePoint = pixelPosition + QPointF(0.5, 0.5);
504 qreal temp;
505 if (m_orientation == Qt::Orientation::Vertical) {
506 temp = (q_pointer->size().height() - coordinatePoint.y()) //
507 / static_cast<qreal>(q_pointer->size().height());
508 } else {
509 if (q_pointer->layoutDirection() == Qt::LayoutDirection::LeftToRight) {
510 temp = coordinatePoint.x() //
511 / static_cast<qreal>(q_pointer->size().width());
512 } else {
513 temp = (q_pointer->size().width() - coordinatePoint.x()) //
514 / static_cast<qreal>(q_pointer->size().width());
515 }
516 }
517 return qBound<qreal>(0, temp, 1);
518}
519
520/** @brief Paint the widget.
521 *
522 * Reimplemented from base class.
523 *
524 * @param event the paint event */
526{
527 Q_UNUSED(event)
528 // We do not paint directly on the widget, but on a QImage buffer first:
529 // Render anti-aliased looks better. But as Qt documentation says:
530 //
531 // “Renderhints are used to specify flags to QPainter that may or
532 // may not be respected by any given engine.”
533 //
534 // Painting here directly on the widget might lead to different
535 // anti-aliasing results depending on the underlying window system. This
536 // is especially problematic as anti-aliasing might shift or not a pixel
537 // to the left or to the right. So we paint on a QImage first. As QImage
538 // (at difference to QPixmap and a QWidget) is independent of native
539 // platform rendering, it guarantees identical anti-aliasing results on
540 // all platforms. Here the quote from QPainter class documentation:
541 //
542 // “To get the optimal rendering result using QPainter, you should
543 // use the platform independent QImage as paint device; i.e. using
544 // QImage will ensure that the result has an identical pixel
545 // representation on any platform.”
546 QImage paintBuffer;
547
548 // Paint the gradient itself.
549 // Make sure the image will be correct. We set length and thickness,
550 // just to be sure (we might have missed a resize event). Also,
551 // the device pixel ratio float might have changed because the
552 // window has been moved to another screen. We do not update the
553 // first and the second color because we have complete control
554 // about these values and are sure the any changes have yet been
555 // applied.
556 d_pointer->m_gradientImageParameters.setDevicePixelRatioF( //
558 d_pointer->m_gradientImageParameters.setGradientLength( //
559 d_pointer->physicalPixelLength());
560 d_pointer->m_gradientImageParameters.setGradientThickness(
561 // Normally, this should not change, but maybe on Hight-DPI
562 // devices there are some differences.
563 d_pointer->physicalPixelThickness());
564 d_pointer->m_gradientImage.setImageParameters( //
565 d_pointer->m_gradientImageParameters);
566 d_pointer->m_gradientImage.refreshAsync();
567 paintBuffer = d_pointer->m_gradientImage.getCache();
568 if (paintBuffer.isNull()) {
569 return;
570 }
571
572 // Draw slider handle
573 QPainter bufferPainter(&paintBuffer);
574 // We use antialiasing. As our current handle is just a horizontal or
575 // vertical line, it might be slightly sharper without antialiasing.
576 // But all other widgets of this library WILL USE antialiasing because
577 // their handles are not perfectly horizontal or vertical and without
578 // antialiasing they might look terrible. Now, when antialiasing is NOT
579 // used, the line thickness is rounded. This would lead to a different
580 // thickness in this widget compared to the other widgets. This is not
581 // a good idea. Therefore, we USE antialiasing here. Anyway, in practical
582 // tests, it seems almost as sharp as without antialiasing, and
583 // additionally the position is more exact!
584 bufferPainter.setRenderHint(QPainter::Antialiasing, true);
585 QPen pen;
586 const qreal handleCoordinatePoint = d_pointer->physicalPixelLength() //
587 / devicePixelRatioF() //
588 * d_pointer->m_value;
589 if (hasFocus()) {
592 bufferPainter.setPen(pen);
593 bufferPainter.drawLine(QPointF(handleCoordinatePoint, 0), //
594 QPointF(handleCoordinatePoint, gradientThickness()));
595 }
597 pen.setColor( //
599 d_pointer->m_gradientImageParameters
600 .colorFromValue( //
601 d_pointer->m_value)
602 .first));
603 bufferPainter.setPen(pen);
604 bufferPainter.drawLine(QPointF(handleCoordinatePoint, 0), //
605 QPointF(handleCoordinatePoint, gradientThickness()));
606
607 // Paint the buffer to the actual widget
608 QTransform transform;
609 // The m_gradientImageProvider contains the gradient always
610 // in a default form, independent of the actual orientation
611 // of this widget and independent of its actual layout direction:
612 // In the default form, the first color is always on the left, and the
613 // second color is always on the right. To paint it, we have to
614 // rotate it if our actual orientation is vertical. And we have to
615 // mirror it when our actual layout direction is RTL.
616 if (d_pointer->m_orientation == Qt::Orientation::Vertical) {
617 if (layoutDirection() == Qt::LayoutDirection::RightToLeft) {
618 // Even on vertical gradients, we mirror the image, so that
619 // the well-aligned edge of the transparency background is
620 // always aligned according to the writing direction.
621 transform.scale(-1, 1);
622 transform.rotate(270);
623 transform.translate(size().height() * (-1), size().width() * (-1));
624 } else {
625 transform.rotate(270);
626 transform.translate(size().height() * (-1), 0);
627 }
628 } else {
629 if (layoutDirection() == Qt::LayoutDirection::RightToLeft) {
630 transform.scale(-1, 1);
631 transform.translate(size().width() * (-1), 0);
632 }
633 }
634 QPainter widgetPainter(this);
635 widgetPainter.setTransform(transform);
636 widgetPainter.drawImage(0, 0, paintBuffer);
637
638 // // TODO Draw a focus rectangle like this?:
639 // widgetPainter.setTransform(QTransform());
640 // if (hasFocus()) {
641 // QStyleOptionFocusRect opt;
642 // opt.palette = palette();
643 // opt.rect = rect();
644 // opt.state = QStyle::State_None |
645 // QStyle::State_KeyboardFocusChange; style()->drawPrimitive(
646 // QStyle::PE_FrameFocusRect,
647 // &opt,
648 // &widgetPainter,
649 // this
650 // );
651 // }
652}
653
654} // namespace PerceptualColor
Q_INVOKABLE AbstractDiagram(QWidget *parent=nullptr)
The constructor.
QColor handleColorFromBackgroundLightness(qreal lightness) const
An appropriate color for a handle, depending on the background lightness.
int gradientMinimumLength() const
The minimum length of a color gradient.
void callUpdate()
An alternative to QWidget::update().
int handleOutlineThickness() const
The outline thickness of a handle.
int gradientThickness() const
The thickness of a color gradient.
QColor focusIndicatorColor() const
The color for painting focus indicators.
A slider who’s groove displays an LCH color gradient.
void setFirstColorCieLchD50A(const PerceptualColor::GenericColor &newFirstColorCieLchD50A)
Setter for firstColorCieLchD50A property.
virtual QSize minimumSizeHint() const override
Recommended minimum size for the widget.
qreal value
The slider’s current value.
Q_INVOKABLE GradientSlider(const QSharedPointer< PerceptualColor::RgbColorSpace > &colorSpace, QWidget *parent=nullptr)
Constructs a vertical slider.
virtual void mouseReleaseEvent(QMouseEvent *event) override
React on a mouse release event.
void singleStepChanged(const qreal newSingleStep)
Signal for singleStep property.
virtual void mouseMoveEvent(QMouseEvent *event) override
React on a mouse move event.
virtual ~GradientSlider() noexcept override
Default destructor.
virtual QSize sizeHint() const override
Recommended size for the widget.
virtual void keyPressEvent(QKeyEvent *event) override
React on key press events.
void setSecondColorCieLchD50A(const PerceptualColor::GenericColor &newSecondColorCieLchD50A)
Setter for secondColorCieLchD50A property.
void firstColorCieLchD50AChanged(const PerceptualColor::GenericColor &newFirstColorCieLchD50A)
Signal for firstColorCieLchD50A property.
void setValue(const qreal newValue)
Setter for value property.
virtual void wheelEvent(QWheelEvent *event) override
React on a mouse wheel event.
void setSingleStep(const qreal newSingleStep)
Setter for singleStep property.
void orientationChanged(const Qt::Orientation newOrientation)
Signal for orientation property.
virtual void resizeEvent(QResizeEvent *event) override
React on a resize event.
PerceptualColor::GenericColor firstColorCieLchD50A
First color (the one corresponding to a low value)
void valueChanged(const qreal newValue)
Signal for value property.
qreal singleStep
This property holds the single step.
virtual void mousePressEvent(QMouseEvent *event) override
React on a mouse press event.
void secondColorCieLchD50AChanged(const PerceptualColor::GenericColor &newSecondColorCieLchD50A)
Signal for secondColorCieLchD50A property.
void setPageStep(const qreal newPageStep)
Setter for pageStep property.
void setColors(const PerceptualColor::GenericColor &newFirstColorCieLchD50A, const PerceptualColor::GenericColor &newSecondColorCieLchD50A)
Setter for both, firstColorCieLchD50A property and secondColorCieLchD50A property.
void setOrientation(const Qt::Orientation newOrientation)
Setter for orientation property.
PerceptualColor::GenericColor secondColorCieLchD50A
Second color (the one corresponding to a high value)
qreal pageStep
This property holds the page step.
Qt::Orientation orientation
Orientation of the widget.
void pageStepChanged(const qreal newPageStep)
Signal for pageStep property.
virtual void paintEvent(QPaintEvent *event) override
Paint the widget.
The namespace of this library.
Qt::KeyboardModifiers keyboardModifiers()
bool isNull() const const
Q_EMITQ_EMIT
QObject * parent() const const
qreal devicePixelRatioF() const const
void drawImage(const QPoint &point, const QImage &image)
void drawLine(const QLine &line)
void setPen(Qt::PenStyle style)
void setRenderHint(RenderHint hint, bool on)
void setTransform(const QTransform &transform, bool combine)
void setColor(const QColor &color)
void setWidthF(qreal width)
qreal x() const const
qreal y() const const
int height() const const
void setHeight(int height)
void setWidth(int width)
int width() const const
StrongFocus
ControlModifier
Orientation
QWidget(QWidget *parent, Qt::WindowFlags f)
virtual bool event(QEvent *event) override
bool hasFocus() const const
virtual void keyPressEvent(QKeyEvent *event)
void update()
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:46:43 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.