]> git.sesse.net Git - vlc/blobdiff - modules/gui/skins2/controls/ctrl_slider.cpp
Layout for album art
[vlc] / modules / gui / skins2 / controls / ctrl_slider.cpp
index a0fcc411643b386f86a89cb2745998b5a8be4a68..b7c982926e454b61db8b8c819fa185da7bbe3946 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_slider.hpp"
@@ -27,6 +27,7 @@
 #include "../events/evt_mouse.hpp"
 #include "../events/evt_scroll.hpp"
 #include "../src/generic_bitmap.hpp"
+#include "../src/scaled_bitmap.hpp"
 #include "../src/top_window.hpp"
 #include "../src/os_factory.hpp"
 #include "../src/os_graphics.hpp"
@@ -50,10 +51,9 @@ CtrlSliderCursor::CtrlSliderCursor( intf_thread_t *pIntf,
     CtrlGeneric( pIntf, rHelp, pVisible ), m_fsm( pIntf ),
     m_rVariable( rVariable ), m_tooltip( rTooltip ),
     m_width( rCurve.getWidth() ), m_height( rCurve.getHeight() ),
-    m_cmdOverDown( pIntf, this ), m_cmdDownOver( pIntf, this ),
-    m_cmdOverUp( pIntf, this ), m_cmdUpOver( pIntf, this ),
-    m_cmdMove( pIntf, this ), m_cmdScroll( pIntf, this ),
-
+    m_cmdOverDown( this ), m_cmdDownOver( this ),
+    m_cmdOverUp( this ), m_cmdUpOver( this ),
+    m_cmdMove( this ), m_cmdScroll( this ),
     m_lastPercentage( 0 ), m_xOffset( 0 ), m_yOffset( 0 ),
     m_pEvt( NULL ), m_rCurve( rCurve )
 {
@@ -160,145 +160,102 @@ void CtrlSliderCursor::draw( OSGraphics &rImage, int xDest, int yDest )
 }
 
 
-void CtrlSliderCursor::onUpdate( Subject<VarPercent> &rVariable )
+void CtrlSliderCursor::onUpdate( Subject<VarPercent> &rVariable,
+                                 void *arg  )
 {
     // The position has changed
-    if( m_pImg )
-    {
-        notifyLayout( m_rCurve.getWidth() + m_pImg->getWidth(),
-                      m_rCurve.getHeight() + m_pImg->getHeight(),
-                      - m_pImg->getWidth() / 2,
-                      - m_pImg->getHeight() / 2 );
-    }
-    else
-        notifyLayout();
+    refreshLayout();
 }
 
 
 void CtrlSliderCursor::CmdOverDown::execute()
 {
-    EvtMouse *pEvtMouse = (EvtMouse*)m_pControl->m_pEvt;
+    EvtMouse *pEvtMouse = (EvtMouse*)m_pParent->m_pEvt;
 
     // Compute the resize factors
     float factorX, factorY;
-    m_pControl->getResizeFactors( factorX, factorY );
+    m_pParent->getResizeFactors( factorX, factorY );
 
     // Get the position of the control
-    const Position *pPos = m_pControl->getPosition();
+    const Position *pPos = m_pParent->getPosition();
 
     // Compute the offset
     int tempX, tempY;
-    m_pControl->m_rCurve.getPoint( m_pControl->m_rVariable.get(), tempX, tempY );
-    m_pControl->m_xOffset = pEvtMouse->getXPos() - pPos->getLeft()
+    m_pParent->m_rCurve.getPoint( m_pParent->m_rVariable.get(), tempX, tempY );
+    m_pParent->m_xOffset = pEvtMouse->getXPos() - pPos->getLeft()
                        - (int)(tempX * factorX);
-    m_pControl->m_yOffset = pEvtMouse->getYPos() - pPos->getTop()
+    m_pParent->m_yOffset = pEvtMouse->getYPos() - pPos->getTop()
                        - (int)(tempY * factorY);
 
-    m_pControl->captureMouse();
-    m_pControl->m_pImg = m_pControl->m_pImgDown;
-    if( m_pControl->m_pImg )
-    {
-        m_pControl->notifyLayout(
-            m_pControl->m_rCurve.getWidth() + m_pControl->m_pImg->getWidth(),
-            m_pControl->m_rCurve.getHeight() + m_pControl->m_pImg->getHeight(),
-            - m_pControl->m_pImg->getWidth() / 2,
-            - m_pControl->m_pImg->getHeight() / 2 );
-    }
-    else
-        m_pControl->notifyLayout();
+    m_pParent->captureMouse();
+    m_pParent->m_pImg = m_pParent->m_pImgDown;
+    m_pParent->refreshLayout();
 }
 
 
 void CtrlSliderCursor::CmdDownOver::execute()
 {
     // Save the position
-    m_pControl->m_lastPercentage = m_pControl->m_rVariable.get();
+    m_pParent->m_lastPercentage = m_pParent->m_rVariable.get();
 
-    m_pControl->releaseMouse();
-    m_pControl->m_pImg = m_pControl->m_pImgUp;
-    if( m_pControl->m_pImg )
-    {
-        m_pControl->notifyLayout(
-            m_pControl->m_rCurve.getWidth() + m_pControl->m_pImg->getWidth(),
-            m_pControl->m_rCurve.getHeight() + m_pControl->m_pImg->getHeight(),
-            - m_pControl->m_pImg->getWidth() / 2,
-            - m_pControl->m_pImg->getHeight() / 2 );
-    }
-    else
-        m_pControl->notifyLayout();
+    m_pParent->releaseMouse();
+    m_pParent->m_pImg = m_pParent->m_pImgUp;
+    m_pParent->refreshLayout();
 }
 
 
 void CtrlSliderCursor::CmdUpOver::execute()
 {
-    m_pControl->m_pImg = m_pControl->m_pImgOver;
-    if( m_pControl->m_pImg )
-    {
-        m_pControl->notifyLayout(
-            m_pControl->m_rCurve.getWidth() + m_pControl->m_pImg->getWidth(),
-            m_pControl->m_rCurve.getHeight() + m_pControl->m_pImg->getHeight(),
-            - m_pControl->m_pImg->getWidth() / 2,
-            - m_pControl->m_pImg->getHeight() / 2 );
-    }
-    else
-        m_pControl->notifyLayout();
+    m_pParent->m_pImg = m_pParent->m_pImgOver;
+    m_pParent->refreshLayout();
 }
 
 
 void CtrlSliderCursor::CmdOverUp::execute()
 {
-    m_pControl->m_pImg = m_pControl->m_pImgUp;
-    if( m_pControl->m_pImg )
-    {
-        m_pControl->notifyLayout(
-            m_pControl->m_rCurve.getWidth() + m_pControl->m_pImg->getWidth(),
-            m_pControl->m_rCurve.getHeight() + m_pControl->m_pImg->getHeight(),
-            - m_pControl->m_pImg->getWidth() / 2,
-            - m_pControl->m_pImg->getHeight() / 2 );
-    }
-    else
-        m_pControl->notifyLayout();
+    m_pParent->m_pImg = m_pParent->m_pImgUp;
+    m_pParent->refreshLayout();
 }
 
 
 void CtrlSliderCursor::CmdMove::execute()
 {
-    EvtMouse *pEvtMouse = (EvtMouse*)m_pControl->m_pEvt;
+    EvtMouse *pEvtMouse = (EvtMouse*)m_pParent->m_pEvt;
 
     // Get the position of the control
-    const Position *pPos = m_pControl->getPosition();
+    const Position *pPos = m_pParent->getPosition();
 
     // Compute the resize factors
     float factorX, factorY;
-    m_pControl->getResizeFactors( factorX, factorY );
+    m_pParent->getResizeFactors( factorX, factorY );
 
     // Compute the relative position of the centre of the cursor
-    float relX = pEvtMouse->getXPos() - pPos->getLeft() - m_pControl->m_xOffset;
-    float relY = pEvtMouse->getYPos() - pPos->getTop() - m_pControl->m_yOffset;
+    float relX = pEvtMouse->getXPos() - pPos->getLeft() - m_pParent->m_xOffset;
+    float relY = pEvtMouse->getYPos() - pPos->getTop() - m_pParent->m_yOffset;
     // Ponderate with the resize factors
     int relXPond = (int)(relX / factorX);
     int relYPond = (int)(relY / factorY);
 
     // Update the position
-    if( m_pControl->m_rCurve.getMinDist( relXPond, relYPond ) < RANGE )
+    if( m_pParent->m_rCurve.getMinDist( relXPond, relYPond ) < RANGE )
     {
-        float percentage = m_pControl->m_rCurve.getNearestPercent( relXPond,
+        float percentage = m_pParent->m_rCurve.getNearestPercent( relXPond,
                                                               relYPond );
-        m_pControl->m_rVariable.set( percentage );
+        m_pParent->m_rVariable.set( percentage );
     }
     else
     {
-        m_pControl->m_rVariable.set( m_pControl->m_lastPercentage );
+        m_pParent->m_rVariable.set( m_pParent->m_lastPercentage );
     }
 }
 
 void CtrlSliderCursor::CmdScroll::execute()
 {
-    EvtScroll *pEvtScroll = (EvtScroll*)m_pControl->m_pEvt;
+    EvtScroll *pEvtScroll = (EvtScroll*)m_pParent->m_pEvt;
 
     int direction = pEvtScroll->getDirection();
 
-    float percentage = m_pControl->m_rVariable.get();
+    float percentage = m_pParent->m_rVariable.get();
     if( direction == EvtScroll::kUp )
     {
         percentage += SCROLL_STEP;
@@ -308,7 +265,7 @@ void CtrlSliderCursor::CmdScroll::execute()
         percentage -= SCROLL_STEP;
     }
 
-    m_pControl->m_rVariable.set( percentage );
+    m_pParent->m_rVariable.set( percentage );
 }
 
 
@@ -333,15 +290,59 @@ void CtrlSliderCursor::getResizeFactors( float &rFactorX,
 }
 
 
+void CtrlSliderCursor::refreshLayout()
+{
+    if( m_pImg )
+    {
+        // Compute the resize factors
+        float factorX, factorY;
+        getResizeFactors( factorX, factorY );
 
-CtrlSliderBg::CtrlSliderBg( intf_thread_t *pIntf, CtrlSliderCursor &rCursor,
+        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 );
+    }
+    else
+        notifyLayout();
+}
+
+
+CtrlSliderBg::CtrlSliderBg( intf_thread_t *pIntf,
                             const Bezier &rCurve, VarPercent &rVariable,
-                            int thickness, VarBool *pVisible,
-                            const UString &rHelp ):
-    CtrlGeneric( pIntf, rHelp, pVisible ), m_rCursor( rCursor ),
+                            int thickness, GenericBitmap *pBackground,
+                            int nbHoriz, int nbVert, int padHoriz, int padVert,
+                            VarBool *pVisible, const UString &rHelp ):
+    CtrlGeneric( pIntf, rHelp, pVisible ), m_pCursor( NULL ),
     m_rVariable( rVariable ), m_thickness( thickness ), m_rCurve( rCurve ),
-    m_width( rCurve.getWidth() ), m_height( rCurve.getHeight() )
+    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 )
 {
+    if( pBackground )
+    {
+        // Build the background image sequence
+        // Note: we suppose that the last padding is not included in the
+        // given image
+        // TODO: we should probably change this assumption, as it would make
+        // the code a bit simpler and it would be more natural for the skins
+        // designers
+        m_bgWidth = (pBackground->getWidth() + m_padHoriz) / nbHoriz;
+        m_bgHeight = (pBackground->getHeight() + m_padVert) / nbVert;
+
+        // Observe the position variable
+        m_rVariable.addObserver( this );
+
+        // Initial position
+        m_position = (int)( m_rVariable.get() * (m_nbHoriz * m_nbVert - 1) );
+    }
+}
+
+
+CtrlSliderBg::~CtrlSliderBg()
+{
+    m_rVariable.delObserver( this );
 }
 
 
