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, 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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in New Issue