]> git.sesse.net Git - vlc/blob - modules/gui/skins2/src/top_window.cpp
3624c9c43159b5e97667ab157221afd80f3ab45d
[vlc] / modules / gui / skins2 / src / top_window.cpp
1 /*****************************************************************************
2  * top_window.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 "top_window.hpp"
26 #include "generic_layout.hpp"
27 #include "os_graphics.hpp"
28 #include "os_window.hpp"
29 #include "os_factory.hpp"
30 #include "theme.hpp"
31 #include "dialogs.hpp"
32 #include "var_manager.hpp"
33 #include "../commands/cmd_on_top.hpp"
34 #include "../controls/ctrl_generic.hpp"
35 #include "../events/evt_enter.hpp"
36 #include "../events/evt_focus.hpp"
37 #include "../events/evt_leave.hpp"
38 #include "../events/evt_motion.hpp"
39 #include "../events/evt_mouse.hpp"
40 #include "../events/evt_key.hpp"
41 #include "../events/evt_refresh.hpp"
42 #include "../events/evt_special.hpp"
43 #include "../events/evt_scroll.hpp"
44 #include "../utils/position.hpp"
45 #include "../utils/ustring.hpp"
46
47 #include <vlc_keys.h>
48
49
50 TopWindow::TopWindow( intf_thread_t *pIntf, int left, int top,
51                       WindowManager &rWindowManager,
52                       bool dragDrop, bool playOnDrop ):
53     GenericWindow( pIntf, left, top, dragDrop, playOnDrop,
54                    NULL),
55     m_rWindowManager( rWindowManager ), m_pActiveLayout( NULL ),
56     m_pLastHitControl( NULL ), m_pCapturingControl( NULL ),
57     m_pFocusControl( NULL ), m_currModifier( 0 )
58 {
59     // Register as a moving window
60     m_rWindowManager.registerWindow( *this );
61 }
62
63
64 TopWindow::~TopWindow()
65 {
66     // Unregister from the window manager
67     m_rWindowManager.unregisterWindow( *this );
68 }
69
70
71 void TopWindow::processEvent( EvtFocus &rEvtFocus )
72 {
73 //    fprintf(stderr, rEvtFocus.getAsString().c_str()) ;
74 }
75
76
77 void TopWindow::processEvent( EvtMotion &rEvtMotion )
78 {
79     // New control hit by the mouse
80     CtrlGeneric *pNewHitControl =
81         findHitControl( rEvtMotion.getXPos() - getLeft(),
82                         rEvtMotion.getYPos() - getTop() );
83
84     setLastHit( pNewHitControl );
85
86     /// Update the help text
87     VarManager *pVarManager = VarManager::instance( getIntf() );
88     if( pNewHitControl )
89     {
90         pVarManager->getHelpText().set( pNewHitControl->getHelpText() );
91     }
92
93     // Send a motion event to the hit control, or to the control
94     // that captured the mouse, if any
95     CtrlGeneric *pActiveControl = pNewHitControl;
96     if( m_pCapturingControl )
97     {
98         pActiveControl = m_pCapturingControl;
99     }
100     if( pActiveControl )
101     {
102         // Compute the coordinates relative to the window
103         int xPos = rEvtMotion.getXPos() - getLeft();
104         int yPos = rEvtMotion.getYPos() - getTop();
105         // Send a motion event
106         EvtMotion evt( getIntf(), xPos, yPos );
107         pActiveControl->handleEvent( evt );
108     }
109 }
110
111
112 void TopWindow::processEvent( EvtLeave &rEvtLeave )
113 {
114     // No more hit control
115     setLastHit( NULL );
116
117     if( !m_pCapturingControl )
118     {
119         m_rWindowManager.hideTooltip();
120     }
121 }
122
123
124 void TopWindow::processEvent( EvtMouse &rEvtMouse )
125 {
126     // Get the control hit by the mouse
127     CtrlGeneric *pNewHitControl = findHitControl( rEvtMouse.getXPos(),
128                                                   rEvtMouse.getYPos() );
129     setLastHit( pNewHitControl );
130
131     // Change the focused control
132     if( rEvtMouse.getAction() == EvtMouse::kDown )
133     {
134         // Raise all the windows
135         m_rWindowManager.raiseAll( *this );
136
137         if( pNewHitControl && pNewHitControl->isFocusable() )
138         {
139             // If a new control gains the focus, the previous one loses it
140             if( m_pFocusControl && m_pFocusControl != pNewHitControl )
141             {
142                 EvtFocus evt( getIntf(), false );
143                 m_pFocusControl->handleEvent( evt );
144             }
145             if( pNewHitControl != m_pFocusControl )
146             {
147                 m_pFocusControl = pNewHitControl;
148                 EvtFocus evt( getIntf(), false );
149                 pNewHitControl->handleEvent( evt );
150             }
151         }
152         else if( m_pFocusControl )
153         {
154             // The previous control loses the focus
155             EvtFocus evt( getIntf(), false );
156             m_pFocusControl->handleEvent( evt );
157             m_pFocusControl = NULL;
158         }
159     }
160
161     // Send a mouse event to the hit control, or to the control
162     // that captured the mouse, if any
163     CtrlGeneric *pActiveControl = pNewHitControl;
164     if( m_pCapturingControl )
165     {
166         pActiveControl = m_pCapturingControl;
167     }
168     if( pActiveControl )
169     {
170         pActiveControl->handleEvent( rEvtMouse );
171     }
172 }
173
174
175 void TopWindow::processEvent( EvtKey &rEvtKey )
176 {
177     // Forward the event to the focused control, if any
178     if( m_pFocusControl )
179     {
180         m_pFocusControl->handleEvent( rEvtKey );
181         return;
182     }
183
184     // Only do the action when the key is down
185     if( rEvtKey.getAsString().find( "key:down") != string::npos )
186     {
187         //XXX not to be hardcoded !
188         // Ctrl-S = Change skin
189         if( (rEvtKey.getMod() & EvtInput::kModCtrl) &&
190             rEvtKey.getKey() == 's' )
191         {
192             Dialogs *pDialogs = Dialogs::instance( getIntf() );
193             if( pDialogs != NULL )
194             {
195                 pDialogs->showChangeSkin();
196             }
197             return;
198         }
199
200         //XXX not to be hardcoded !
201         // Ctrl-T = Toggle on top
202         if( (rEvtKey.getMod() & EvtInput::kModCtrl) &&
203             rEvtKey.getKey() == 't' )
204         {
205             CmdOnTop cmd( getIntf() );
206             cmd.execute();
207             return;
208         }
209
210         vlc_value_t val;
211         // Set the key
212         val.i_int = rEvtKey.getKey();
213         // Set the modifiers
214         if( rEvtKey.getMod() & EvtInput::kModAlt )
215         {
216             val.i_int |= KEY_MODIFIER_ALT;
217         }
218         if( rEvtKey.getMod() & EvtInput::kModCtrl )
219         {
220             val.i_int |= KEY_MODIFIER_CTRL;
221         }
222         if( rEvtKey.getMod() & EvtInput::kModShift )
223         {
224             val.i_int |= KEY_MODIFIER_SHIFT;
225         }
226
227         var_Set( getIntf()->p_vlc, "key-pressed", val );
228     }
229
230     // Always store the modifier, which can be needed for scroll events
231     m_currModifier = rEvtKey.getMod();
232 }
233
234
235 void TopWindow::processEvent( EvtRefresh &rEvtRefresh )
236 {
237     // Refresh the given area
238     refresh( rEvtRefresh.getXStart(), rEvtRefresh.getYStart(),
239              rEvtRefresh.getWidth(), rEvtRefresh.getHeight() );
240 }
241
242
243 void TopWindow::processEvent( EvtScroll &rEvtScroll )
244 {
245     // Raise the windows
246     raise();
247
248     // Get the control hit by the mouse
249     CtrlGeneric *pNewHitControl = findHitControl( rEvtScroll.getXPos(),
250                                                   rEvtScroll.getYPos());
251     setLastHit( pNewHitControl );
252
253     // Send a mouse event to the hit control, or to the control
254     // that captured the mouse, if any
255     CtrlGeneric *pActiveControl = pNewHitControl;
256
257     if( m_pCapturingControl )
258     {
259         pActiveControl = m_pCapturingControl;
260     }
261     if( pActiveControl )
262     {
263         pActiveControl->handleEvent( rEvtScroll );
264     }
265     else
266     {
267         // Treat the scroll event as a hotkey
268         vlc_value_t val;
269         if( rEvtScroll.getDirection() == EvtScroll::kUp )
270         {
271             val.i_int = KEY_MOUSEWHEELUP;
272         }
273         else
274         {
275             val.i_int = KEY_MOUSEWHEELDOWN;
276         }
277         // Add the modifiers
278         val.i_int |= m_currModifier;
279
280         var_Set( getIntf()->p_vlc, "key-pressed", val );
281     }
282 }
283
284
285 void TopWindow::forwardEvent( EvtGeneric &rEvt, CtrlGeneric &rCtrl )
286 {
287     // XXX: We should do some checks here
288     rCtrl.handleEvent( rEvt );
289 }
290
291
292 void TopWindow::refresh( int left, int top, int width, int height )
293 {
294     if( m_pActiveLayout )
295     {
296         m_pActiveLayout->getImage()->copyToWindow( *getOSWindow(), left, top,
297                                                    width, height, left, top );
298     }
299 }
300
301
302 void TopWindow::setActiveLayout( GenericLayout *pLayout )
303 {
304     pLayout->setWindow( this );
305     m_pActiveLayout = pLayout;
306     // Get the size of the layout and resize the window
307     resize( pLayout->getWidth(), pLayout->getHeight() );
308     updateShape();
309     pLayout->refreshAll();
310 }
311
312
313 void TopWindow::innerShow()
314 {
315     // First, refresh the layout and update the shape of the window
316     if( m_pActiveLayout )
317     {
318         updateShape();
319         m_pActiveLayout->refreshAll();
320     }
321     // Show the window
322     GenericWindow::innerShow();
323 }
324
325  
326 void TopWindow::updateShape()
327 {
328     // Set the shape of the window
329     if( m_pActiveLayout )
330     {
331         OSGraphics *pImage = m_pActiveLayout->getImage();
332         if( pImage )
333         {
334             pImage->applyMaskToWindow( *getOSWindow() );
335         }
336     }
337 }
338
339
340 const list<Anchor*> TopWindow::getAnchorList() const
341 {
342     return m_anchorList;
343 }
344
345
346 void TopWindow::addAnchor( Anchor *pAnchor )
347 {
348     m_anchorList.push_back( pAnchor );
349 }
350
351
352 void TopWindow::onControlCapture( const CtrlGeneric &rCtrl )
353 {
354     // Set the capturing control
355     m_pCapturingControl = (CtrlGeneric*) &rCtrl;
356 }
357
358
359 void TopWindow::onControlRelease( const CtrlGeneric &rCtrl )
360 {
361     // Release the capturing control
362     if( m_pCapturingControl == &rCtrl )
363     {
364         m_pCapturingControl = NULL;
365     }
366     else
367     {
368         msg_Dbg( getIntf(), "Control had not captured the mouse" );
369     }
370
371     // Send an enter event to the control under the mouse, if it doesn't
372     // have received it yet
373     if( m_pLastHitControl && m_pLastHitControl != &rCtrl )
374     {
375         EvtEnter evt( getIntf() );
376         m_pLastHitControl->handleEvent( evt );
377
378         // Show the tooltip
379         m_rWindowManager.hideTooltip();
380         UString tipText = m_pLastHitControl->getTooltipText();
381         if( tipText.length() > 0 )
382         {
383             // Set the tooltip text variable
384             VarManager *pVarManager = VarManager::instance( getIntf() );
385             pVarManager->getTooltipText().set( tipText );
386             m_rWindowManager.showTooltip();
387         }
388     }
389 }
390
391
392 void TopWindow::onTooltipChange( const CtrlGeneric &rCtrl )
393 {
394     // Check that the control is the active one
395     if( m_pLastHitControl && m_pLastHitControl == &rCtrl )
396     {
397         // Set the tooltip text variable
398         VarManager *pVarManager = VarManager::instance( getIntf() );
399         pVarManager->getTooltipText().set( rCtrl.getTooltipText() );
400     }
401 }
402
403
404 CtrlGeneric *TopWindow::findHitControl( int xPos, int yPos )
405 {
406     if( m_pActiveLayout == NULL )
407     {
408         return NULL;
409     }
410
411     // Get the controls in the active layout
412     const list<LayeredControl> &ctrlList = m_pActiveLayout->getControlList();
413     list<LayeredControl>::const_reverse_iterator iter;
414
415     // New control hit by the mouse
416     CtrlGeneric *pNewHitControl = NULL;
417
418     // Loop on the control list to find the uppest hit control
419     for( iter = ctrlList.rbegin(); iter != ctrlList.rend(); iter++ )
420     {
421         // Get the position of the control in the layout
422         const Position *pos = (*iter).m_pControl->getPosition();
423         if( pos != NULL )
424         {
425             // Compute the coordinates of the mouse relative to the control
426             int xRel = xPos - pos->getLeft();
427             int yRel = yPos - pos->getTop();
428
429             CtrlGeneric *pCtrl = (*iter).m_pControl;
430             // Control hit ?
431             if( pCtrl->isVisible() && pCtrl->mouseOver( xRel, yRel ) )
432             {
433                 pNewHitControl = (*iter).m_pControl;
434                 break;
435             }
436         }
437         else
438         {
439             msg_Dbg( getIntf(), "Control at NULL position" );
440         }
441     }
442
443     // If the hit control has just been entered, send it an enter event
444     if( pNewHitControl && (pNewHitControl != m_pLastHitControl) )
445     {
446         // Don't send the event if another control captured the mouse
447         if( !m_pCapturingControl || (m_pCapturingControl == pNewHitControl ) )
448         {
449             EvtEnter evt( getIntf() );
450             pNewHitControl->handleEvent( evt );
451
452             if( !m_pCapturingControl )
453             {
454                 // Show the tooltip
455                 m_rWindowManager.hideTooltip();
456                 UString tipText = pNewHitControl->getTooltipText();
457                 if( tipText.length() > 0 )
458                 {
459                     // Set the tooltip text variable
460                     VarManager *pVarManager = VarManager::instance( getIntf() );
461                     pVarManager->getTooltipText().set( tipText );
462                     m_rWindowManager.showTooltip();
463                 }
464             }
465         }
466     }
467
468     return pNewHitControl;
469 }
470
471
472
473 void TopWindow::setLastHit( CtrlGeneric *pNewHitControl )
474 {
475     // Send a leave event to the left control
476     if( m_pLastHitControl && (pNewHitControl != m_pLastHitControl) )
477     {
478         // Don't send the event if another control captured the mouse
479         if( !m_pCapturingControl || (m_pCapturingControl == m_pLastHitControl))
480         {
481             EvtLeave evt( getIntf() );
482             m_pLastHitControl->handleEvent( evt );
483         }
484     }
485
486     m_pLastHitControl = pNewHitControl;
487 }
488