@@ -351,8 +352,35 @@ bool CtrlSliderBg::mouseOver( int x, int y ) const
     float factorX, factorY;
     getResizeFactors( factorX, factorY );
 
-    return (m_rCurve.getMinDist( (int)(x / factorX),
-                                 (int)(y / factorY) ) < m_thickness );
+    return (m_rCurve.getMinDist( (int)(x / factorX), (int)(y / factorY),
+                                 factorX, factorY ) < m_thickness );
+}
+
+
+void CtrlSliderBg::draw( OSGraphics &rImage, int xDest, int yDest )
+{
+    if( m_pImgSeq )
+    {
+        if( m_bgWidth > 0 && m_bgHeight > 0 )
+        {
+            // Compute the resize factors
+            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) );
+
+            // 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) );
+        }
+    }
 }
 
 
@@ -378,12 +406,12 @@ void CtrlSliderBg::handleEvent( EvtGeneric &rEvent )
         // Forward the clic to the cursor
         EvtMouse evt( getIntf(), x, y, EvtMouse::kLeft, EvtMouse::kDown );
         TopWindow *pWin = getWindow();
-        if( pWin )
+        if( pWin && m_pCursor )
         {
             EvtEnter evtEnter( getIntf() );
             // XXX It was not supposed to be implemented like that !!
-            pWin->forwardEvent( evtEnter, m_rCursor );
-            pWin->forwardEvent( evt, m_rCursor );
+            pWin->forwardEvent( evtEnter, *m_pCursor );
+            pWin->forwardEvent( evt, *m_pCursor );
         }
     }
     else if( rEvent.getAsString().find( "scroll" ) != string::npos )
