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