]> git.sesse.net Git - vlc/blobdiff - modules/gui/skins2/controls/ctrl_checkbox.cpp
skins2: improve refresh of layouts
[vlc] / modules / gui / skins2 / controls / ctrl_checkbox.cpp
index 57992449fd40ef6c9a19003d60cad8f551b1f5ff..82991a831162f2b6e2e9064ddbc28810d8ca317a 100644 (file)
@@ -5,7 +5,7 @@
  * $Id$
  *
  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
- *          Olivier Teulière <ipkiss@via.ecp.fr>
+ *          Olivier Teulière <ipkiss@via.ecp.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 #include "ctrl_checkbox.hpp"
@@ -47,34 +47,15 @@ CtrlCheckbox::CtrlCheckbox( intf_thread_t *pIntf,
     m_rVariable( rVariable ),
     m_rCommand1( rCommand1 ), m_rCommand2( rCommand2 ),
     m_tooltip1( rTooltip1 ), m_tooltip2( rTooltip2 ),
-    m_cmdUpOverDownOver( pIntf, this ), m_cmdDownOverUpOver( pIntf, this ),
-    m_cmdDownOverDown( pIntf, this ), m_cmdDownDownOver( pIntf, this ),
-    m_cmdUpOverUp( pIntf, this ), m_cmdUpUpOver( pIntf, this ),
-    m_cmdDownUp( pIntf, this ), m_cmdUpHidden( pIntf, this ),
-    m_cmdHiddenUp( pIntf, this )
+    m_imgUp1( pIntf, rBmpUp1 ), m_imgOver1( pIntf, rBmpOver1 ),
+    m_imgDown1( pIntf, rBmpDown1 ), m_imgUp2( pIntf, rBmpUp2 ),
+    m_imgOver2( pIntf, rBmpOver2 ), m_imgDown2( pIntf, rBmpDown2 ),
+    m_cmdUpOverDownOver( this ), m_cmdDownOverUpOver( this ),
+    m_cmdDownOverDown( this ), m_cmdDownDownOver( this ),
+    m_cmdUpOverUp( this ), m_cmdUpUpOver( this ),
+    m_cmdDownUp( this ), m_cmdUpHidden( this ),
+    m_cmdHiddenUp( this )
 {
-    // Build the images of the checkbox
-    OSFactory *pOsFactory = OSFactory::instance( pIntf );
-    m_pImgUp1 = pOsFactory->createOSGraphics( rBmpUp1.getWidth(),
-                                              rBmpUp1.getHeight() );
-    m_pImgUp1->drawBitmap( rBmpUp1, 0, 0 );
-    m_pImgDown1 = pOsFactory->createOSGraphics( rBmpDown1.getWidth(),
-                                                rBmpDown1.getHeight() );
-    m_pImgDown1->drawBitmap( rBmpDown1, 0, 0 );
-    m_pImgOver1 = pOsFactory->createOSGraphics( rBmpOver1.getWidth(),
-                                                rBmpOver1.getHeight() );
-    m_pImgOver1->drawBitmap( rBmpOver1, 0, 0 );
-
-    m_pImgUp2 = pOsFactory->createOSGraphics( rBmpUp2.getWidth(),
-                                              rBmpUp2.getHeight() );
-    m_pImgUp2->drawBitmap( rBmpUp2, 0, 0 );
-    m_pImgDown2 = pOsFactory->createOSGraphics( rBmpDown2.getWidth(),
-                                                rBmpDown2.getHeight() );
-    m_pImgDown2->drawBitmap( rBmpDown2, 0, 0 );
-    m_pImgOver2 = pOsFactory->createOSGraphics( rBmpOver2.getWidth(),
-                                                rBmpOver2.getHeight() );
-    m_pImgOver2->drawBitmap( rBmpOver2, 0, 0 );
-
     // States
     m_fsm.addState( "up" );
     m_fsm.addState( "down" );
@@ -109,19 +90,19 @@ CtrlCheckbox::CtrlCheckbox( intf_thread_t *pIntf,
     m_fsm.setState( "up" );
     if( !m_rVariable.get() )
     {
-        m_pImgUp = m_pImgUp1;
-        m_pImgOver = m_pImgOver1;
-        m_pImgDown = m_pImgDown1;
+        m_pImgUp = &m_imgUp1;
+        m_pImgOver = &m_imgOver1;
+        m_pImgDown = &m_imgDown1;
         m_pImgCurrent = m_pImgUp;
         m_pCommand = &m_rCommand1;
         m_pTooltip = &m_tooltip1;
     }
     else
     {
-        m_pImgUp = m_pImgUp2;
-        m_pImgOver = m_pImgOver2;
-        m_pImgDown = m_pImgDown2;
-        m_pImgCurrent = m_pImgDown;
+        m_pImgUp = &m_imgUp2;
+        m_pImgOver = &m_imgOver2;
+        m_pImgDown = &m_imgDown2;
+        m_pImgCurrent = m_pImgUp;
         m_pCommand = &m_rCommand2;
         m_pTooltip = &m_tooltip2;
     }
@@ -131,12 +112,6 @@ CtrlCheckbox::CtrlCheckbox( intf_thread_t *pIntf,
 CtrlCheckbox::~CtrlCheckbox()
 {
     m_rVariable.delObserver( this );
-    SKINS_DELETE( m_pImgUp1 );
-    SKINS_DELETE( m_pImgDown1 );
-    SKINS_DELETE( m_pImgOver1 );
-    SKINS_DELETE( m_pImgUp2 );
-    SKINS_DELETE( m_pImgDown2 );
-    SKINS_DELETE( m_pImgOver2 );
 }
 
 
@@ -159,90 +134,122 @@ 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
-        rImage.drawGraphics( *m_pImgCurrent, 0, 0, xDest, yDest );
+        m_pImgCurrent->draw( rImage,
+                      inter.x, inter.y, inter.width, inter.height,
+                      inter.x - pPos->getLeft(),
+                      inter.y - pPos->getTop() );
+    }
+}
+
+
+void CtrlCheckbox::setImage( AnimBitmap *pImg )
+{
+    AnimBitmap *pOldImg = m_pImgCurrent;
+    m_pImgCurrent = pImg;
+
+    if( pOldImg )
+    {
+        pOldImg->stopAnim();
+        pOldImg->delObserver( this );
     }
+
+    if( pImg )
+    {
+        pImg->startAnim();
+        pImg->addObserver( this );
+    }
+
+    notifyLayoutMaxSize( pOldImg, pImg );
 }
 
 
 void CtrlCheckbox::CmdUpOverDownOver::execute()
 {
-    m_pControl->captureMouse();
-    const OSGraphics *pOldImg = m_pControl->m_pImgCurrent;
-    m_pControl->m_pImgCurrent = m_pControl->m_pImgDown;
-    m_pControl->notifyLayoutMaxSize( pOldImg, m_pControl->m_pImgCurrent );
+    m_pParent->captureMouse();
+    m_pParent->setImage( m_pParent->m_pImgDown );
 }
 
 
 void CtrlCheckbox::CmdDownOverUpOver::execute()
 {
-    m_pControl->releaseMouse();
+    m_pParent->releaseMouse();
+
+    // There is a little trick here: since we update the image of the control
+    // before executing the command, there is no way that the observed variable
+    // can have changed, so changeButton() has not been called, and m_pImgUp is
+    // still the "old" up state. That's why we don't use it, and use the other
+    // one instead. Otherwise, we would notice a "phantom effect", where the
+    // old up image is displayed for a few milliseconds, until the variable is
+    // updated and the correct up image is displayed.
+    // Executing the action before refreshing the state wouldn't work, because
+    // the variable may be updated asynchronously (when triggered by a callback
+    // from an object variable).
 
     // Invert the state variable
-    const OSGraphics *pOldImg = m_pControl->m_pImgCurrent;
-    m_pControl->m_pImgCurrent = m_pControl->m_pImgUp;
-    m_pControl->notifyLayoutMaxSize( pOldImg, m_pControl->m_pImgCurrent );
+    if( m_pParent->m_pImgUp == &m_pParent->m_imgUp1 )
+        m_pParent->setImage( &m_pParent->m_imgUp2 );
+    else
+        m_pParent->setImage( &m_pParent->m_imgUp1 );
 
     // Execute the command
-    m_pControl->m_pCommand->execute();
+    m_pParent->m_pCommand->execute();
 }
 
 
 void CtrlCheckbox::CmdDownOverDown::execute()
 {
-    const OSGraphics *pOldImg = m_pControl->m_pImgCurrent;
-    m_pControl->m_pImgCurrent = m_pControl->m_pImgUp;
-    m_pControl->notifyLayoutMaxSize( pOldImg, m_pControl->m_pImgCurrent );
+    m_pParent->setImage( m_pParent->m_pImgUp );
 }
 
 
 void CtrlCheckbox::CmdDownDownOver::execute()
 {
-    const OSGraphics *pOldImg = m_pControl->m_pImgCurrent;
-    m_pControl->m_pImgCurrent = m_pControl->m_pImgDown;
-    m_pControl->notifyLayoutMaxSize( pOldImg, m_pControl->m_pImgCurrent );
+    m_pParent->setImage( m_pParent->m_pImgDown );
 }
 
 
 void CtrlCheckbox::CmdUpUpOver::execute()
 {
-    const OSGraphics *pOldImg = m_pControl->m_pImgCurrent;
-    m_pControl->m_pImgCurrent = m_pControl->m_pImgOver;
-    m_pControl->notifyLayoutMaxSize( pOldImg, m_pControl->m_pImgCurrent );
+    m_pParent->setImage( m_pParent->m_pImgOver );
 }
 
 
 void CtrlCheckbox::CmdUpOverUp::execute()
 {
-    const OSGraphics *pOldImg = m_pControl->m_pImgCurrent;
-    m_pControl->m_pImgCurrent = m_pControl->m_pImgUp;
-    m_pControl->notifyLayoutMaxSize( pOldImg, m_pControl->m_pImgCurrent );
+    m_pParent->setImage( m_pParent->m_pImgUp );
 }
 
 
 void CtrlCheckbox::CmdDownUp::execute()
 {
-    m_pControl->releaseMouse();
+    m_pParent->releaseMouse();
 }
 
 
 void CtrlCheckbox::CmdUpHidden::execute()
 {
-    const OSGraphics *pOldImg = m_pControl->m_pImgCurrent;
-    m_pControl->m_pImgCurrent = NULL;
-    m_pControl->notifyLayoutMaxSize( pOldImg, m_pControl->m_pImgCurrent );
+    m_pParent->setImage( NULL );
 }
 
 
 void CtrlCheckbox::CmdHiddenUp::execute()
 {
-    const OSGraphics *pOldImg = m_pControl->m_pImgCurrent;
-    m_pControl->m_pImgCurrent = m_pControl->m_pImgUp;
-    m_pControl->notifyLayoutMaxSize( pOldImg, m_pControl->m_pImgCurrent );
+    m_pParent->setImage( m_pParent->m_pImgUp );
 }
 
 
@@ -252,30 +259,35 @@ void CtrlCheckbox::onVarBoolUpdate( VarBool &rVariable )
 }
 
 
+void CtrlCheckbox::onUpdate( Subject<AnimBitmap> &rBitmap, void *arg )
+{
+    notifyLayout( m_pImgCurrent->getWidth(), m_pImgCurrent->getHeight() );
+}
+
+
 void CtrlCheckbox::changeButton()
 {
     // Are we using the first set of images or the second one?
-    if( m_pImgUp == m_pImgUp1 )
+    if( m_pImgUp == &m_imgUp1 )
     {
-        m_pImgUp = m_pImgUp2;
-        m_pImgOver = m_pImgOver2;
-        m_pImgDown = m_pImgDown2;
+        m_pImgUp = &m_imgUp2;
+        m_pImgOver = &m_imgOver2;
+        m_pImgDown = &m_imgDown2;
         m_pTooltip = &m_tooltip2;
         m_pCommand = &m_rCommand2;
     }
     else
     {
-        m_pImgUp = m_pImgUp1;
-        m_pImgOver = m_pImgOver1;
-        m_pImgDown = m_pImgDown1;
+        m_pImgUp = &m_imgUp1;
+        m_pImgOver = &m_imgOver1;
+        m_pImgDown = &m_imgDown1;
         m_pTooltip = &m_tooltip1;
         m_pCommand = &m_rCommand1;
     }
     // XXX: We assume that the checkbox is up
-    m_pImgCurrent = m_pImgUp;
+    setImage( m_pImgUp );
 
     // Notify the window the tooltip has changed
     notifyTooltipChange();
-    // Refresh
-    notifyLayout();
 }
+