create image on main thread
This commit is contained in:
parent
e36aa93557
commit
ed562d092a
|
@ -12,31 +12,67 @@ QSK_SUBCONTROL( QskColorPicker, Panel )
|
||||||
QSK_SUBCONTROL( QskColorPicker, ColorPane )
|
QSK_SUBCONTROL( QskColorPicker, ColorPane )
|
||||||
QSK_SUBCONTROL( QskColorPicker, Selector )
|
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
|
class QskColorPicker::PrivateData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
qreal value = 255;
|
qreal value = 255;
|
||||||
bool isPressed = false;
|
bool isPressed = false;
|
||||||
int colorChangedEventType;
|
QImage image;
|
||||||
};
|
};
|
||||||
|
|
||||||
QskColorPicker::QskColorPicker( QQuickItem* parent )
|
QskColorPicker::QskColorPicker( QQuickItem* parent )
|
||||||
: Inherited( parent )
|
: Inherited( parent )
|
||||||
, m_data( new PrivateData )
|
, m_data( new PrivateData )
|
||||||
{
|
{
|
||||||
m_data->colorChangedEventType = QEvent::registerEventType();
|
|
||||||
|
|
||||||
setAcceptedMouseButtons( Qt::LeftButton );
|
setAcceptedMouseButtons( Qt::LeftButton );
|
||||||
setBoundaries( 0, 255 );
|
setBoundaries( 0, 255 );
|
||||||
|
setPolishOnResize( true );
|
||||||
|
createImage();
|
||||||
|
setPositionHint( HPos, -1 );
|
||||||
|
setPositionHint( VPos, -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
QskColorPicker::~QskColorPicker() = default;
|
QskColorPicker::~QskColorPicker() = default;
|
||||||
|
|
||||||
QColor QskColorPicker::selectedColor() const
|
QColor QskColorPicker::selectedColor() const
|
||||||
{
|
{
|
||||||
auto* skinlet = static_cast< const QskColorPickerSkinlet* >( effectiveSkinlet() );
|
if( image().isNull() )
|
||||||
Q_ASSERT( skinlet );
|
{
|
||||||
return skinlet->selectedColor();
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_data->image.pixelColor( position().toPoint() );
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal QskColorPicker::value() const
|
qreal QskColorPicker::value() const
|
||||||
|
@ -49,9 +85,9 @@ qreal QskColorPicker::valueAsRatio() const
|
||||||
return valueAsRatio( m_data->value );
|
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 )
|
void QskColorPicker::setValue( qreal v )
|
||||||
|
@ -59,8 +95,10 @@ void QskColorPicker::setValue( qreal v )
|
||||||
if( !qskFuzzyCompare( m_data->value, v ) )
|
if( !qskFuzzyCompare( m_data->value, v ) )
|
||||||
{
|
{
|
||||||
m_data->value = v;
|
m_data->value = v;
|
||||||
|
createImage();
|
||||||
update();
|
update();
|
||||||
Q_EMIT valueChanged( m_data->value );
|
Q_EMIT valueChanged( m_data->value );
|
||||||
|
Q_EMIT selectedColorChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,22 +108,16 @@ void QskColorPicker::setValueAsRatio( qreal ratio )
|
||||||
setValue( minimum() + ratio * boundaryLength() );
|
setValue( minimum() + ratio * boundaryLength() );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QskColorPicker::event( QEvent* event )
|
void QskColorPicker::updateLayout()
|
||||||
{
|
{
|
||||||
if( event->type() == colorChangedEventType() )
|
createImage();
|
||||||
{
|
updatePosition( position() );
|
||||||
event->setAccepted( true );
|
|
||||||
Q_EMIT selectedColorChanged();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Inherited::event( event );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskColorPicker::mousePressEvent( QMouseEvent* event )
|
void QskColorPicker::mousePressEvent( QMouseEvent* event )
|
||||||
{
|
{
|
||||||
m_data->isPressed = true;
|
m_data->isPressed = true;
|
||||||
updatePosition( event );
|
updatePosition( qskMousePosition( event ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskColorPicker::mouseMoveEvent( QMouseEvent* event )
|
void QskColorPicker::mouseMoveEvent( QMouseEvent* event )
|
||||||
|
@ -95,7 +127,7 @@ void QskColorPicker::mouseMoveEvent( QMouseEvent* event )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePosition( event );
|
updatePosition( qskMousePosition( event ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskColorPicker::mouseReleaseEvent( QMouseEvent* )
|
void QskColorPicker::mouseReleaseEvent( QMouseEvent* )
|
||||||
|
@ -103,24 +135,51 @@ void QskColorPicker::mouseReleaseEvent( QMouseEvent* )
|
||||||
m_data->isPressed = false;
|
m_data->isPressed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskColorPicker::updatePosition( QMouseEvent* event )
|
void QskColorPicker::updatePosition( const QPointF& point )
|
||||||
{
|
{
|
||||||
auto p = qskMousePosition( event );
|
|
||||||
const auto rect = subControlRect( ColorPane );
|
const auto rect = subControlRect( ColorPane );
|
||||||
|
|
||||||
p.rx() = qBound( rect.x(), p.x(), rect.right() );
|
if( rect.isEmpty() )
|
||||||
p.ry() = qBound( rect.y(), p.y(), rect.bottom() );
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto oldX = positionHint( Selector | QskAspect::Horizontal );
|
auto p = point;
|
||||||
const auto oldY = positionHint( Selector | QskAspect::Vertical );
|
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 ) )
|
if( !qskFuzzyCompare( p.x(), oldX ) || !qskFuzzyCompare( p.y(), oldY ) )
|
||||||
{
|
{
|
||||||
setPositionHint( Selector | QskAspect::Horizontal, p.x() );
|
setPositionHint( HPos, p.x() );
|
||||||
setPositionHint( Selector | QskAspect::Vertical, p.y() );
|
setPositionHint( VPos, p.y() );
|
||||||
|
|
||||||
update();
|
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"
|
#include "moc_QskColorPicker.cpp"
|
||||||
|
|
|
@ -28,7 +28,8 @@ class QskColorPicker : public QskBoundedControl
|
||||||
qreal valueAsRatio() const; // [0.0, 1.0]
|
qreal valueAsRatio() const; // [0.0, 1.0]
|
||||||
using QskBoundedControl::valueAsRatio;
|
using QskBoundedControl::valueAsRatio;
|
||||||
|
|
||||||
int colorChangedEventType() const;
|
QImage image() const;
|
||||||
|
QPointF position() const;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void setValue( qreal );
|
void setValue( qreal );
|
||||||
|
@ -37,15 +38,17 @@ class QskColorPicker : public QskBoundedControl
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void valueChanged( qreal );
|
void valueChanged( qreal );
|
||||||
void selectedColorChanged() const;
|
void selectedColorChanged() const;
|
||||||
|
void positionChanged() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool event( QEvent* ) override;
|
void updateLayout() override;
|
||||||
void mousePressEvent( QMouseEvent* ) override;
|
void mousePressEvent( QMouseEvent* ) override;
|
||||||
void mouseMoveEvent( QMouseEvent* ) override;
|
void mouseMoveEvent( QMouseEvent* ) override;
|
||||||
void mouseReleaseEvent( QMouseEvent* ) override;
|
void mouseReleaseEvent( QMouseEvent* ) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updatePosition( QMouseEvent* );
|
void updatePosition( const QPointF& );
|
||||||
|
void createImage();
|
||||||
|
|
||||||
class PrivateData;
|
class PrivateData;
|
||||||
std::unique_ptr< PrivateData > m_data;
|
std::unique_ptr< PrivateData > m_data;
|
||||||
|
|
|
@ -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 )
|
const Q* q = static_cast< const Q* >( nodeData );
|
||||||
{
|
p->drawImage( QPointF( 0, 0 ), q->image() );
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateNode( QQuickWindow* window, const QRectF& rect, int value )
|
void updateNode( QQuickWindow* window, const QRectF& rect, const Q* q )
|
||||||
{
|
{
|
||||||
update( window, rect, QSizeF(), &value );
|
update( window, rect, QSizeF(), q );
|
||||||
}
|
|
||||||
|
|
||||||
QColor selectedColor( const QPointF& p ) const
|
|
||||||
{
|
|
||||||
return m_image.pixelColor( p.toPoint() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QskHashValue hash( const void* nodeData ) const override
|
QskHashValue hash( const void* nodeData ) const override
|
||||||
{
|
{
|
||||||
const auto* value = reinterpret_cast< const int* >( nodeData );
|
const Q* q = static_cast< const Q* >( nodeData );
|
||||||
return *value;
|
const auto r = q->subControlRect( Q::ColorPane );
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
QskHashValue h = qHash( r.width() );
|
||||||
QImage m_image;
|
h = qHash( r.height() );
|
||||||
|
h = qHash( q->value() );
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class QskColorPickerSkinlet::PrivateData
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QColor selectedColor;
|
|
||||||
ColorPaneNode* colorPaneNode = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
QskColorPickerSkinlet::QskColorPickerSkinlet( QskSkin* skin )
|
QskColorPickerSkinlet::QskColorPickerSkinlet( QskSkin* skin )
|
||||||
: Inherited( skin )
|
: Inherited( skin )
|
||||||
, m_data( new PrivateData )
|
|
||||||
{
|
{
|
||||||
setNodeRoles( { PanelRole, ColorPaneRole, SelectorRole } );
|
setNodeRoles( { PanelRole, ColorPaneRole, SelectorRole } );
|
||||||
}
|
}
|
||||||
|
@ -103,9 +73,7 @@ QSGNode* QskColorPickerSkinlet::updateSubNode(
|
||||||
}
|
}
|
||||||
case SelectorRole:
|
case SelectorRole:
|
||||||
{
|
{
|
||||||
auto* n = updateBoxNode( skinnable, node, Q::Selector );
|
return updateBoxNode( skinnable, node, Q::Selector );
|
||||||
updateSelectedColor( q );
|
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,57 +93,26 @@ QRectF QskColorPickerSkinlet::subControlRect(
|
||||||
|
|
||||||
if( subControl == Q::Selector )
|
if( subControl == Q::Selector )
|
||||||
{
|
{
|
||||||
const auto size = q->strutSizeHint( Q::Selector );
|
const auto s = q->strutSizeHint( Q::Selector );
|
||||||
const auto x = q->positionHint( Q::Selector | QskAspect::Horizontal );
|
const auto p = q->position();
|
||||||
const auto y = q->positionHint( Q::Selector | QskAspect::Vertical );
|
|
||||||
|
|
||||||
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 r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor QskColorPickerSkinlet::selectedColor() const
|
|
||||||
{
|
|
||||||
return m_data->selectedColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
QSGNode* QskColorPickerSkinlet::updateColorPaneNode(
|
QSGNode* QskColorPickerSkinlet::updateColorPaneNode(
|
||||||
const QskColorPicker* q, QSGNode* node ) const
|
const QskColorPicker* q, QSGNode* node ) const
|
||||||
{
|
{
|
||||||
m_data->colorPaneNode = QskSGNode::ensureNode< ColorPaneNode >( node );
|
auto* 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 );
|
|
||||||
|
|
||||||
const auto rect = q->subControlRect( Q::ColorPane );
|
const auto rect = q->subControlRect( Q::ColorPane );
|
||||||
|
|
||||||
p.rx() = qBound( rect.x(), p.x(), rect.right() );
|
colorPaneNode->updateNode( q->window(), rect, q );
|
||||||
p.ry() = qBound( rect.y(), p.y(), rect.bottom() );
|
|
||||||
|
|
||||||
return p;
|
return colorPaneNode;
|
||||||
}
|
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_QskColorPickerSkinlet.cpp"
|
#include "moc_QskColorPickerSkinlet.cpp"
|
||||||
|
|
|
@ -42,11 +42,6 @@ class QskColorPickerSkinlet : public QskSkinlet
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QRectF cursorRect( const QskSkinnable*, const QRectF&, int index ) const;
|
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
|
#endif
|
||||||
|
|
|
@ -479,7 +479,7 @@ namespace
|
||||||
outerBox->setMargins( 20 );
|
outerBox->setMargins( 20 );
|
||||||
outerBox->setSpacing( 20 );
|
outerBox->setSpacing( 20 );
|
||||||
#if 1
|
#if 1
|
||||||
outerBox->setFixedSize( 700, 500 );
|
outerBox->setFixedSize( 500, 500 );
|
||||||
#endif
|
#endif
|
||||||
auto* upperBox = new QskLinearBox( Qt::Horizontal, outerBox );
|
auto* upperBox = new QskLinearBox( Qt::Horizontal, outerBox );
|
||||||
upperBox->setSpacing( 12 );
|
upperBox->setSpacing( 12 );
|
||||||
|
|
Loading…
Reference in New Issue