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

KDE's Doxygen guidelines are available online.