From a1921136e0dcdc037994d34a0c12be7401f59d00 Mon Sep 17 00:00:00 2001 From: Erwan Tulou Date: Fri, 30 Jul 2010 00:13:02 +0200 Subject: [PATCH] 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. --- modules/gui/skins2/controls/ctrl_button.cpp | 18 +- modules/gui/skins2/controls/ctrl_button.hpp | 2 +- modules/gui/skins2/controls/ctrl_checkbox.cpp | 21 ++- modules/gui/skins2/controls/ctrl_checkbox.hpp | 2 +- modules/gui/skins2/controls/ctrl_generic.cpp | 5 +- modules/gui/skins2/controls/ctrl_generic.hpp | 4 +- modules/gui/skins2/controls/ctrl_image.cpp | 45 ++++- modules/gui/skins2/controls/ctrl_image.hpp | 2 +- modules/gui/skins2/controls/ctrl_list.cpp | 14 +- modules/gui/skins2/controls/ctrl_list.hpp | 2 +- modules/gui/skins2/controls/ctrl_move.cpp | 4 +- modules/gui/skins2/controls/ctrl_move.hpp | 2 +- .../gui/skins2/controls/ctrl_radialslider.cpp | 25 ++- .../gui/skins2/controls/ctrl_radialslider.hpp | 2 +- modules/gui/skins2/controls/ctrl_resize.cpp | 4 +- modules/gui/skins2/controls/ctrl_resize.hpp | 2 +- modules/gui/skins2/controls/ctrl_slider.cpp | 155 ++++++++++++++---- modules/gui/skins2/controls/ctrl_slider.hpp | 21 ++- modules/gui/skins2/controls/ctrl_text.cpp | 18 +- modules/gui/skins2/controls/ctrl_text.hpp | 2 +- modules/gui/skins2/controls/ctrl_tree.cpp | 15 +- modules/gui/skins2/controls/ctrl_tree.hpp | 2 +- modules/gui/skins2/controls/ctrl_video.cpp | 19 ++- modules/gui/skins2/controls/ctrl_video.hpp | 2 +- modules/gui/skins2/src/anim_bitmap.cpp | 9 +- modules/gui/skins2/src/anim_bitmap.hpp | 2 +- modules/gui/skins2/src/generic_layout.cpp | 37 ++--- modules/gui/skins2/utils/pointer.hpp | 106 ++++++++++++ 28 files changed, 420 insertions(+), 122 deletions(-) diff --git a/modules/gui/skins2/controls/ctrl_button.cpp b/modules/gui/skins2/controls/ctrl_button.cpp index a1eb12559a..1c19bc3bda 100644 --- a/modules/gui/skins2/controls/ctrl_button.cpp +++ b/modules/gui/skins2/controls/ctrl_button.cpp @@ -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 &rBitmap, void *arg ) { - notifyLayout(); + notifyLayout( m_pImg->getWidth(), m_pImg->getHeight() ); } diff --git a/modules/gui/skins2/controls/ctrl_button.hpp b/modules/gui/skins2/controls/ctrl_button.hpp index 6e4581a8c9..b6a8652da7 100644 --- a/modules/gui/skins2/controls/ctrl_button.hpp +++ b/modules/gui/skins2/controls/ctrl_button.hpp @@ -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; } diff --git a/modules/gui/skins2/controls/ctrl_checkbox.cpp b/modules/gui/skins2/controls/ctrl_checkbox.cpp index 0f0116faf3..82991a8311 100644 --- a/modules/gui/skins2/controls/ctrl_checkbox.cpp +++ b/modules/gui/skins2/controls/ctrl_checkbox.cpp @@ -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 &rBitmap, void *arg ) { - notifyLayout(); + notifyLayout( m_pImgCurrent->getWidth(), m_pImgCurrent->getHeight() ); } diff --git a/modules/gui/skins2/controls/ctrl_checkbox.hpp b/modules/gui/skins2/controls/ctrl_checkbox.hpp index 7342bf0ae0..78fff7c41e 100644 --- a/modules/gui/skins2/controls/ctrl_checkbox.hpp +++ b/modules/gui/skins2/controls/ctrl_checkbox.hpp @@ -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; } diff --git a/modules/gui/skins2/controls/ctrl_generic.cpp b/modules/gui/skins2/controls/ctrl_generic.cpp index 81465feebf..1e9f7a3a5b 100644 --- a/modules/gui/skins2/controls/ctrl_generic.cpp +++ b/modules/gui/skins2/controls/ctrl_generic.cpp @@ -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 ) { diff --git a/modules/gui/skins2/controls/ctrl_generic.hpp b/modules/gui/skins2/controls/ctrl_generic.hpp index d1decf734f..cc33f4620a 100644 --- a/modules/gui/skins2/controls/ctrl_generic.hpp +++ b/modules/gui/skins2/controls/ctrl_generic.hpp @@ -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. diff --git a/modules/gui/skins2/controls/ctrl_image.cpp b/modules/gui/skins2/controls/ctrl_image.cpp index c9c35ca688..9709de7e9f 100644 --- a/modules/gui/skins2/controls/ctrl_image.cpp +++ b/modules/gui/skins2/controls/ctrl_image.cpp @@ -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 ); + } } } diff --git a/modules/gui/skins2/controls/ctrl_image.hpp b/modules/gui/skins2/controls/ctrl_image.hpp index 470ab9f73a..f1d18f17ae 100644 --- a/modules/gui/skins2/controls/ctrl_image.hpp +++ b/modules/gui/skins2/controls/ctrl_image.hpp @@ -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"; } diff --git a/modules/gui/skins2/controls/ctrl_list.cpp b/modules/gui/skins2/controls/ctrl_list.cpp index 4bf7d1e757..4c01bec711 100644 --- a/modules/gui/skins2/controls/ctrl_list.cpp +++ b/modules/gui/skins2/controls/ctrl_list.cpp @@ -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 ); } } diff --git a/modules/gui/skins2/controls/ctrl_list.hpp b/modules/gui/skins2/controls/ctrl_list.hpp index 5fd6f7a8db..fcfb33e3f3 100644 --- a/modules/gui/skins2/controls/ctrl_list.hpp +++ b/modules/gui/skins2/controls/ctrl_list.hpp @@ -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(); diff --git a/modules/gui/skins2/controls/ctrl_move.cpp b/modules/gui/skins2/controls/ctrl_move.cpp index f4cf8880fd..39700c839b 100644 --- a/modules/gui/skins2/controls/ctrl_move.cpp +++ b/modules/gui/skins2/controls/ctrl_move.cpp @@ -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 ); } diff --git a/modules/gui/skins2/controls/ctrl_move.hpp b/modules/gui/skins2/controls/ctrl_move.hpp index 67e813fe2b..13fbcfaf7c 100644 --- a/modules/gui/skins2/controls/ctrl_move.hpp +++ b/modules/gui/skins2/controls/ctrl_move.hpp @@ -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, diff --git a/modules/gui/skins2/controls/ctrl_radialslider.cpp b/modules/gui/skins2/controls/ctrl_radialslider.cpp index a1bbec3c00..3ca78acccd 100644 --- a/modules/gui/skins2/controls/ctrl_radialslider.cpp +++ b/modules/gui/skins2/controls/ctrl_radialslider.cpp @@ -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 &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 ); + } } diff --git a/modules/gui/skins2/controls/ctrl_radialslider.hpp b/modules/gui/skins2/controls/ctrl_radialslider.hpp index a528c2cab5..e17852b0a2 100644 --- a/modules/gui/skins2/controls/ctrl_radialslider.hpp +++ b/modules/gui/skins2/controls/ctrl_radialslider.hpp @@ -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"; } diff --git a/modules/gui/skins2/controls/ctrl_resize.cpp b/modules/gui/skins2/controls/ctrl_resize.cpp index 1fb37b72bf..7992d4b0fe 100644 --- a/modules/gui/skins2/controls/ctrl_resize.cpp +++ b/modules/gui/skins2/controls/ctrl_resize.cpp @@ -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 ); } diff --git a/modules/gui/skins2/controls/ctrl_resize.hpp b/modules/gui/skins2/controls/ctrl_resize.hpp index 7d2d718b18..8f2912cfb9 100644 --- a/modules/gui/skins2/controls/ctrl_resize.hpp +++ b/modules/gui/skins2/controls/ctrl_resize.hpp @@ -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, diff --git a/modules/gui/skins2/controls/ctrl_slider.cpp b/modules/gui/skins2/controls/ctrl_slider.cpp index 5159caebde..8eca2b0375 100644 --- a/modules/gui/skins2/controls/ctrl_slider.cpp +++ b/modules/gui/skins2/controls/ctrl_slider.cpp @@ -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 &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 ); } diff --git a/modules/gui/skins2/controls/ctrl_slider.hpp b/modules/gui/skins2/controls/ctrl_slider.hpp index ac31b9944f..df010a5e69 100644 --- a/modules/gui/skins2/controls/ctrl_slider.hpp +++ b/modules/gui/skins2/controls/ctrl_slider.hpp @@ -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 diff --git a/modules/gui/skins2/controls/ctrl_text.cpp b/modules/gui/skins2/controls/ctrl_text.cpp index 867c661236..513028fe7c 100644 --- a/modules/gui/skins2/controls/ctrl_text.cpp +++ b/modules/gui/skins2/controls/ctrl_text.cpp @@ -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; } - rImage.drawBitmap( *m_pCurrImg, -m_xPos, 0, xDest + offset, - yDest, width, height, true ); + rect region( pPos->getLeft() + offset, + pPos->getTop(), width, height ); + rect inter; + if( rect::intersect( region, clip, &inter ) ) + rImage.drawBitmap( *m_pCurrImg, -m_xPos + inter.x - region.x, + inter.y - region.y, + inter.x, inter.y, + inter.width, inter.height, true ); } } } diff --git a/modules/gui/skins2/controls/ctrl_text.hpp b/modules/gui/skins2/controls/ctrl_text.hpp index eafdb8e1b9..c0a35bb619 100644 --- a/modules/gui/skins2/controls/ctrl_text.hpp +++ b/modules/gui/skins2/controls/ctrl_text.hpp @@ -74,7 +74,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 text of the control, with an optional color /// This takes effect immediatly diff --git a/modules/gui/skins2/controls/ctrl_tree.cpp b/modules/gui/skins2/controls/ctrl_tree.cpp index 27ffdd29d6..b816d02b3f 100644 --- a/modules/gui/skins2/controls/ctrl_tree.cpp +++ b/modules/gui/skins2/controls/ctrl_tree.cpp @@ -636,10 +636,19 @@ bool CtrlTree::mouseOver( int x, int y ) const x >= 0 && x <= pPos->getWidth() && y >= 0 && y <= pPos->getHeight(); } -void CtrlTree::draw( OSGraphics &rImage, int xDest, int yDest ) +void CtrlTree::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h) { - if( m_pImage ) - rImage.drawGraphics( *m_pImage, 0, 0, xDest, yDest ); + 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, + inter.x - pPos->getLeft(), + inter.y - pPos->getTop(), + inter.x, inter.y, inter.width, inter.height ); } bool CtrlTree::ensureVisible( VarTree::Iterator item ) diff --git a/modules/gui/skins2/controls/ctrl_tree.hpp b/modules/gui/skins2/controls/ctrl_tree.hpp index 76e43a2a82..44ff222ffe 100644 --- a/modules/gui/skins2/controls/ctrl_tree.hpp +++ b/modules/gui/skins2/controls/ctrl_tree.hpp @@ -62,7 +62,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(); diff --git a/modules/gui/skins2/controls/ctrl_video.cpp b/modules/gui/skins2/controls/ctrl_video.cpp index 823cac4689..5008d6de3a 100644 --- a/modules/gui/skins2/controls/ctrl_video.cpp +++ b/modules/gui/skins2/controls/ctrl_video.cpp @@ -85,14 +85,25 @@ void CtrlVideo::onPositionChange() } -void CtrlVideo::draw( OSGraphics &rImage, int xDest, int yDest ) +void CtrlVideo::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h) { const Position *pPos = getPosition(); - if( pPos ) + rect region( pPos->getLeft(), pPos->getTop(), + pPos->getWidth(), pPos->getHeight() ); + rect clip( xDest, yDest, w, h ); + rect inter; + + if( rect::intersect( region, clip, &inter ) ) { // Draw a black rectangle under the video to avoid transparency - rImage.fillRect( pPos->getLeft(), pPos->getTop(), pPos->getWidth(), - pPos->getHeight(), 0 ); + rImage.fillRect( inter.x, inter.y, inter.width, inter.height, 0 ); + } + + if( m_pVoutWindow ) + { + m_pVoutWindow->move( pPos->getLeft(), pPos->getTop() ); + m_pVoutWindow->resize( pPos->getWidth(), pPos->getHeight() ); + m_pVoutWindow->show(); } } diff --git a/modules/gui/skins2/controls/ctrl_video.hpp b/modules/gui/skins2/controls/ctrl_video.hpp index 2f9a19bb0b..1b5d37d4ec 100644 --- a/modules/gui/skins2/controls/ctrl_video.hpp +++ b/modules/gui/skins2/controls/ctrl_video.hpp @@ -51,7 +51,7 @@ public: virtual void onPositionChange(); /// 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 "video"; } diff --git a/modules/gui/skins2/src/anim_bitmap.cpp b/modules/gui/skins2/src/anim_bitmap.cpp index f09da66db8..32880183ed 100644 --- a/modules/gui/skins2/src/anim_bitmap.cpp +++ b/modules/gui/skins2/src/anim_bitmap.cpp @@ -69,7 +69,8 @@ void AnimBitmap::stopAnim() } -void AnimBitmap::draw( OSGraphics &rImage, int xDest, int yDest ) +void AnimBitmap::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h, + int xOffset, int yOffset ) { // Draw the current frame int height = m_pImage->getHeight() / m_nbFrames; @@ -79,9 +80,9 @@ void AnimBitmap::draw( OSGraphics &rImage, int xDest, int yDest ) // rImage.drawGraphics( *m_pImage, 0, ySrc, xDest, yDest, // m_pImage->getWidth(), height ); - // A new way .... needs to be tested thoroughly - rImage.drawBitmap( m_rBitmap, 0, ySrc, xDest, yDest, - m_pImage->getWidth(), height, true ); + rImage.drawBitmap( m_rBitmap, + xOffset, ySrc + yOffset, + xDest, yDest, w, h, true ); } diff --git a/modules/gui/skins2/src/anim_bitmap.hpp b/modules/gui/skins2/src/anim_bitmap.hpp index 6667ce118c..bc005a784f 100644 --- a/modules/gui/skins2/src/anim_bitmap.hpp +++ b/modules/gui/skins2/src/anim_bitmap.hpp @@ -49,7 +49,7 @@ public: void stopAnim(); /// Draw the current frame on another graphics - void draw( OSGraphics &rImage, int xDest, int yDest ); + void draw( OSGraphics &rImage, int xDest, int yDest, int w, int h, int xOffset = 0, int yOffset = 0 ); /// Tell whether the pixel at the given position is visible bool hit( int x, int y ) const; diff --git a/modules/gui/skins2/src/generic_layout.cpp b/modules/gui/skins2/src/generic_layout.cpp index 731d8dd75c..cd7f6e2c28 100644 --- a/modules/gui/skins2/src/generic_layout.cpp +++ b/modules/gui/skins2/src/generic_layout.cpp @@ -109,10 +109,6 @@ void GenericLayout::addControl( CtrlGeneric *pControl, // Associate this layout to the control pControl->setLayout( this, rPosition ); - // Draw the control - if( pControl->isVisible() ) - pControl->draw( *m_pImage, rPosition.getLeft(), rPosition.getTop() ); - // Add the control in the list. // This list must remain sorted by layer order list::iterator it; @@ -153,19 +149,23 @@ void GenericLayout::onControlUpdate( const CtrlGeneric &rCtrl, int width, int height, int xOffSet, int yOffSet ) { - // The size is not valid, refresh the whole layout - if( width <= 0 || height <= 0 ) - { - refreshAll(); + // Do nothing if the layout or control is hidden + if( !m_visible ) return; - } const Position *pPos = rCtrl.getPosition(); - if( pPos ) + if( width > 0 && height > 0 ) { - refreshRect( pPos->getLeft() + xOffSet, + // make sure region is within the layout + rect region( pPos->getLeft() + xOffSet, pPos->getTop() + yOffSet, width, height ); + rect layout( 0, 0, m_rect.getWidth(), m_rect.getHeight() ); + rect inter; + if( rect::intersect( layout, region, &inter ) ) + { + refreshRect( inter.x, inter.y, inter.width, inter.height ); + } } } @@ -223,10 +223,9 @@ void GenericLayout::refreshRect( int x, int y, int width, int height ) for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ ) { CtrlGeneric *pCtrl = (*iter).m_pControl; - const Position *pPos = pCtrl->getPosition(); - if( pPos && pCtrl->isVisible() ) + if( pCtrl->isVisible() ) { - pCtrl->draw( *m_pImage, pPos->getLeft(), pPos->getTop() ); + pCtrl->draw( *m_pImage, x, y, width, height ); } } @@ -237,16 +236,6 @@ void GenericLayout::refreshRect( int x, int y, int width, int height ) // first apply new shape to the window pWindow->updateShape(); - // Check boundaries - if( x < 0 ) - x = 0; - if( y < 0) - y = 0; - if( x + width > m_rect.getWidth() ) - width = m_rect.getWidth() - x; - if( y + height > m_rect.getHeight() ) - height = m_rect.getHeight() - y; - pWindow->refresh( x, y, width, height ); } } diff --git a/modules/gui/skins2/utils/pointer.hpp b/modules/gui/skins2/utils/pointer.hpp index 4d2aa29c25..2a7e815210 100644 --- a/modules/gui/skins2/utils/pointer.hpp +++ b/modules/gui/skins2/utils/pointer.hpp @@ -93,4 +93,110 @@ private: }; +class rect +{ +public: + rect( int v_x = 0, int v_y = 0, int v_width = 0, int v_height = 0 ) + : x( v_x ), y( v_y ), width( v_width ), height( v_height ) { } + ~rect() { } + int x; + int y; + int width; + int height; + + // rect2 fully included in rect1 + static bool isIncluded( rect& rect2, rect& rect1 ) + { + int x1 = rect1.x; + int y1 = rect1.y; + int w1 = rect1.width; + int h1 = rect1.height; + + int x2 = rect2.x; + int y2 = rect2.y; + int w2 = rect2.width; + int h2 = rect2.height; + + return x2 >= x1 && x2 < x1 + w1 + && y2 >= y1 && y2 < y1 + h1 + && w2 <= w1 + && h2 <= h1; + } + + static bool areDisjunct( rect& rect2, rect& rect1 ) + { + int x1 = rect1.x; + int y1 = rect1.y; + int w1 = rect1.width; + int h1 = rect1.height; + + int x2 = rect2.x; + int y2 = rect2.y; + int w2 = rect2.width; + int h2 = rect2.height; + + return y2 + h2 -1 < y1 // rect2 above rect1 + || y2 > y1 + h1 - 1 // rect2 under rect1 + || x2 > x1 + w1 -1 // rect2 right of rect1 + || x2 + w2 - 1 < x1; // rect2 left of rect1 + } + + static bool intersect( rect& rect1, rect& rect2, rect* pRect ) + { + int x1 = rect1.x; + int y1 = rect1.y; + int w1 = rect1.width; + int h1 = rect1.height; + + int x2 = rect2.x; + int y2 = rect2.y; + int w2 = rect2.width; + int h2 = rect2.height; + + if( areDisjunct( rect1, rect2 ) ) + return false; + else + { + int left = max( x1, x2 ); + int right = min( x1 + w1 - 1, x2 + w2 - 1 ); + int top = max( y1, y2 ); + int bottom = min( y1 + h1 - 1, y2 + h2 -1 ); + pRect->x = left; + pRect->y = top; + pRect->width = right - left + 1; + pRect->height = bottom - top + 1; + + return pRect->width > 0 && pRect->height > 0; + } + } + + static bool join( rect& rect1, rect& rect2, rect* pRect ) + { + int x1 = rect1.x; + int y1 = rect1.y; + int w1 = rect1.width; + int h1 = rect1.height; + + int x2 = rect2.x; + int y2 = rect2.y; + int w2 = rect2.width; + int h2 = rect2.height; + + int left = min( x1, x2 ); + int right = max( x1 + w1 - 1, x2 + w2 - 1 ); + int top = min( y1, y2 ); + int bottom = max( y1 + h1 - 1, y2 + h2 -1 ); + pRect->x = left; + pRect->y = top; + pRect->width = right - left + 1; + pRect->height = bottom - top + 1; + + return pRect->width > 0 && pRect->height > 0; + } + static int min( int x, int y ) { return x < y ? x : y; } + static int max( int x, int y ) { return x < y ? y : x; } + +}; + + #endif -- 2.39.5