1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 the VideoLAN team
7 * Authors: Cyril Deguet <asmax@via.ecp.fr>
8 * Olivier Teulière <ipkiss@via.ecp.fr>
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.
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.
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
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/scaled_bitmap.hpp"
31 #include "../src/top_window.hpp"
32 #include "../src/os_factory.hpp"
33 #include "../src/os_graphics.hpp"
34 #include "../utils/position.hpp"
35 #include "../utils/var_percent.hpp"
39 #define SCROLL_STEP 0.05f
41 static inline float scroll( bool up
, float pct
)
43 return pct
+ (up
? SCROLL_STEP
: -SCROLL_STEP
);
47 CtrlSliderCursor::CtrlSliderCursor( intf_thread_t
*pIntf
,
48 const GenericBitmap
&rBmpUp
,
49 const GenericBitmap
&rBmpOver
,
50 const GenericBitmap
&rBmpDown
,
52 VarPercent
&rVariable
,
54 const UString
&rTooltip
,
55 const UString
&rHelp
):
56 CtrlGeneric( pIntf
, rHelp
, pVisible
), m_fsm( pIntf
),
57 m_rVariable( rVariable
), m_tooltip( rTooltip
),
58 m_width( rCurve
.getWidth() ), m_height( rCurve
.getHeight() ),
59 m_cmdOverDown( this ), m_cmdDownOver( this ),
60 m_cmdOverUp( this ), m_cmdUpOver( this ),
61 m_cmdMove( this ), m_cmdScroll( this ),
62 m_lastPercentage( 0 ), m_xOffset( 0 ), m_yOffset( 0 ),
63 m_pEvt( NULL
), m_rCurve( rCurve
)
65 // Build the images of the cursor
66 OSFactory
*pOsFactory
= OSFactory::instance( getIntf() );
67 m_pImgUp
= pOsFactory
->createOSGraphics( rBmpUp
.getWidth(),
69 m_pImgUp
->drawBitmap( rBmpUp
, 0, 0 );
70 m_pImgDown
= pOsFactory
->createOSGraphics( rBmpDown
.getWidth(),
71 rBmpDown
.getHeight() );
72 m_pImgDown
->drawBitmap( rBmpDown
, 0, 0 );
73 m_pImgOver
= pOsFactory
->createOSGraphics( rBmpOver
.getWidth(),
74 rBmpOver
.getHeight() );
75 m_pImgOver
->drawBitmap( rBmpOver
, 0, 0 );
78 m_fsm
.addState( "up" );
79 m_fsm
.addState( "over" );
80 m_fsm
.addState( "down" );
83 m_fsm
.addTransition( "over", "mouse:left:down", "down",
85 m_fsm
.addTransition( "down", "mouse:left:up", "over",
87 m_fsm
.addTransition( "over", "leave", "up", &m_cmdOverUp
);
88 m_fsm
.addTransition( "up", "enter", "over", &m_cmdUpOver
);
89 m_fsm
.addTransition( "down", "motion", "down", &m_cmdMove
);
90 m_fsm
.addTransition( "over", "scroll", "over", &m_cmdScroll
);
93 m_fsm
.setState( "up" );
96 // Observe the position variable
97 m_rVariable
.addObserver( this );
99 // Initial position of the cursor
100 m_lastPercentage
= m_rVariable
.get();
104 CtrlSliderCursor::~CtrlSliderCursor()
106 m_rVariable
.delObserver( this );
113 void CtrlSliderCursor::handleEvent( EvtGeneric
&rEvent
)
115 // Save the event to use it in callbacks
118 m_fsm
.handleTransition( rEvent
.getAsString() );
122 bool CtrlSliderCursor::mouseOver( int x
, int y
) const
126 // Compute the position of the cursor
128 m_rCurve
.getPoint( m_rVariable
.get(), xPos
, yPos
);
130 // Compute the resize factors
131 float factorX
, factorY
;
132 getResizeFactors( factorX
, factorY
);
133 xPos
= (int)(xPos
* factorX
);
134 yPos
= (int)(yPos
* factorY
);
136 return m_pImg
->hit( x
- xPos
+ m_pImg
->getWidth() / 2,
137 y
- yPos
+ m_pImg
->getHeight() / 2 );
146 void CtrlSliderCursor::draw( OSGraphics
&rImage
, int xDest
, int yDest
)
150 // Compute the position of the cursor
152 m_rCurve
.getPoint( m_rVariable
.get(), xPos
, yPos
);
154 // Compute the resize factors
155 float factorX
, factorY
;
156 getResizeFactors( factorX
, factorY
);
157 xPos
= (int)(xPos
* factorX
);
158 yPos
= (int)(yPos
* factorY
);
160 // Draw the current image
161 rImage
.drawGraphics( *m_pImg
, 0, 0,
162 xDest
+ xPos
- m_pImg
->getWidth() / 2,
163 yDest
+ yPos
- m_pImg
->getHeight() / 2 );
168 void CtrlSliderCursor::onUpdate( Subject
<VarPercent
> &rVariable
,
171 // The position has changed
176 void CtrlSliderCursor::CmdOverDown::execute()
178 EvtMouse
*pEvtMouse
= static_cast<EvtMouse
*>(m_pParent
->m_pEvt
);
180 // Compute the resize factors
181 float factorX
, factorY
;
182 m_pParent
->getResizeFactors( factorX
, factorY
);
184 // Get the position of the control
185 const Position
*pPos
= m_pParent
->getPosition();
187 // Compute the offset
189 m_pParent
->m_rCurve
.getPoint( m_pParent
->m_rVariable
.get(), tempX
, tempY
);
190 m_pParent
->m_xOffset
= pEvtMouse
->getXPos() - pPos
->getLeft()
191 - (int)(tempX
* factorX
);
192 m_pParent
->m_yOffset
= pEvtMouse
->getYPos() - pPos
->getTop()
193 - (int)(tempY
* factorY
);
195 m_pParent
->captureMouse();
196 m_pParent
->m_pImg
= m_pParent
->m_pImgDown
;
197 m_pParent
->refreshLayout();
201 void CtrlSliderCursor::CmdDownOver::execute()
204 m_pParent
->m_lastPercentage
= m_pParent
->m_rVariable
.get();
206 m_pParent
->releaseMouse();
207 m_pParent
->m_pImg
= m_pParent
->m_pImgUp
;
208 m_pParent
->refreshLayout();
212 void CtrlSliderCursor::CmdUpOver::execute()
214 m_pParent
->m_pImg
= m_pParent
->m_pImgOver
;
215 m_pParent
->refreshLayout();
219 void CtrlSliderCursor::CmdOverUp::execute()
221 m_pParent
->m_pImg
= m_pParent
->m_pImgUp
;
222 m_pParent
->refreshLayout();
226 void CtrlSliderCursor::CmdMove::execute()
228 EvtMouse
*pEvtMouse
= static_cast<EvtMouse
*>(m_pParent
->m_pEvt
);
230 // Get the position of the control
231 const Position
*pPos
= m_pParent
->getPosition();
233 // Compute the resize factors
234 float factorX
, factorY
;
235 m_pParent
->getResizeFactors( factorX
, factorY
);
237 // Compute the relative position of the centre of the cursor
238 float relX
= pEvtMouse
->getXPos() - pPos
->getLeft() - m_pParent
->m_xOffset
;
239 float relY
= pEvtMouse
->getYPos() - pPos
->getTop() - m_pParent
->m_yOffset
;
240 // Ponderate with the resize factors
241 int relXPond
= (int)(relX
/ factorX
);
242 int relYPond
= (int)(relY
/ factorY
);
244 // Update the position
245 if( m_pParent
->m_rCurve
.getMinDist( relXPond
, relYPond
) < RANGE
)
247 float percentage
= m_pParent
->m_rCurve
.getNearestPercent( relXPond
,
249 m_pParent
->m_rVariable
.set( percentage
);
253 m_pParent
->m_rVariable
.set( m_pParent
->m_lastPercentage
);
257 void CtrlSliderCursor::CmdScroll::execute()
259 // XXX Two of these in this file, figure out where it really belongs.
260 int dir
= static_cast<EvtScroll
*>(m_pParent
->m_pEvt
)->getDirection();
261 m_pParent
->m_rVariable
.set( scroll( EvtScroll::kUp
== dir
,
262 m_pParent
->m_rVariable
.get() ) );
266 void CtrlSliderCursor::getResizeFactors( float &rFactorX
,
267 float &rFactorY
) const
269 // Get the position of the control
270 const Position
*pPos
= getPosition();
275 // Compute the resize factors
277 rFactorX
= (float)pPos
->getWidth() / (float)m_width
;
279 rFactorY
= (float)pPos
->getHeight() / (float)m_height
;
283 void CtrlSliderCursor::refreshLayout()
289 // Compute the resize factors
290 float factorX
, factorY
;
291 getResizeFactors( factorX
, factorY
);
293 notifyLayout( (int)(m_rCurve
.getWidth() * factorX
) + m_pImg
->getWidth(),
294 (int)(m_rCurve
.getHeight() * factorY
) + m_pImg
->getHeight(),
295 - m_pImg
->getWidth() / 2,
296 - m_pImg
->getHeight() / 2 );
301 CtrlSliderBg::CtrlSliderBg( intf_thread_t
*pIntf
,
302 const Bezier
&rCurve
, VarPercent
&rVariable
,
303 int thickness
, GenericBitmap
*pBackground
,
304 int nbHoriz
, int nbVert
, int padHoriz
, int padVert
,
305 VarBool
*pVisible
, const UString
&rHelp
):
306 CtrlGeneric( pIntf
, rHelp
, pVisible
), m_pCursor( NULL
),
307 m_rVariable( rVariable
), m_thickness( thickness
), m_rCurve( rCurve
),
308 m_width( rCurve
.getWidth() ), m_height( rCurve
.getHeight() ),
309 m_pImgSeq( pBackground
), m_nbHoriz( nbHoriz
), m_nbVert( nbVert
),
310 m_padHoriz( padHoriz
), m_padVert( padVert
), m_bgWidth( 0 ),
311 m_bgHeight( 0 ), m_position( 0 )
315 // Build the background image sequence
316 // Note: we suppose that the last padding is not included in the
318 // TODO: we should probably change this assumption, as it would make
319 // the code a bit simpler and it would be more natural for the skins
321 m_bgWidth
= (pBackground
->getWidth() + m_padHoriz
) / nbHoriz
;
322 m_bgHeight
= (pBackground
->getHeight() + m_padVert
) / nbVert
;
324 // Observe the position variable
325 m_rVariable
.addObserver( this );
328 m_position
= (int)( m_rVariable
.get() * (m_nbHoriz
* m_nbVert
- 1) );
333 CtrlSliderBg::~CtrlSliderBg()
335 m_rVariable
.delObserver( this );
339 bool CtrlSliderBg::mouseOver( int x
, int y
) const
341 // Compute the resize factors
342 float factorX
, factorY
;
343 getResizeFactors( factorX
, factorY
);
345 return (m_rCurve
.getMinDist( (int)(x
/ factorX
), (int)(y
/ factorY
),
346 factorX
, factorY
) < m_thickness
);
350 void CtrlSliderBg::draw( OSGraphics
&rImage
, int xDest
, int yDest
)
352 if( !m_pImgSeq
|| m_bgWidth
<=0 || m_bgHeight
<= 0 )
355 // Compute the resize factors
356 float factorX
, factorY
;
357 getResizeFactors( factorX
, factorY
);
359 // Rescale the image with the actual size of the control
360 ScaledBitmap
bmp( getIntf(), *m_pImgSeq
,
361 m_bgWidth
* m_nbHoriz
- (int)(m_padHoriz
* factorX
),
362 m_bgHeight
* m_nbVert
- (int)(m_padVert
* factorY
) );
364 // Locate the right image in the background bitmap
365 int x
= m_bgWidth
* ( m_position
% m_nbHoriz
);
366 int y
= m_bgHeight
* ( m_position
/ m_nbHoriz
);
367 // Draw the background image
368 rImage
.drawBitmap( bmp
, x
, y
, xDest
, yDest
,
369 m_bgWidth
- (int)(m_padHoriz
* factorX
),
370 m_bgHeight
- (int)(m_padVert
* factorY
) );
374 void CtrlSliderBg::handleEvent( EvtGeneric
&rEvent
)
376 if( rEvent
.getAsString().find( "mouse:left:down" ) != string::npos
)
378 // Compute the resize factors
379 float factorX
, factorY
;
380 getResizeFactors( factorX
, factorY
);
382 // Get the position of the control
383 const Position
*pPos
= getPosition();
385 // Get the value corresponding to the position of the mouse
386 EvtMouse
&rEvtMouse
= (EvtMouse
&)rEvent
;
387 int x
= rEvtMouse
.getXPos();
388 int y
= rEvtMouse
.getYPos();
389 m_rVariable
.set( m_rCurve
.getNearestPercent(
390 (int)((x
- pPos
->getLeft()) / factorX
),
391 (int)((y
- pPos
->getTop()) / factorY
) ) );
393 // Forward the clic to the cursor
394 EvtMouse
evt( getIntf(), x
, y
, EvtMouse::kLeft
, EvtMouse::kDown
);
395 TopWindow
*pWin
= getWindow();
396 if( pWin
&& m_pCursor
)
398 EvtEnter
evtEnter( getIntf() );
399 // XXX It was not supposed to be implemented like that !!
400 pWin
->forwardEvent( evtEnter
, *m_pCursor
);
401 pWin
->forwardEvent( evt
, *m_pCursor
);
404 else if( rEvent
.getAsString().find( "scroll" ) != string::npos
)
406 // XXX Two of these in this file, figure out where it really belongs.
407 int dir
= static_cast<EvtScroll
*>(&rEvent
)->getDirection();
408 m_rVariable
.set( scroll( EvtScroll::kUp
== dir
, m_rVariable
.get() ) );
413 void CtrlSliderBg::onResize()
417 // Compute only the new size of an elementary image.
418 // The actual resizing is done in the draw() method for now...
420 // Compute the resize factors
421 float factorX
, factorY
;
422 getResizeFactors( factorX
, factorY
);
424 // Size of one elementary background image (padding included)
425 m_bgWidth
= (int)((m_pImgSeq
->getWidth() + m_padHoriz
) * factorX
/ m_nbHoriz
);
426 m_bgHeight
= (int)((m_pImgSeq
->getHeight() + m_padVert
) * factorY
/ m_nbVert
);
431 void CtrlSliderBg::associateCursor( CtrlSliderCursor
&rCursor
)
433 m_pCursor
= &rCursor
;
437 void CtrlSliderBg::onUpdate( Subject
<VarPercent
> &rVariable
, void*arg
)
439 int position
= (int)( m_rVariable
.get() * (m_nbHoriz
* m_nbVert
- 1) );
440 if( position
== m_position
)
443 m_position
= position
;
444 notifyLayout( m_bgWidth
, m_bgHeight
);
448 void CtrlSliderBg::getResizeFactors( float &rFactorX
, float &rFactorY
) const
450 // Get the position of the control
451 const Position
*pPos
= getPosition();
456 // Compute the resize factors
458 rFactorX
= (float)pPos
->getWidth() / (float)m_width
;
460 rFactorY
= (float)pPos
->getHeight() / (float)m_height
;