Commit a1921136 authored by Erwan Tulou's avatar Erwan Tulou

skins2: improve refresh of layouts

Up to now, notification of invalidated subareas was available for controls
but yet, the layout always ended up being totally rebuilt. For instance,
 a small animated image meant a total rebuild of everything. For simple skins,
 this could go unnoticed, but old computers had much difficulty with more
 complex skins (e.g wmp11), that were mostly busy rebuilding layouts
 over and over.

This patch ensures that only what needs to be rebuilt is rebuilt. Some skins
 like wmp11 on Linux do show dramatic improvement with this one patch.
parent 6fad8bff
......@@ -114,16 +114,22 @@ bool CtrlButton::mouseOver( int x, int y ) const
}
void CtrlButton::draw( OSGraphics &rImage, int xDest, int yDest )
{
if( m_pImg )
void CtrlButton::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h )
{
const Position *pPos = getPosition();
rect region( pPos->getLeft(), pPos->getTop(),
pPos->getWidth(), pPos->getHeight() );
rect clip( xDest, yDest, w, h );
rect inter;
if( rect::intersect( region, clip, &inter ) && m_pImg )
{
// Draw the current image
m_pImg->draw( rImage, xDest, yDest );
m_pImg->draw( rImage, inter.x, inter.y, inter.width, inter.height,
inter.x - pPos->getLeft(),
inter.y - pPos->getTop() );
}
}
void CtrlButton::setImage( AnimBitmap *pImg )
{
AnimBitmap *pOldImg = m_pImg;
......@@ -147,7 +153,7 @@ void CtrlButton::setImage( AnimBitmap *pImg )
void CtrlButton::onUpdate( Subject<AnimBitmap> &rBitmap, void *arg )
{
notifyLayout();
notifyLayout( m_pImg->getWidth(), m_pImg->getHeight() );
}
......
......@@ -57,7 +57,7 @@ public:
virtual bool mouseOver( int x, int y ) const;
/// Draw the control on the given graphics
virtual void draw( OSGraphics &rImage, int xDest, int yDest );
virtual void draw( OSGraphics &rImage, int xDest, int yDest, int w, int h );
/// Get the text of the tooltip
virtual UString getTooltipText() const { return m_tooltip; }
......
......@@ -134,12 +134,25 @@ bool CtrlCheckbox::mouseOver( int x, int y ) const
}
void CtrlCheckbox::draw( OSGraphics &rImage, int xDest, int yDest )
void CtrlCheckbox::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h )
{
if( m_pImgCurrent )
if( !m_pImgCurrent )
return;
const Position *pPos = getPosition();
// rect region( pPos->getLeft(), pPos->getTop(),
// pPos->getWidth(), pPos->getHeight() );
rect region( pPos->getLeft(), pPos->getTop(),
m_pImgCurrent->getWidth(), m_pImgCurrent->getHeight() );
rect clip( xDest, yDest, w, h );
rect inter;
if( rect::intersect( region, clip, &inter ) )
{
// Draw the current image
m_pImgCurrent->draw( rImage, xDest, yDest );
m_pImgCurrent->draw( rImage,
inter.x, inter.y, inter.width, inter.height,
inter.x - pPos->getLeft(),
inter.y - pPos->getTop() );
}
}
......@@ -248,7 +261,7 @@ void CtrlCheckbox::onVarBoolUpdate( VarBool &rVariable )
void CtrlCheckbox::onUpdate( Subject<AnimBitmap> &rBitmap, void *arg )
{
notifyLayout();
notifyLayout( m_pImgCurrent->getWidth(), m_pImgCurrent->getHeight() );
}
......
......@@ -61,7 +61,7 @@ public:
virtual bool mouseOver( int x, int y ) const;
/// Draw the control on the given graphics
virtual void draw( OSGraphics &rImage, int xDest, int yDest );
virtual void draw( OSGraphics &rImage, int xDest, int yDest, int w, int h );
/// Get the text of the tooltip XXX
virtual UString getTooltipText() const { return *m_pTooltip; }
......
......@@ -74,8 +74,11 @@ void CtrlGeneric::unsetLayout()
}
void CtrlGeneric::notifyLayout( int width, int height,
int xOffSet, int yOffSet ) const
int xOffSet, int yOffSet )
{
width = ( width > 0 ) ? width : m_pPosition->getWidth();
height = ( height > 0 ) ? height : m_pPosition->getHeight();
// Notify the layout
if( m_pLayout )
{
......
......@@ -53,7 +53,7 @@ public:
virtual bool mouseOver( int x, int y ) const { return false; }
/// Draw the control on the given graphics
virtual void draw( OSGraphics &rImage, int xDest, int yDest ) { }
virtual void draw( OSGraphics &rImage, int xDest, int yDest, int w, int h ) { }
/// Set the position and the associated layout of the control
virtual void setLayout( GenericLayout *pLayout,
......@@ -96,7 +96,7 @@ protected:
* Use the default values to repaint the whole window
*/
virtual void notifyLayout( int witdh = -1, int height = -1,
int xOffSet = 0, int yOffSet = 0 ) const;
int xOffSet = 0, int yOffSet = 0 );
/**
* Same as notifyLayout(), but takes optional images as parameters.
......
......@@ -118,7 +118,7 @@ bool CtrlImage::mouseOver( int x, int y ) const
}
void CtrlImage::draw( OSGraphics &rImage, int xDest, int yDest )
void CtrlImage::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h )
{
const Position *pPos = getPosition();
if( !pPos )
......@@ -129,6 +129,13 @@ void CtrlImage::draw( OSGraphics &rImage, int xDest, int yDest )
if( width <= 0 || height <= 0 )
return;
rect region( pPos->getLeft(), pPos->getTop(),
pPos->getWidth(), pPos->getHeight() );
rect clip( xDest, yDest, w, h );
rect inter;
if( !rect::intersect( region, clip, &inter ) )
return;
if( m_resizeMethod == kScale )
{
// Use scaling method
......@@ -142,25 +149,40 @@ void CtrlImage::draw( OSGraphics &rImage, int xDest, int yDest )
m_pImage = pOsFactory->createOSGraphics( width, height );
m_pImage->drawBitmap( bmp, 0, 0 );
}
rImage.drawGraphics( *m_pImage, 0, 0, xDest, yDest );
rImage.drawGraphics( *m_pImage,
inter.x - pPos->getLeft(),
inter.y - pPos->getTop(),
inter.x, inter.y,
inter.width, inter.height );
}
else if( m_resizeMethod == kMosaic )
{
int xDest0 = pPos->getLeft();
int yDest0 = pPos->getTop();
// Use mosaic method
while( width > 0 )
{
int curWidth = __MIN( width, m_pImage->getWidth() );
height = pPos->getHeight();
int curYDest = yDest;
int curYDest = yDest0;
while( height > 0 )
{
int curHeight = __MIN( height, m_pImage->getHeight() );
rImage.drawGraphics( *m_pImage, 0, 0, xDest, curYDest,
curWidth, curHeight );
rect region1( xDest0, curYDest, curWidth, curHeight );
rect inter1;
if( rect::intersect( region1, clip, &inter1 ) )
{
rImage.drawGraphics( *m_pImage,
inter1.x - region1.x,
inter1.y - region1.y,
inter1.x, inter1.y,
inter1.width, inter1.height );
}
curYDest += curHeight;
height -= m_pImage->getHeight();
}
xDest += curWidth;
xDest0 += curWidth;
width -= m_pImage->getWidth();
}
}
......@@ -202,7 +224,16 @@ void CtrlImage::draw( OSGraphics &rImage, int xDest, int yDest )
}
// draw the scaled image at offset (m_x, m_y) from control origin
rImage.drawGraphics( *m_pImage, 0, 0, xDest + m_x, yDest + m_y );
rect region1( pPos->getLeft() + m_x, pPos->getTop() + m_y, w, h );
rect inter1;
if( rect::intersect( region1, inter, &inter1 ) )
{
rImage.drawGraphics( *m_pImage,
inter1.x - pPos->getLeft() - m_x,
inter1.y - pPos->getTop() - m_y,
inter1.x, inter1.y,
inter1.width, inter1.height );
}
}
}
......
......@@ -60,7 +60,7 @@ public:
virtual bool mouseOver( int x, int y ) const;
/// Draw the control on the given graphics
virtual void draw( OSGraphics &rImage, int xDest, int yDest );
virtual void draw( OSGraphics &rImage, int xDest, int yDest, int w, int h );
/// Get the type of control (custom RTTI)
virtual string getType() const { return "image"; }
......
......@@ -349,11 +349,19 @@ bool CtrlList::mouseOver( int x, int y ) const
}
void CtrlList::draw( OSGraphics &rImage, int xDest, int yDest )
void CtrlList::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h )
{
if( m_pImage )
const Position *pPos = getPosition();
rect region( pPos->getLeft(), pPos->getTop(),
pPos->getWidth(), pPos->getHeight() );
rect clip( xDest, yDest, w, h );
rect inter;
if( rect::intersect( region, clip, &inter ) && m_pImage )
{
rImage.drawGraphics( *m_pImage, 0, 0, xDest, yDest );
rImage.drawGraphics( *m_pImage,
inter.x - pPos->getLeft(),
inter.y - pPos->getTop(),
inter.x, inter.y, inter.width, inter.height );
}
}
......
......@@ -53,7 +53,7 @@ public:
virtual bool mouseOver( int x, int y ) const;
/// Draw the control on the given graphics
virtual void draw( OSGraphics &rImage, int xDest, int yDest );
virtual void draw( OSGraphics &rImage, int xDest, int yDest, int w, int h );
/// Called when the layout is resized
virtual void onResize();
......
......@@ -66,9 +66,9 @@ bool CtrlMove::mouseOver( int x, int y ) const
}
void CtrlMove::draw( OSGraphics &rImage, int xDest, int yDest )
void CtrlMove::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h )
{
m_rCtrl.draw( rImage, xDest, yDest );
m_rCtrl.draw( rImage, xDest, yDest, w, h );
}
......
......@@ -49,7 +49,7 @@ public:
virtual bool mouseOver( int x, int y ) const;
/// Draw the control on the given graphics
virtual void draw( OSGraphics &rImage, int xDest, int yDest );
virtual void draw( OSGraphics &rImage, int xDest, int yDest, int w, int h );
/// Set the position and the associated layout of the decorated control
virtual void setLayout( GenericLayout *pLayout,
......
......@@ -90,18 +90,33 @@ bool CtrlRadialSlider::mouseOver( int x, int y ) const
}
void CtrlRadialSlider::draw( OSGraphics &rImage, int xDest, int yDest )
void CtrlRadialSlider::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h )
{
rImage.drawGraphics( *m_pImgSeq, 0, m_position * m_height, xDest, yDest,
m_width, m_height );
const Position *pPos = getPosition();
rect region( pPos->getLeft(), pPos->getTop(), m_width, m_height );
rect clip( xDest, yDest, w ,h );
rect inter;
if( rect::intersect( region, clip, &inter ) )
rImage.drawGraphics( *m_pImgSeq,
inter.x - region.x,
inter.y - region.y + m_position * m_height,
inter.x, inter.y,
inter.width, inter.height );
}
void CtrlRadialSlider::onUpdate( Subject<VarPercent> &rVariable,
void *arg )
{
m_position = (int)( m_rVariable.get() * ( m_numImg - 1 ) );
notifyLayout( m_width, m_height );
if( &rVariable == &m_rVariable )
{
int position = (int)( m_rVariable.get() * ( m_numImg - 1 ) );
if( position == m_position )
return;
m_position = position;
notifyLayout( m_width, m_height );
}
}
......
......@@ -55,7 +55,7 @@ public:
virtual bool mouseOver( int x, int y ) const;
/// Draw the control on the given graphics
virtual void draw( OSGraphics &rImage, int xDest, int yDest );
virtual void draw( OSGraphics &rImage, int xDest, int yDest, int w, int h );
/// Get the type of control (custom RTTI)
virtual string getType() const { return "radial_slider"; }
......
......@@ -75,9 +75,9 @@ bool CtrlResize::mouseOver( int x, int y ) const
}
void CtrlResize::draw( OSGraphics &rImage, int xDest, int yDest )
void CtrlResize::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h )
{
m_rCtrl.draw( rImage, xDest, yDest );
m_rCtrl.draw( rImage, xDest, yDest, w, h );
}
......
......@@ -50,7 +50,7 @@ public:
virtual bool mouseOver( int x, int y ) const;
/// Draw the control on the given graphics
virtual void draw( OSGraphics &rImage, int xDest, int yDest );
virtual void draw( OSGraphics &rImage, int xDest, int yDest, int w, int h );
/// Set the position and the associated layout of the decorated control
virtual void setLayout( GenericLayout *pLayout,
......
......@@ -143,24 +143,65 @@ bool CtrlSliderCursor::mouseOver( int x, int y ) const
}
void CtrlSliderCursor::draw( OSGraphics &rImage, int xDest, int yDest )
void CtrlSliderCursor::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h )
{
if( m_pImg )
{
// Compute the position of the cursor
int xPos, yPos;
m_rCurve.getPoint( m_rVariable.get(), xPos, yPos );
// Draw the current image
rect inter;
rect clip( xDest, yDest, w, h);
if( rect::intersect( m_currentCursorRect, clip, &inter ) )
rImage.drawGraphics( *m_pImg,
inter.x - m_currentCursorRect.x,
inter.y - m_currentCursorRect.y,
inter.x, inter.y, inter.width, inter.height );
}
}
// Compute the resize factors
float factorX, factorY;
getResizeFactors( factorX, factorY );
xPos = (int)(xPos * factorX);
yPos = (int)(yPos * factorY);
// Draw the current image
rImage.drawGraphics( *m_pImg, 0, 0,
xDest + xPos - m_pImg->getWidth() / 2,
yDest + yPos - m_pImg->getHeight() / 2 );
void CtrlSliderCursor::onPositionChange()
{
// Compute the position of the cursor
int xPos, yPos;
m_rCurve.getPoint( m_rVariable.get(), xPos, yPos );
// Compute the resize factors
float factorX, factorY;
getResizeFactors( factorX, factorY );
xPos = (int)(xPos * factorX);
yPos = (int)(yPos * factorY);
const Position *pPos = getPosition();
int x = pPos->getLeft() + xPos - m_pImg->getWidth() / 2;
int y = pPos->getTop() + yPos - m_pImg->getHeight() / 2;
m_currentCursorRect = rect( x, y, m_pImg->getWidth(), m_pImg->getHeight() );
}
void CtrlSliderCursor::onResize()
{
onPositionChange();
}
void CtrlSliderCursor::notifyLayout( int width, int height, int xOffSet, int yOffSet )
{
if( width > 0 && height > 0 )
{
CtrlGeneric::notifyLayout( width, height, xOffSet, yOffSet );
}
else
{
onPositionChange();
const Position *pPos = getPosition();
CtrlGeneric::notifyLayout( m_currentCursorRect.width,
m_currentCursorRect.height,
m_currentCursorRect.x - pPos->getLeft(),
m_currentCursorRect.y - pPos->getTop() );
}
}
......@@ -169,7 +210,7 @@ void CtrlSliderCursor::onUpdate( Subject<VarPercent> &rVariable,
void *arg )
{
// The position has changed
refreshLayout();
refreshLayout( false );
}
......@@ -280,20 +321,42 @@ void CtrlSliderCursor::getResizeFactors( float &rFactorX,
}
void CtrlSliderCursor::refreshLayout()
void CtrlSliderCursor::refreshLayout( bool force )
{
if( !m_pImg )
notifyLayout();
else
// Compute the position of the cursor
int xPos, yPos;
m_rCurve.getPoint( m_rVariable.get(), xPos, yPos );
// Compute the resize factors
float factorX, factorY;
getResizeFactors( factorX, factorY );
xPos = (int)(xPos * factorX);
yPos = (int)(yPos * factorY);
const Position *pPos = getPosition();
int x = pPos->getLeft() + xPos - m_pImg->getWidth() / 2;
int y = pPos->getTop() + yPos - m_pImg->getHeight() / 2;
rect region( x, y, m_pImg->getWidth(), m_pImg->getHeight() );
if( !force &&
region.x == m_currentCursorRect.x &&
region.y == m_currentCursorRect.y &&
region.width == m_currentCursorRect.width &&
region.height == m_currentCursorRect.height )
{
// Compute the resize factors
float factorX, factorY;
getResizeFactors( factorX, factorY );
return;
}
notifyLayout( (int)(m_rCurve.getWidth() * factorX) + m_pImg->getWidth(),
(int)(m_rCurve.getHeight() * factorY) + m_pImg->getHeight(),
- m_pImg->getWidth() / 2,
- m_pImg->getHeight() / 2 );
rect join;
if( rect::join( m_currentCursorRect, region, &join ) )
{
m_currentCursorRect = region;
notifyLayout( join.width, join.height,
join.x - pPos->getLeft(),
join.y - pPos->getTop() );
}
}
......@@ -308,9 +371,9 @@ CtrlSliderBg::CtrlSliderBg( intf_thread_t *pIntf,
m_width( rCurve.getWidth() ), m_height( rCurve.getHeight() ),
m_pImgSeq( pBackground ), m_nbHoriz( nbHoriz ), m_nbVert( nbVert ),
m_padHoriz( padHoriz ), m_padVert( padVert ), m_bgWidth( 0 ),
m_bgHeight( 0 ), m_position( 0 )
m_bgHeight( 0 ), m_position( 0 ), m_pScaledBmp( NULL )
{
if( pBackground )
if( m_pImgSeq )
{
// Build the background image sequence
// Note: we suppose that the last padding is not included in the
......@@ -332,7 +395,10 @@ CtrlSliderBg::CtrlSliderBg( intf_thread_t *pIntf,
CtrlSliderBg::~CtrlSliderBg()
{
m_rVariable.delObserver( this );
if( m_pImgSeq )
m_rVariable.delObserver( this );
delete m_pScaledBmp;
}
......@@ -347,7 +413,7 @@ bool CtrlSliderBg::mouseOver( int x, int y ) const
}
void CtrlSliderBg::draw( OSGraphics &rImage, int xDest, int yDest )
void CtrlSliderBg::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h )
{
if( !m_pImgSeq || m_bgWidth <=0 || m_bgHeight <= 0 )
return;
......@@ -356,18 +422,35 @@ void CtrlSliderBg::draw( OSGraphics &rImage, int xDest, int yDest )
float factorX, factorY;
getResizeFactors( factorX, factorY );
// Rescale the image with the actual size of the control
ScaledBitmap bmp( getIntf(), *m_pImgSeq,
m_bgWidth * m_nbHoriz - (int)(m_padHoriz * factorX),
m_bgHeight * m_nbVert - (int)(m_padVert * factorY) );
int width = m_bgWidth * m_nbHoriz - (int)(m_padHoriz * factorX);
int height = m_bgHeight * m_nbVert - (int)(m_padVert * factorY);
// Rescale the image with the actual size of the control if needed
if( !m_pScaledBmp ||
m_pScaledBmp->getWidth() != width ||
m_pScaledBmp->getHeight() != height )
{
delete m_pScaledBmp;
m_pScaledBmp = new ScaledBitmap( getIntf(), *m_pImgSeq, width, height );
}
// Locate the right image in the background bitmap
int x = m_bgWidth * ( m_position % m_nbHoriz );
int y = m_bgHeight * ( m_position / m_nbHoriz );
// Draw the background image
rImage.drawBitmap( bmp, x, y, xDest, yDest,
m_bgWidth - (int)(m_padHoriz * factorX),
m_bgHeight - (int)(m_padVert * factorY) );
const Position *pPos = getPosition();
rect region( pPos->getLeft(), pPos->getTop(),
m_bgWidth - (int)(m_padHoriz * factorX),
m_bgHeight - (int)(m_padVert * factorY) );
rect clip( xDest, yDest, w, h );
rect inter;
if( rect::intersect( region, clip, &inter ) )
rImage.drawBitmap( *m_pScaledBmp,
x + inter.x - region.x,
y + inter.y - region.y,
inter.x, inter.y,
inter.width, inter.height );
}
......
......@@ -32,6 +32,7 @@
class GenericBitmap;
class ScaledBitmap;
class OSGraphics;
class VarPercent;
......@@ -58,7 +59,18 @@ public:
virtual bool mouseOver( int x, int y ) const;
/// Draw the control on the given graphics
virtual void draw( OSGraphics &rImage, int xDest, int yDest );
virtual void draw( OSGraphics &rImage, int xDest, int yDest, int w, int h );
/// Called when the position is set
virtual void onPositionChange();
/// Method called when the control is resized
virtual void onResize();
/// Method called to notify are to be updated
virtual void notifyLayout( int witdh = -1, int height = -1,
int xOffSet = 0, int yOffSet = 0 );
/// Get the text of the tooltip
virtual UString getTooltipText() const { return m_tooltip; }
......@@ -77,6 +89,7 @@ private:
int m_width, m_height;
/// Position of the cursor
int m_xPosition, m_yPosition;
rect m_currentCursorRect;
/// Callback objects
DEFINE_CALLBACK( CtrlSliderCursor, OverDown )
DEFINE_CALLBACK( CtrlSliderCursor, DownOver )
......@@ -104,7 +117,7 @@ private:
void getResizeFactors( float &rFactorX, float &rFactorY ) const;
/// Call notifyLayout
void refreshLayout();
void refreshLayout( bool force = true );
};
......@@ -123,7 +136,7 @@ public:
virtual bool mouseOver( int x, int y ) const;
/// Draw the control on the given graphics
virtual void draw( OSGraphics &rImage, int xDest, int yDest );
virtual void draw( OSGraphics &rImage, int xDest, int yDest, int w, int h );
/// Handle an event
virtual void handleEvent( EvtGeneric &rEvent );
......@@ -150,6 +163,8 @@ private:
int m_width, m_height;
/// Background image sequence (optional)
GenericBitmap *m_pImgSeq;
/// Scaled bitmap if needed
ScaledBitmap *m_pScaledBmp;
/// Number of images in the background bitmap
int m_nbHoriz, m_nbVert;
/// Number of pixels between two images
......
......@@ -150,8 +150,10 @@ bool CtrlText::mouseOver( int x, int y ) const
}
void CtrlText::draw( OSGraphics &rImage, int xDest, int yDest )
void CtrlText::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h )
{
rect clip( xDest, yDest, w, h );
const Position *pPos = getPosition();
if( m_pCurrImg )
{
// Compute the dimensions to draw
......@@ -178,12 +180,18 @@ void CtrlText::draw( OSGraphics &rImage, int xDest, int yDest )
else if( m_alignment == kCenter &&
width < getPosition()->getWidth() )
{
// The text is shorter than the width of the control, so we
// can center it
// The text is shorter than the width of the control, so we
// can center it
offset = (getPosition()->getWidth() - width) / 2;