create image on main thread

This commit is contained in:
Peter Hartmann 2025-01-28 10:43:22 +01:00
parent e36aa93557
commit ed562d092a
5 changed files with 113 additions and 119 deletions

View File

@ -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"

View File

@ -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;

View File

@ -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"

View File

@ -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

View File

@ -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 );