@@ -405,6 +433,37 @@ void CtrlSliderBg::handleEvent( EvtGeneric &rEvent )
 }
 
 
+void CtrlSliderBg::onResize()
+{
+    if( m_pImgSeq )
+    {
+        // Compute only the new size of an elementary image.
+        // The actual resizing is done in the draw() method for now...
+
+        // Compute the resize factors
+        float factorX, factorY;
+        getResizeFactors( factorX, factorY );
+
+        // Size of one elementary background image (padding included)
+        m_bgWidth = (int)((m_pImgSeq->getWidth() + m_padHoriz) * factorX / m_nbHoriz);
+        m_bgHeight = (int)((m_pImgSeq->getHeight() + m_padVert) * factorY / m_nbVert);
+    }
+}
+
+
+void CtrlSliderBg::associateCursor( CtrlSliderCursor &rCursor )
+{
+    m_pCursor = &rCursor;
+}
+
+
+void CtrlSliderBg::onUpdate( Subject<VarPercent> &rVariable, void*arg )
+{
+    m_position = (int)( m_rVariable.get() * (m_nbHoriz * m_nbVert - 1) );
+    notifyLayout( m_bgWidth, m_bgHeight );
+}
+
+
 void CtrlSliderBg::getResizeFactors( float &rFactorX, float &rFactorY ) const
 {
     // Get the position of the control