diff --git a/src/dialogs/QskColorPicker.cpp b/src/dialogs/QskColorPicker.cpp index 8f21ae0b..7b33ac0a 100644 --- a/src/dialogs/QskColorPicker.cpp +++ b/src/dialogs/QskColorPicker.cpp @@ -12,31 +12,67 @@ QSK_SUBCONTROL( QskColorPicker, Panel ) QSK_SUBCONTROL( QskColorPicker, ColorPane ) QSK_SUBCONTROL( QskColorPicker, Selector ) +using A = QskAspect; + +namespace +{ + const auto HPos = QskColorPicker::Selector | A::Horizontal; + const auto VPos = QskColorPicker::Selector | A::Vertical; + + void createImage( QImage* image, const QSizeF& size, qreal v ) + { + if( image->size() != size ) + { + *image = QImage( size.width(), size.height(), QImage::Format_RGB32 ); + } + + QColor color; + float h, s; + + for( int x = 0; x < image->width(); x++ ) + { + h = static_cast< float >( x ) / image->width(); + + for( int y = 0; y < image->height(); y++ ) + { + s = 1.0 - static_cast< float >( y ) / image->height(); + color.setHsvF( h, s, v ); + image->setPixel( x, y, color.rgb() ); + } + } + } +} + class QskColorPicker::PrivateData { public: qreal value = 255; bool isPressed = false; - int colorChangedEventType; + QImage image; }; QskColorPicker::QskColorPicker( QQuickItem* parent ) : Inherited( parent ) , m_data( new PrivateData ) { - m_data->colorChangedEventType = QEvent::registerEventType(); - setAcceptedMouseButtons( Qt::LeftButton ); setBoundaries( 0, 255 ); + setPolishOnResize( true ); + createImage(); + setPositionHint( HPos, -1 ); + setPositionHint( VPos, -1 ); } QskColorPicker::~QskColorPicker() = default; QColor QskColorPicker::selectedColor() const { - auto* skinlet = static_cast< const QskColorPickerSkinlet* >( effectiveSkinlet() ); - Q_ASSERT( skinlet ); - return skinlet->selectedColor(); + if( image().isNull() ) + { + return {}; + } + + return m_data->image.pixelColor( position().toPoint() ); } qreal QskColorPicker::value() const @@ -49,9 +85,9 @@ qreal QskColorPicker::valueAsRatio() const return valueAsRatio( m_data->value ); } -int QskColorPicker::colorChangedEventType() const +QImage QskColorPicker::image() const { - return m_data->colorChangedEventType; + return m_data->image; } void QskColorPicker::setValue( qreal v ) @@ -59,8 +95,10 @@ void QskColorPicker::setValue( qreal v ) if( !qskFuzzyCompare( m_data->value, v ) ) { m_data->value = v; + createImage(); update(); Q_EMIT valueChanged( m_data->value ); + Q_EMIT selectedColorChanged(); } } @@ -70,22 +108,16 @@ void QskColorPicker::setValueAsRatio( qreal ratio ) setValue( minimum() + ratio * boundaryLength() ); } -bool QskColorPicker::event( QEvent* event ) +void QskColorPicker::updateLayout() { - if( event->type() == colorChangedEventType() ) - { - event->setAccepted( true ); - Q_EMIT selectedColorChanged(); - return true; - } - - return Inherited::event( event ); + createImage(); + updatePosition( position() ); } void QskColorPicker::mousePressEvent( QMouseEvent* event ) { m_data->isPressed = true; - updatePosition( event ); + updatePosition( qskMousePosition( event ) ); } void QskColorPicker::mouseMoveEvent( QMouseEvent* event ) @@ -95,7 +127,7 @@ void QskColorPicker::mouseMoveEvent( QMouseEvent* event ) return; } - updatePosition( event ); + updatePosition( qskMousePosition( event ) ); } void QskColorPicker::mouseReleaseEvent( QMouseEvent* ) @@ -103,24 +135,51 @@ void QskColorPicker::mouseReleaseEvent( QMouseEvent* ) m_data->isPressed = false; } -void QskColorPicker::updatePosition( QMouseEvent* event ) +void QskColorPicker::updatePosition( const QPointF& point ) { - auto p = qskMousePosition( event ); const auto rect = subControlRect( ColorPane ); - p.rx() = qBound( rect.x(), p.x(), rect.right() ); - p.ry() = qBound( rect.y(), p.y(), rect.bottom() ); + if( rect.isEmpty() ) + { + return; + } - const auto oldX = positionHint( Selector | QskAspect::Horizontal ); - const auto oldY = positionHint( Selector | QskAspect::Vertical ); + auto p = point; + p.rx() = qBound( rect.x(), p.x(), rect.right() - 1.0 ); + p.ry() = qBound( rect.y(), p.y(), rect.bottom() - 1.0 ); + + const auto oldX = positionHint( HPos ); + const auto oldY = positionHint( VPos ); if( !qskFuzzyCompare( p.x(), oldX ) || !qskFuzzyCompare( p.y(), oldY ) ) { - setPositionHint( Selector | QskAspect::Horizontal, p.x() ); - setPositionHint( Selector | QskAspect::Vertical, p.y() ); + setPositionHint( HPos, p.x() ); + setPositionHint( VPos, p.y() ); update(); + Q_EMIT positionChanged(); + Q_EMIT selectedColorChanged(); } } +QPointF QskColorPicker::position() const +{ + const auto r = subControlRect( ColorPane ); + + if( !r.size().isValid() ) + { + return {}; + } + + const auto x = positionHint( HPos ); + const auto y = positionHint( VPos ); + return { x, y }; +} + +void QskColorPicker::createImage() +{ + const auto r = subControlRect( ColorPane ); + ::createImage( &m_data->image, r.size(), valueAsRatio() ); +} + #include "moc_QskColorPicker.cpp" diff --git a/src/dialogs/QskColorPicker.h b/src/dialogs/QskColorPicker.h index fa28e12c..57fa84eb 100644 --- a/src/dialogs/QskColorPicker.h +++ b/src/dialogs/QskColorPicker.h @@ -28,7 +28,8 @@ class QskColorPicker : public QskBoundedControl qreal valueAsRatio() const; // [0.0, 1.0] using QskBoundedControl::valueAsRatio; - int colorChangedEventType() const; + QImage image() const; + QPointF position() const; public Q_SLOTS: void setValue( qreal ); @@ -37,15 +38,17 @@ class QskColorPicker : public QskBoundedControl Q_SIGNALS: void valueChanged( qreal ); void selectedColorChanged() const; + void positionChanged() const; protected: - bool event( QEvent* ) override; + void updateLayout() override; void mousePressEvent( QMouseEvent* ) override; void mouseMoveEvent( QMouseEvent* ) override; void mouseReleaseEvent( QMouseEvent* ) override; private: - void updatePosition( QMouseEvent* ); + void updatePosition( const QPointF& ); + void createImage(); class PrivateData; std::unique_ptr< PrivateData > m_data; diff --git a/src/dialogs/QskColorPickerSkinlet.cpp b/src/dialogs/QskColorPickerSkinlet.cpp index d6ea1b49..200d9256 100644 --- a/src/dialogs/QskColorPickerSkinlet.cpp +++ b/src/dialogs/QskColorPickerSkinlet.cpp @@ -22,64 +22,34 @@ namespace { } - void paint( QPainter* p, const QSize& size, const void* nodeData ) override + void paint( QPainter* p, const QSize&, const void* nodeData ) override { - if( m_image.size() != size ) - { - m_image = QImage( size.width(), size.height(), QImage::Format_RGB32 ); - } - - QColor color; - float h, s; - const float v = *reinterpret_cast< const int* >( nodeData ) / 255.0; - - for( int x = 0; x < m_image.width(); x++ ) - { - h = ( float ) x / m_image.width(); - - for( int y = 0; y < m_image.height(); y++ ) - { - s = 1.0 - ( float ) y / m_image.height(); - color.setHsvF( h, s, v ); - m_image.setPixel( x, y, color.rgb() ); - } - } - - p->drawImage( QPointF( 0, 0 ), m_image ); + const Q* q = static_cast< const Q* >( nodeData ); + p->drawImage( QPointF( 0, 0 ), q->image() ); } - void updateNode( QQuickWindow* window, const QRectF& rect, int value ) + void updateNode( QQuickWindow* window, const QRectF& rect, const Q* q ) { - update( window, rect, QSizeF(), &value ); - } - - QColor selectedColor( const QPointF& p ) const - { - return m_image.pixelColor( p.toPoint() ); + update( window, rect, QSizeF(), q ); } protected: QskHashValue hash( const void* nodeData ) const override { - const auto* value = reinterpret_cast< const int* >( nodeData ); - return *value; - } + const Q* q = static_cast< const Q* >( nodeData ); + const auto r = q->subControlRect( Q::ColorPane ); - private: - QImage m_image; + QskHashValue h = qHash( r.width() ); + h = qHash( r.height() ); + h = qHash( q->value() ); + + return h; + } }; } -class QskColorPickerSkinlet::PrivateData -{ - public: - QColor selectedColor; - ColorPaneNode* colorPaneNode = nullptr; -}; - QskColorPickerSkinlet::QskColorPickerSkinlet( QskSkin* skin ) : Inherited( skin ) - , m_data( new PrivateData ) { setNodeRoles( { PanelRole, ColorPaneRole, SelectorRole } ); } @@ -103,9 +73,7 @@ QSGNode* QskColorPickerSkinlet::updateSubNode( } case SelectorRole: { - auto* n = updateBoxNode( skinnable, node, Q::Selector ); - updateSelectedColor( q ); - return n; + return updateBoxNode( skinnable, node, Q::Selector ); } } @@ -125,57 +93,26 @@ QRectF QskColorPickerSkinlet::subControlRect( if( subControl == Q::Selector ) { - const auto size = q->strutSizeHint( Q::Selector ); - const auto x = q->positionHint( Q::Selector | QskAspect::Horizontal ); - const auto y = q->positionHint( Q::Selector | QskAspect::Vertical ); + const auto s = q->strutSizeHint( Q::Selector ); + const auto p = q->position(); - QRectF r( { x - size.width() / 2.0, y - size.height() / 2.0 }, size ); + const QRectF r( { p.x() - s.width() / 2.0, p.y() - s.height() / 2.0 }, s ); return r; } return Inherited::subControlRect( skinnable, contentsRect, subControl ); } -QColor QskColorPickerSkinlet::selectedColor() const -{ - return m_data->selectedColor; -} - QSGNode* QskColorPickerSkinlet::updateColorPaneNode( const QskColorPicker* q, QSGNode* node ) const { - m_data->colorPaneNode = QskSGNode::ensureNode< ColorPaneNode >( node ); - - const auto rect = q->subControlRect( Q::ColorPane ); - m_data->colorPaneNode->updateNode( q->window(), rect, q->value() ); - - updateSelectedColor( q ); - - return m_data->colorPaneNode; -} - -QPointF QskColorPickerSkinlet::selectorPos( const Q* q ) const -{ - const auto x = q->positionHint( Q::Selector | QskAspect::Horizontal ); - const auto y = q->positionHint( Q::Selector | QskAspect::Vertical ); - - QPointF p( x, y ); + auto* colorPaneNode = QskSGNode::ensureNode< ColorPaneNode >( node ); const auto rect = q->subControlRect( Q::ColorPane ); - p.rx() = qBound( rect.x(), p.x(), rect.right() ); - p.ry() = qBound( rect.y(), p.y(), rect.bottom() ); + colorPaneNode->updateNode( q->window(), rect, q ); - return p; -} - -void QskColorPickerSkinlet::updateSelectedColor( const Q* q ) const -{ - const auto color = m_data->colorPaneNode->selectedColor( selectorPos( q ) ); - m_data->selectedColor = color; - - auto* e = new QEvent( static_cast< QEvent::Type >( q->colorChangedEventType() ) ); - QCoreApplication::postEvent( const_cast< Q* >( q ), e ); + return colorPaneNode; } #include "moc_QskColorPickerSkinlet.cpp" diff --git a/src/dialogs/QskColorPickerSkinlet.h b/src/dialogs/QskColorPickerSkinlet.h index 2bb7d844..5e552ac7 100644 --- a/src/dialogs/QskColorPickerSkinlet.h +++ b/src/dialogs/QskColorPickerSkinlet.h @@ -42,11 +42,6 @@ class QskColorPickerSkinlet : public QskSkinlet private: QRectF cursorRect( const QskSkinnable*, const QRectF&, int index ) const; - QPointF selectorPos( const QskColorPicker* ) const; - void updateSelectedColor( const QskColorPicker* ) const; - - class PrivateData; - std::unique_ptr< PrivateData > m_data; }; #endif diff --git a/src/dialogs/QskDialog.cpp b/src/dialogs/QskDialog.cpp index 661caf79..2d83bc64 100644 --- a/src/dialogs/QskDialog.cpp +++ b/src/dialogs/QskDialog.cpp @@ -479,7 +479,7 @@ namespace outerBox->setMargins( 20 ); outerBox->setSpacing( 20 ); #if 1 - outerBox->setFixedSize( 700, 500 ); + outerBox->setFixedSize( 500, 500 ); #endif auto* upperBox = new QskLinearBox( Qt::Horizontal, outerBox ); upperBox->setSpacing( 12 );