]> git.sesse.net Git - vlc/blob - modules/gui/skins2/controls/ctrl_slider.cpp
* skins/utils/bezier.cpp: Fixed a bug in the computation of the size of a
[vlc] / modules / gui / skins2 / controls / ctrl_slider.cpp
1 /*****************************************************************************
2  * ctrl_slider.cpp
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id$
6  *
7  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
8  *          Olivier Teulière <ipkiss@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 #include "ctrl_slider.hpp"
26 #include "../events/evt_enter.hpp"
27 #include "../events/evt_mouse.hpp"
28 #include "../events/evt_scroll.hpp"
29 #include "../src/generic_bitmap.hpp"
30 #include "../src/top_window.hpp"
31 #include "../src/os_factory.hpp"
32 #include "../src/os_graphics.hpp"
33 #include "../utils/position.hpp"
34 #include "../utils/var_percent.hpp"
35
36
37 #define RANGE 40
38 #define SCROLL_STEP 0.05
39
40
41 CtrlSliderCursor::CtrlSliderCursor( intf_thread_t *pIntf,
42                                     const GenericBitmap &rBmpUp,
43                                     const GenericBitmap &rBmpOver,
44                                     const GenericBitmap &rBmpDown,
45                                     const Bezier &rCurve,
46                                     VarPercent &rVariable,
47                                     VarBool *pVisible,
48                                     const UString &rTooltip,
49                                     const UString &rHelp ):
50     CtrlGeneric( pIntf, rHelp, pVisible ), m_fsm( pIntf ),
51     m_rVariable( rVariable ), m_tooltip( rTooltip ),
52     m_width( rCurve.getWidth() ), m_height( rCurve.getHeight() ),
53     m_cmdOverDown( this, &transOverDown ),
54     m_cmdDownOver( this, &transDownOver ), m_cmdOverUp( this, &transOverUp ),
55     m_cmdUpOver( this, &transUpOver ), m_cmdMove( this, &transMove ),
56     m_cmdScroll( this, &transScroll ),
57     m_lastPercentage( 0 ), m_xOffset( 0 ), m_yOffset( 0 ),
58     m_pEvt( NULL ), m_rCurve( rCurve )
59 {
60     // Build the images of the cursor
61     OSFactory *pOsFactory = OSFactory::instance( getIntf() );
62     m_pImgUp = pOsFactory->createOSGraphics( rBmpUp.getWidth(),
63                                              rBmpUp.getHeight() );
64     m_pImgUp->drawBitmap( rBmpUp, 0, 0 );
65     m_pImgDown = pOsFactory->createOSGraphics( rBmpDown.getWidth(),
66                                                rBmpDown.getHeight() );
67     m_pImgDown->drawBitmap( rBmpDown, 0, 0 );
68     m_pImgOver = pOsFactory->createOSGraphics( rBmpOver.getWidth(),
69                                                rBmpOver.getHeight() );
70     m_pImgOver->drawBitmap( rBmpOver, 0, 0 );
71
72     // States
73     m_fsm.addState( "up" );
74     m_fsm.addState( "over" );
75     m_fsm.addState( "down" );
76
77     // Transitions
78     m_fsm.addTransition( "over", "mouse:left:down", "down",
79                          &m_cmdOverDown );
80     m_fsm.addTransition( "down", "mouse:left:up", "over",
81                          &m_cmdDownOver );
82     m_fsm.addTransition( "over", "leave", "up", &m_cmdOverUp );
83     m_fsm.addTransition( "up", "enter", "over", &m_cmdUpOver );
84     m_fsm.addTransition( "down", "motion", "down", &m_cmdMove );
85     m_fsm.addTransition( "over", "scroll", "over", &m_cmdScroll );
86
87     // Initial state
88     m_fsm.setState( "up" );
89     m_pImg = m_pImgUp;
90
91     // Observe the position variable
92     m_rVariable.addObserver( this );
93
94     // Initial position of the cursor
95     m_lastPercentage = m_rVariable.get();
96 }
97
98
99 CtrlSliderCursor::~CtrlSliderCursor()
100 {
101     m_rVariable.delObserver( this );
102     SKINS_DELETE( m_pImgUp );
103     SKINS_DELETE( m_pImgDown );
104     SKINS_DELETE( m_pImgOver );
105 }
106
107
108 void CtrlSliderCursor::handleEvent( EvtGeneric &rEvent )
109 {
110     // Save the event to use it in callbacks
111     m_pEvt = &rEvent;
112
113     m_fsm.handleTransition( rEvent.getAsString() );
114 }
115
116
117 bool CtrlSliderCursor::mouseOver( int x, int y ) const
118 {
119     if( m_pImg )
120     {
121         // Compute the position of the cursor
122         int xPos, yPos;
123         m_rCurve.getPoint( m_rVariable.get(), xPos, yPos );
124
125         // Compute the resize factors
126         float factorX, factorY;
127         getResizeFactors( factorX, factorY );
128         xPos = (int)(xPos * factorX);
129         yPos = (int)(yPos * factorY);
130
131         return m_pImg->hit( x - xPos + m_pImg->getWidth() / 2,
132                             y - yPos + m_pImg->getHeight() / 2 );
133     }
134     else
135     {
136         return false;
137     }
138 }
139
140
141 void CtrlSliderCursor::draw( OSGraphics &rImage, int xDest, int yDest )
142 {
143     if( m_pImg )
144     {
145         // Compute the position of the cursor
146         int xPos, yPos;
147         m_rCurve.getPoint( m_rVariable.get(), xPos, yPos );
148
149         // Compute the resize factors
150         float factorX, factorY;
151         getResizeFactors( factorX, factorY );
152         xPos = (int)(xPos * factorX);
153         yPos = (int)(yPos * factorY);
154
155         // Draw the current image
156         rImage.drawGraphics( *m_pImg, 0, 0,
157                              xDest + xPos - m_pImg->getWidth() / 2,
158                              yDest + yPos - m_pImg->getHeight() / 2 );
159     }
160 }
161
162
163 void CtrlSliderCursor::onUpdate( Subject<VarPercent> &rVariable )
164 {
165     // The position has changed
166     if( m_pImg )
167     {
168         notifyLayout( m_rCurve.getWidth() + m_pImg->getWidth(),
169                       m_rCurve.getHeight() + m_pImg->getHeight(),
170                       - m_pImg->getWidth() / 2,
171                       - m_pImg->getHeight() / 2 );
172     }
173     else
174         notifyLayout();
175 }
176
177
178 void CtrlSliderCursor::transOverDown( SkinObject *pCtrl )
179 {
180     CtrlSliderCursor *pThis = (CtrlSliderCursor*)pCtrl;
181     EvtMouse *pEvtMouse = (EvtMouse*)pThis->m_pEvt;
182
183     // Compute the resize factors
184     float factorX, factorY;
185     pThis->getResizeFactors( factorX, factorY );
186
187     // Get the position of the control
188     const Position *pPos = pThis->getPosition();
189
190     // Compute the offset
191     int tempX, tempY;
192     pThis->m_rCurve.getPoint( pThis->m_rVariable.get(), tempX, tempY );
193     pThis->m_xOffset = pEvtMouse->getXPos() - pPos->getLeft()
194                        - (int)(tempX * factorX);
195     pThis->m_yOffset = pEvtMouse->getYPos() - pPos->getTop()
196                        - (int)(tempY * factorY);
197
198     pThis->captureMouse();
199     pThis->m_pImg = pThis->m_pImgDown;
200     if( pThis->m_pImg )
201     {
202         pThis->notifyLayout(
203             pThis->m_rCurve.getWidth() + pThis->m_pImg->getWidth(),
204             pThis->m_rCurve.getHeight() + pThis->m_pImg->getHeight(),
205             - pThis->m_pImg->getWidth() / 2,
206             - pThis->m_pImg->getHeight() / 2 );
207     }
208     else
209         pThis->notifyLayout();
210 }
211
212
213 void CtrlSliderCursor::transDownOver( SkinObject *pCtrl )
214 {
215     CtrlSliderCursor *pThis = (CtrlSliderCursor*)pCtrl;
216
217     // Save the position
218     pThis->m_lastPercentage = pThis->m_rVariable.get();
219
220     pThis->releaseMouse();
221     pThis->m_pImg = pThis->m_pImgUp;
222     if( pThis->m_pImg )
223     {
224         pThis->notifyLayout(
225             pThis->m_rCurve.getWidth() + pThis->m_pImg->getWidth(),
226             pThis->m_rCurve.getHeight() + pThis->m_pImg->getHeight(),
227             - pThis->m_pImg->getWidth() / 2,
228             - pThis->m_pImg->getHeight() / 2 );
229     }
230     else
231         pThis->notifyLayout();
232 }
233
234
235 void CtrlSliderCursor::transUpOver( SkinObject *pCtrl )
236 {
237     CtrlSliderCursor *pThis = (CtrlSliderCursor*)pCtrl;
238
239     pThis->m_pImg = pThis->m_pImgOver;
240     if( pThis->m_pImg )
241     {
242         pThis->notifyLayout(
243             pThis->m_rCurve.getWidth() + pThis->m_pImg->getWidth(),
244             pThis->m_rCurve.getHeight() + pThis->m_pImg->getHeight(),
245             - pThis->m_pImg->getWidth() / 2,
246             - pThis->m_pImg->getHeight() / 2 );
247     }
248     else
249         pThis->notifyLayout();
250 }
251
252
253 void CtrlSliderCursor::transOverUp( SkinObject *pCtrl )
254 {
255     CtrlSliderCursor *pThis = (CtrlSliderCursor*)pCtrl;
256
257     pThis->m_pImg = pThis->m_pImgUp;
258     if( pThis->m_pImg )
259     {
260         pThis->notifyLayout(
261             pThis->m_rCurve.getWidth() + pThis->m_pImg->getWidth(),
262             pThis->m_rCurve.getHeight() + pThis->m_pImg->getHeight(),
263             - pThis->m_pImg->getWidth() / 2,
264             - pThis->m_pImg->getHeight() / 2 );
265     }
266     else
267         pThis->notifyLayout();
268 }
269
270
271 void CtrlSliderCursor::transMove( SkinObject *pCtrl )
272 {
273     CtrlSliderCursor *pThis = (CtrlSliderCursor*)pCtrl;
274     EvtMouse *pEvtMouse = (EvtMouse*)pThis->m_pEvt;
275
276     // Get the position of the control
277     const Position *pPos = pThis->getPosition();
278
279     // Compute the resize factors
280     float factorX, factorY;
281     pThis->getResizeFactors( factorX, factorY );
282
283     // Compute the relative position of the centre of the cursor
284     float relX = pEvtMouse->getXPos() - pPos->getLeft() - pThis->m_xOffset;
285     float relY = pEvtMouse->getYPos() - pPos->getTop() - pThis->m_yOffset;
286     // Ponderate with the resize factors
287     int relXPond = (int)(relX / factorX);
288     int relYPond = (int)(relY / factorY);
289
290     // Update the position
291     if( pThis->m_rCurve.getMinDist( relXPond, relYPond ) < RANGE )
292     {
293         float percentage = pThis->m_rCurve.getNearestPercent( relXPond,
294                                                               relYPond );
295         pThis->m_rVariable.set( percentage );
296     }
297     else
298     {
299         pThis->m_rVariable.set( pThis->m_lastPercentage );
300     }
301 }
302
303 void CtrlSliderCursor::transScroll( SkinObject *pCtrl )
304 {
305     CtrlSliderCursor *pThis = (CtrlSliderCursor*)pCtrl;
306     EvtScroll *pEvtScroll = (EvtScroll*)pThis->m_pEvt;
307
308     int direction = pEvtScroll->getDirection();
309
310     float percentage = pThis->m_rVariable.get();
311     if( direction == EvtScroll::kUp )
312     {
313         percentage += SCROLL_STEP;
314     }
315     else
316     {
317         percentage -= SCROLL_STEP;
318     }
319
320     pThis->m_rVariable.set( percentage );
321 }
322
323
324 void CtrlSliderCursor::getResizeFactors( float &rFactorX,
325                                          float &rFactorY ) const
326 {
327     // Get the position of the control
328     const Position *pPos = getPosition();
329
330     rFactorX = 1.0;
331     rFactorY = 1.0;
332
333     // Compute the resize factors
334     if( m_width > 0 )
335     {
336         rFactorX = (float)pPos->getWidth() / (float)m_width;
337     }
338     if( m_height > 0 )
339     {
340         rFactorY = (float)pPos->getHeight() / (float)m_height;
341     }
342 }
343
344
345
346 CtrlSliderBg::CtrlSliderBg( intf_thread_t *pIntf, CtrlSliderCursor &rCursor,
347                             const Bezier &rCurve, VarPercent &rVariable,
348                             int thickness, VarBool *pVisible,
349                             const UString &rHelp ):
350     CtrlGeneric( pIntf, rHelp, pVisible ), m_rCursor( rCursor ),
351     m_rVariable( rVariable ), m_thickness( thickness ), m_rCurve( rCurve ),
352     m_width( rCurve.getWidth() ), m_height( rCurve.getHeight() )
353 {
354 }
355
356
357 bool CtrlSliderBg::mouseOver( int x, int y ) const
358 {
359     // Compute the resize factors
360     float factorX, factorY;
361     getResizeFactors( factorX, factorY );
362
363     return (m_rCurve.getMinDist( (int)(x / factorX),
364                                  (int)(y / factorY) ) < m_thickness );
365 }
366
367
368 void CtrlSliderBg::handleEvent( EvtGeneric &rEvent )
369 {
370     if( rEvent.getAsString().find( "mouse:left:down" ) != string::npos )
371     {
372         // Compute the resize factors
373         float factorX, factorY;
374         getResizeFactors( factorX, factorY );
375
376         // Get the position of the control
377         const Position *pPos = getPosition();
378
379         // Get the value corresponding to the position of the mouse
380         EvtMouse &rEvtMouse = (EvtMouse&)rEvent;
381         int x = rEvtMouse.getXPos();
382         int y = rEvtMouse.getYPos();
383         m_rVariable.set( m_rCurve.getNearestPercent(
384                             (int)((x - pPos->getLeft()) / factorX),
385                             (int)((y - pPos->getTop()) / factorY) ) );
386
387         // Forward the clic to the cursor
388         EvtMouse evt( getIntf(), x, y, EvtMouse::kLeft, EvtMouse::kDown );
389         TopWindow *pWin = getWindow();
390         if( pWin )
391         {
392             EvtEnter evtEnter( getIntf() );
393             // XXX It was not supposed to be implemented like that !!
394             pWin->forwardEvent( evtEnter, m_rCursor );
395             pWin->forwardEvent( evt, m_rCursor );
396         }
397     }
398     else if( rEvent.getAsString().find( "scroll" ) != string::npos )
399     {
400         int direction = ((EvtScroll&)rEvent).getDirection();
401
402         float percentage = m_rVariable.get();
403         if( direction == EvtScroll::kUp )
404         {
405             percentage += SCROLL_STEP;
406         }
407         else
408         {
409             percentage -= SCROLL_STEP;
410         }
411
412         m_rVariable.set( percentage );
413     }
414 }
415
416
417 void CtrlSliderBg::getResizeFactors( float &rFactorX, float &rFactorY ) const
418 {
419     // Get the position of the control
420     const Position *pPos = getPosition();
421
422     rFactorX = 1.0;
423     rFactorY = 1.0;
424
425     // Compute the resize factors
426     if( m_width > 0 )
427     {
428         rFactorX = (float)pPos->getWidth() / (float)m_width;
429     }
430     if( m_height > 0 )
431     {
432         rFactorY = (float)pPos->getHeight() / (float)m_height;
433     }
434 }
435