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
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 #include "ctrl_checkbox.hpp"
26 #include "../events/evt_generic.hpp"
27 #include "../commands/cmd_generic.hpp"
28 #include "../src/generic_bitmap.hpp"
29 #include "../src/os_factory.hpp"
30 #include "../src/os_graphics.hpp"
31 #include "../utils/var_bool.hpp"
34 CtrlCheckbox::CtrlCheckbox( intf_thread_t *pIntf,
35 const GenericBitmap &rBmpUp1,
36 const GenericBitmap &rBmpOver1,
37 const GenericBitmap &rBmpDown1,
38 const GenericBitmap &rBmpUp2,
39 const GenericBitmap &rBmpOver2,
40 const GenericBitmap &rBmpDown2,
41 CmdGeneric &rCommand1, CmdGeneric &rCommand2,
42 const UString &rTooltip1,
43 const UString &rTooltip2,
44 VarBool &rVariable, const UString &rHelp,
46 CtrlGeneric( pIntf, rHelp, pVisible ), m_fsm( pIntf ),
47 m_rVariable( rVariable ),
48 m_rCommand1( rCommand1 ), m_rCommand2( rCommand2 ),
49 m_tooltip1( rTooltip1 ), m_tooltip2( rTooltip2 ),
50 m_imgUp1( pIntf, rBmpUp1 ), m_imgOver1( pIntf, rBmpOver1 ),
51 m_imgDown1( pIntf, rBmpDown1 ), m_imgUp2( pIntf, rBmpUp2 ),
52 m_imgOver2( pIntf, rBmpOver2 ), m_imgDown2( pIntf, rBmpDown2 ),
53 m_cmdUpOverDownOver( this ), m_cmdDownOverUpOver( this ),
54 m_cmdDownOverDown( this ), m_cmdDownDownOver( this ),
55 m_cmdUpOverUp( this ), m_cmdUpUpOver( this ),
56 m_cmdDownUp( this ), m_cmdUpHidden( this ),
60 m_fsm.addState( "up" );
61 m_fsm.addState( "down" );
62 m_fsm.addState( "upOver" );
63 m_fsm.addState( "downOver" );
64 m_fsm.addState( "hidden" );
67 m_fsm.addTransition( "upOver", "mouse:left:down", "downOver",
68 &m_cmdUpOverDownOver );
69 m_fsm.addTransition( "upOver", "mouse:left:dblclick", "downOver",
70 &m_cmdUpOverDownOver );
71 m_fsm.addTransition( "downOver", "mouse:left:up", "upOver",
72 &m_cmdDownOverUpOver );
73 m_fsm.addTransition( "downOver", "leave", "down", &m_cmdDownOverDown );
74 m_fsm.addTransition( "down", "enter", "downOver", &m_cmdDownDownOver );
75 m_fsm.addTransition( "upOver", "leave", "up", &m_cmdUpOverUp );
76 m_fsm.addTransition( "up", "enter", "upOver", &m_cmdUpUpOver );
77 m_fsm.addTransition( "down", "mouse:left:up", "up", &m_cmdDownUp );
78 // XXX: It would be easy to use a "ANY" initial state to handle these
79 // four lines in only one. But till now it isn't worthwhile...
80 m_fsm.addTransition( "up", "special:hide", "hidden", &m_cmdUpHidden );
81 m_fsm.addTransition( "down", "special:hide", "hidden", &m_cmdUpHidden );
82 m_fsm.addTransition( "upOver", "special:hide", "hidden", &m_cmdUpHidden );
83 m_fsm.addTransition( "downOver", "special:hide", "hidden", &m_cmdUpHidden );
84 m_fsm.addTransition( "hidden", "special:show", "up", &m_cmdHiddenUp );
86 // Observe the variable
87 m_rVariable.addObserver( this );
90 m_fsm.setState( "up" );
91 if( !m_rVariable.get() )
94 m_pImgOver = &m_imgOver1;
95 m_pImgDown = &m_imgDown1;
96 m_pImgCurrent = m_pImgUp;
97 m_pCommand = &m_rCommand1;
98 m_pTooltip = &m_tooltip1;
102 m_pImgUp = &m_imgUp2;
103 m_pImgOver = &m_imgOver2;
104 m_pImgDown = &m_imgDown2;
105 m_pImgCurrent = m_pImgDown;
106 m_pCommand = &m_rCommand2;
107 m_pTooltip = &m_tooltip2;
112 CtrlCheckbox::~CtrlCheckbox()
114 m_rVariable.delObserver( this );
118 void CtrlCheckbox::handleEvent( EvtGeneric &rEvent )
120 m_fsm.handleTransition( rEvent.getAsString() );
124 bool CtrlCheckbox::mouseOver( int x, int y ) const
128 return m_pImgCurrent->hit( x, y );
137 void CtrlCheckbox::draw( OSGraphics &rImage, int xDest, int yDest )
141 // Draw the current image
142 m_pImgCurrent->draw( rImage, xDest, yDest );
147 void CtrlCheckbox::setImage( AnimBitmap *pImg )
149 AnimBitmap *pOldImg = m_pImgCurrent;
150 m_pImgCurrent = pImg;
155 pOldImg->delObserver( this );
161 pImg->addObserver( this );
164 notifyLayoutMaxSize( pOldImg, pImg );
168 void CtrlCheckbox::CmdUpOverDownOver::execute()
170 m_pParent->captureMouse();
171 m_pParent->setImage( m_pParent->m_pImgDown );
175 void CtrlCheckbox::CmdDownOverUpOver::execute()
177 m_pParent->releaseMouse();
179 // There is a little trick here: since we update the image of the control
180 // before executing the command, there is no way that the observed variable
181 // can have changed, so changeButton() has not been called, and m_pImgUp is
182 // still the "old" up state. That's why we don't use it, and use the other
183 // one instead. Otherwise, we would notice a "phantom effect", where the
184 // old up image is displayed for a few milliseconds, until the variable is
185 // updated and the correct up image is displayed.
186 // Executing the action before refreshing the state wouldn't work, because
187 // the variable may be updated asynchronously (when triggered by a callback
188 // from an object variable).
190 // Invert the state variable
191 if( m_pParent->m_pImgUp == &m_pParent->m_imgUp1 )
192 m_pParent->setImage( &m_pParent->m_imgUp2 );
194 m_pParent->setImage( &m_pParent->m_imgUp1 );
196 // Execute the command
197 m_pParent->m_pCommand->execute();
201 void CtrlCheckbox::CmdDownOverDown::execute()
203 m_pParent->setImage( m_pParent->m_pImgUp );
207 void CtrlCheckbox::CmdDownDownOver::execute()
209 m_pParent->setImage( m_pParent->m_pImgDown );
213 void CtrlCheckbox::CmdUpUpOver::execute()
215 m_pParent->setImage( m_pParent->m_pImgOver );
219 void CtrlCheckbox::CmdUpOverUp::execute()
221 m_pParent->setImage( m_pParent->m_pImgUp );
225 void CtrlCheckbox::CmdDownUp::execute()
227 m_pParent->releaseMouse();
231 void CtrlCheckbox::CmdUpHidden::execute()
233 m_pParent->setImage( NULL );
237 void CtrlCheckbox::CmdHiddenUp::execute()
239 m_pParent->setImage( m_pParent->m_pImgUp );
243 void CtrlCheckbox::onVarBoolUpdate( VarBool &rVariable )
249 void CtrlCheckbox::onUpdate( Subject<AnimBitmap, void*> &rBitmap, void *arg )
255 void CtrlCheckbox::changeButton()
257 // Are we using the first set of images or the second one?
258 if( m_pImgUp == &m_imgUp1 )
260 m_pImgUp = &m_imgUp2;
261 m_pImgOver = &m_imgOver2;
262 m_pImgDown = &m_imgDown2;
263 m_pTooltip = &m_tooltip2;
264 m_pCommand = &m_rCommand2;
268 m_pImgUp = &m_imgUp1;
269 m_pImgOver = &m_imgOver1;
270 m_pImgDown = &m_imgDown1;
271 m_pTooltip = &m_tooltip1;
272 m_pCommand = &m_rCommand1;
274 // XXX: We assume that the checkbox is up
275 setImage( m_pImgUp );
277 // Notify the window the tooltip has changed
278 notifyTooltipChange();