1 /*****************************************************************************
2 * ctrl_button.cpp
3 *****************************************************************************
4 * Copyright (C) 2003 the VideoLAN team
5 * $Id: 06a294416320ed638862daab5b08943ba6b170d8 $
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
24
25 #include "ctrl_button.hpp"
26 #include "../events/evt_generic.hpp"
27 #include "../src/generic_bitmap.hpp"
28 #include "../src/generic_layout.hpp"
29 #include "../src/os_factory.hpp"
30 #include "../src/os_graphics.hpp"
31 #include "../commands/cmd_generic.hpp"
32
33
CtrlButton(intf_thread_t * pIntf,const GenericBitmap & rBmpUp,const GenericBitmap & rBmpOver,const GenericBitmap & rBmpDown,CmdGeneric & rCommand,const UString & rTooltip,const UString & rHelp,VarBool * pVisible)34 CtrlButton::CtrlButton( intf_thread_t *pIntf, const GenericBitmap &rBmpUp,
35 const GenericBitmap &rBmpOver,
36 const GenericBitmap &rBmpDown, CmdGeneric &rCommand,
37 const UString &rTooltip, const UString &rHelp,
38 VarBool *pVisible ):
39 CtrlGeneric( pIntf, rHelp, pVisible ), m_fsm( pIntf ),
40 m_rCommand( rCommand ), m_tooltip( rTooltip ),
41 m_imgUp( pIntf, rBmpUp ), m_imgOver( pIntf, rBmpOver ),
42 m_imgDown( pIntf, rBmpDown ), m_pImg( NULL ), m_cmdUpOverDownOver( this ),
43 m_cmdDownOverUpOver( this ), m_cmdDownOverDown( this ),
44 m_cmdDownDownOver( this ), m_cmdUpOverUp( this ), m_cmdUpUpOver( this ),
45 m_cmdDownUp( this ), m_cmdUpHidden( this ), m_cmdHiddenUp( this )
46 {
47 // States
48 m_fsm.addState( "up" );
49 m_fsm.addState( "down" );
50 m_fsm.addState( "upOver" );
51 m_fsm.addState( "downOver" );
52 m_fsm.addState( "hidden" );
53
54 // Transitions
55 m_fsm.addTransition( "upOver", "mouse:left:down", "downOver",
56 &m_cmdUpOverDownOver );
57 m_fsm.addTransition( "upOver", "mouse:left:dblclick", "downOver",
58 &m_cmdUpOverDownOver );
59 m_fsm.addTransition( "downOver", "mouse:left:up", "upOver",
60 &m_cmdDownOverUpOver );
61 m_fsm.addTransition( "downOver", "leave", "down", &m_cmdDownOverDown );
62 m_fsm.addTransition( "down", "enter", "downOver", &m_cmdDownDownOver );
63 m_fsm.addTransition( "upOver", "leave", "up", &m_cmdUpOverUp );
64 m_fsm.addTransition( "up", "enter", "upOver", &m_cmdUpUpOver );
65 m_fsm.addTransition( "down", "mouse:left:up", "up", &m_cmdDownUp );
66 // XXX: It would be easy to use a "ANY" initial state to handle these
67 // four lines in only one. But till now it isn't worthwhile...
68 m_fsm.addTransition( "up", "special:hide", "hidden", &m_cmdUpHidden );
69 m_fsm.addTransition( "down", "special:hide", "hidden", &m_cmdUpHidden );
70 m_fsm.addTransition( "upOver", "special:hide", "hidden", &m_cmdUpHidden );
71 m_fsm.addTransition( "downOver", "special:hide", "hidden", &m_cmdUpHidden );
72 m_fsm.addTransition( "hidden", "special:show", "up", &m_cmdHiddenUp );
73
74 // Initial state
75 m_fsm.setState( "up" );
76 setImage( &m_imgUp );
77 }
78
79
~CtrlButton()80 CtrlButton::~CtrlButton()
81 {
82 if( m_pImg )
83 {
84 m_pImg->stopAnim();
85 m_pImg->delObserver( this );
86 }
87 }
88
setLayout(GenericLayout * pLayout,const Position & rPosition)89 void CtrlButton::setLayout( GenericLayout *pLayout,
90 const Position &rPosition )
91 {
92 CtrlGeneric::setLayout( pLayout, rPosition );
93 m_pLayout->getActiveVar().addObserver( this );
94 }
95
96
unsetLayout()97 void CtrlButton::unsetLayout()
98 {
99 m_pLayout->getActiveVar().delObserver( this );
100 CtrlGeneric::unsetLayout();
101 }
102
handleEvent(EvtGeneric & rEvent)103 void CtrlButton::handleEvent( EvtGeneric &rEvent )
104 {
105 m_fsm.handleTransition( rEvent.getAsString() );
106 }
107
108
mouseOver(int x,int y) const109 bool CtrlButton::mouseOver( int x, int y ) const
110 {
111 if( m_pImg )
112 {
113 return m_pImg->hit( x, y );
114 }
115 else
116 {
117 return false;
118 }
119 }
120
121
draw(OSGraphics & rImage,int xDest,int yDest,int w,int h)122 void CtrlButton::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h )
123 {
124 const Position *pPos = getPosition();
125 rect region( pPos->getLeft(), pPos->getTop(),
126 pPos->getWidth(), pPos->getHeight() );
127 rect clip( xDest, yDest, w, h );
128 rect inter;
129 if( rect::intersect( region, clip, &inter ) && m_pImg )
130 {
131 // Draw the current image
132 m_pImg->draw( rImage, inter.x, inter.y, inter.width, inter.height,
133 inter.x - pPos->getLeft(),
134 inter.y - pPos->getTop() );
135 }
136 }
137
setImage(AnimBitmap * pImg)138 void CtrlButton::setImage( AnimBitmap *pImg )
139 {
140 if( pImg == m_pImg )
141 return;
142
143 if( pImg && m_pImg && *pImg == *m_pImg )
144 return;
145
146 AnimBitmap *pOldImg = m_pImg;
147 m_pImg = pImg;
148
149 if( pOldImg )
150 {
151 pOldImg->stopAnim();
152 pOldImg->delObserver( this );
153 }
154
155 if( pImg )
156 {
157 pImg->startAnim();
158 pImg->addObserver( this );
159 }
160
161 notifyLayoutMaxSize( pOldImg, pImg );
162 }
163
164
onUpdate(Subject<AnimBitmap> & rBitmap,void * arg)165 void CtrlButton::onUpdate( Subject<AnimBitmap> &rBitmap, void *arg )
166 {
167 (void)rBitmap;(void)arg;
168 notifyLayout( m_pImg->getWidth(), m_pImg->getHeight() );
169 }
170
171
execute()172 void CtrlButton::CmdUpOverDownOver::execute()
173 {
174 m_pParent->captureMouse();
175 m_pParent->setImage( &m_pParent->m_imgDown );
176 }
177
178
execute()179 void CtrlButton::CmdDownOverUpOver::execute()
180 {
181 m_pParent->releaseMouse();
182 m_pParent->setImage( &m_pParent->m_imgUp );
183 // Execute the command associated to this button
184 m_pParent->m_rCommand.execute();
185 }
186
187
execute()188 void CtrlButton::CmdDownOverDown::execute()
189 {
190 m_pParent->setImage( &m_pParent->m_imgUp );
191 }
192
193
execute()194 void CtrlButton::CmdDownDownOver::execute()
195 {
196 m_pParent->setImage( &m_pParent->m_imgDown );
197 }
198
199
execute()200 void CtrlButton::CmdUpUpOver::execute()
201 {
202 m_pParent->setImage( &m_pParent->m_imgOver );
203 }
204
205
execute()206 void CtrlButton::CmdUpOverUp::execute()
207 {
208 m_pParent->setImage( &m_pParent->m_imgUp );
209 }
210
211
execute()212 void CtrlButton::CmdDownUp::execute()
213 {
214 m_pParent->releaseMouse();
215 }
216
217
execute()218 void CtrlButton::CmdUpHidden::execute()
219 {
220 m_pParent->setImage( NULL );
221 }
222
223
execute()224 void CtrlButton::CmdHiddenUp::execute()
225 {
226 m_pParent->setImage( &m_pParent->m_imgUp );
227 }
228
onUpdate(Subject<VarBool> & rVariable,void * arg)229 void CtrlButton::onUpdate( Subject<VarBool> &rVariable, void *arg )
230 {
231 // restart animation
232 if( &rVariable == m_pVisible
233 || &rVariable == &m_pLayout->getActiveVar()
234 )
235 {
236 if( m_pImg )
237 {
238 m_pImg->stopAnim();
239 m_pImg->startAnim();
240 }
241 }
242 CtrlGeneric::onUpdate( rVariable, arg );
243 }
244
245