]> git.sesse.net Git - vlc/blob - modules/gui/skins2/src/top_window.cpp
d5a559ba1fa22d841f5a4175107ebf4a6f545ed3
[vlc] / modules / gui / skins2 / src / top_window.cpp
1 /*****************************************************************************
2  * top_window.cpp
3  *****************************************************************************
4  * Copyright (C) 2003 the VideoLAN team
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 "var_manager.hpp"
32 #include "../commands/cmd_on_top.hpp"
33 #include "../commands/cmd_dialogs.hpp"
34 #include "../controls/ctrl_generic.hpp"
35 #include "../events/evt_refresh.hpp"
36 #include "../events/evt_enter.hpp"
37 #include "../events/evt_focus.hpp"
38 #include "../events/evt_leave.hpp"
39 #include "../events/evt_motion.hpp"
40 #include "../events/evt_mouse.hpp"
41 #include "../events/evt_key.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, bool visible ):
53     GenericWindow( pIntf, left, top, dragDrop, playOnDrop, NULL ),
54     m_visible( visible ), m_rWindowManager( rWindowManager ),
55     m_pActiveLayout( NULL ), m_pLastHitControl( NULL ),
56     m_pCapturingControl( NULL ), m_pFocusControl( NULL ), m_currModifier( 0 )
57 {
58     // Register as a moving window
59     m_rWindowManager.registerWindow( *this );
60 }
61
62
63 TopWindow::~TopWindow()
64 {
65     // Unregister from the window manager
66     m_rWindowManager.unregisterWindow( *this );
67 }
68
69
70 void TopWindow::processEvent( EvtRefresh &rEvtRefresh )
71 {
72     // We override the behaviour defined in GenericWindow, because we don't
73     // want to draw on a video control!
74     if( m_pActiveLayout == NULL )
75     {
76         GenericWindow::processEvent( rEvtRefresh );
77     }
78     else
79     {
80         m_pActiveLayout->refreshRect( rEvtRefresh.getXStart(),
81                                       rEvtRefresh.getYStart(),
82                                       rEvtRefresh.getWidth(),
83                                       rEvtRefresh.getHeight() );
84     }
85 }
86
87
88 void TopWindow::processEvent( EvtFocus &rEvtFocus )
89 {
90 //    fprintf(stderr, rEvtFocus.getAsString().c_str()) ;
91 }
92
93
94 void TopWindow::processEvent( EvtMotion &rEvtMotion )
95 {
96     // New control hit by the mouse
97     CtrlGeneric *pNewHitControl =
98         findHitControl( rEvtMotion.getXPos() - getLeft(),
99                         rEvtMotion.getYPos() - getTop() );
100
101     setLastHit( pNewHitControl );
102
103     /// Update the help text
104     VarManager *pVarManager = VarManager::instance( getIntf() );
105     if( pNewHitControl )
106     {
107         pVarManager->getHelpText().set( pNewHitControl->getHelpText() );
108     }
109
110     // Send a motion event to the hit control, or to the control
111     // that captured the mouse, if any
112     CtrlGeneric *pActiveControl = pNewHitControl;
113     if( m_pCapturingControl )
114     {
115         pActiveControl = m_pCapturingControl;
116     }
117     if( pActiveControl )
118     {
119         // Compute the coordinates relative to the window
120         int xPos = rEvtMotion.getXPos() - getLeft();
121         int yPos = rEvtMotion.getYPos() - getTop();
122         // Send a motion event
123         EvtMotion evt( getIntf(), xPos, yPos );
124         pActiveControl->handleEvent( evt );
125     }
126 }
127
128
129 void TopWindow::processEvent( EvtLeave &rEvtLeave )
130 {
131     // No more hit control
132     setLastHit( NULL );
133
134     if( !m_pCapturingControl )
135     {
136         m_rWindowManager.hideTooltip();
137     }
138 }
139
140
141 void TopWindow::processEvent( EvtMouse &rEvtMouse )
142 {
143     // Get the control hit by the mouse
144     CtrlGeneric *pNewHitControl = findHitControl( rEvtMouse.getXPos(),
145                                                   rEvtMouse.getYPos() );
146     setLastHit( pNewHitControl );
147
148     // Change the focused control
149     if( rEvtMouse.getAction() == EvtMouse::kDown )
150     {
151         // Raise the window
152         m_rWindowManager.raise( *this );
153
154         if( pNewHitControl && pNewHitControl->isFocusable() )
155         {
156             // If a new control gains the focus, the previous one loses it
157             if( m_pFocusControl && m_pFocusControl != pNewHitControl )
158             {
159                 EvtFocus evt( getIntf(), false );
160                 m_pFocusControl->handleEvent( evt );
161             }
162             if( pNewHitControl != m_pFocusControl )
163             {
164                 m_pFocusControl = pNewHitControl;
165                 EvtFocus evt( getIntf(), false );
166                 pNewHitControl->handleEvent( evt );
167             }
168         }
169         else if( m_pFocusControl )
170         {
171             // The previous control loses the focus
172             EvtFocus evt( getIntf(), false );
173             m_pFocusControl->handleEvent( evt );
174             m_pFocusControl = NULL;
175         }
176     }
177
178     // Send a mouse event to the hit control, or to the control
179     // that captured the mouse, if any
180     CtrlGeneric *pActiveControl = pNewHitControl;
181     if( m_pCapturingControl )
182     {
183         pActiveControl = m_pCapturingControl;
184     }
185     if( pActiveControl )
186     {
187         pActiveControl->handleEvent( rEvtMouse );
188     }
189 }
190
191
192 void TopWindow::processEvent( EvtKey &rEvtKey )
193 {
194     // Forward the event to the focused control, if any
195     if( m_pFocusControl )
196     {
197         m_pFocusControl->handleEvent( rEvtKey );
198         return;
199     }
200
201     // Only do the action when the key is down
202     if( rEvtKey.getAsString().find( "key:down") != string::npos )
203     {
204         //XXX not to be hardcoded!
205         // Ctrl-S = Change skin
206         if( (rEvtKey.getMod() & EvtInput::kModCtrl) &&
207             rEvtKey.getKey() == 's' )
208         {
209             CmdDlgChangeSkin cmd( getIntf() );
210             cmd.execute();
211             return;
212         }
213
214         //XXX not to be hardcoded!
215         // Ctrl-T = Toggle on top
216         if( (rEvtKey.getMod() & EvtInput::kModCtrl) &&
217             rEvtKey.getKey() == 't' )
218         {
219             CmdOnTop cmd( getIntf() );
220             cmd.execute();
221             return;
222         }
223
224         vlc_value_t val;
225         // Set the key
226         val.i_int = rEvtKey.getKey();
227         // Set the modifiers
228         if( rEvtKey.getMod() & EvtInput::kModAlt )
229         {
230             val.i_int |= KEY_MODIFIER_ALT;
231         }
232         if( rEvtKey.getMod() & EvtInput::kModCtrl )
233         {
234             val.i_int |= KEY_MODIFIER_CTRL;
235         }
236         if( rEvtKey.getMod() & EvtInput::kModShift )
237         {
238             val.i_int |= KEY_MODIFIER_SHIFT;
239         }
240
241         var_Set( getIntf()->p_vlc, "key-pressed", val );
242     }
243
244     // Always store the modifier, which can be needed for scroll events
245     m_currModifier = rEvtKey.getMod();
246 }
247
248
249 void TopWindow::processEvent( EvtScroll &rEvtScroll )
250 {
251     // Raise the windows
252     raise();
253
254     // Get the control hit by the mouse
255     CtrlGeneric *pNewHitControl = findHitControl( rEvtScroll.getXPos(),
256                                                   rEvtScroll.getYPos());
257     setLastHit( pNewHitControl );
258
259     // Send a mouse event to the hit control, or to the control
260     // that captured the mouse, if any
261     CtrlGeneric *pActiveControl = pNewHitControl;
262
263     if( m_pCapturingControl )
264     {
265         pActiveControl = m_pCapturingControl;
266     }
267     if( pActiveControl )
268     {
269         pActiveControl->handleEvent( rEvtScroll );
270     }
271     else
272     {
273         // Treat the scroll event as a hotkey
274         vlc_value_t val;
275         if( rEvtScroll.getDirection() == EvtScroll::kUp )
276         {
277             val.i_int = KEY_MOUSEWHEELUP;
278         }
279         else
280         {
281             val.i_int = KEY_MOUSEWHEELDOWN;
282         }
283         // Add the modifiers
284         val.i_int |= m_currModifier;
285
286         var_Set( getIntf()->p_vlc, "key-pressed", val );
287     }
288 }
289
290
291 void TopWindow::forwardEvent( EvtGeneric &rEvt, CtrlGeneric &rCtrl )
292 {
293     // XXX: We should do some checks here
294     rCtrl.handleEvent( rEvt );
295 }
296
297
298 void TopWindow::refresh( int left, int top, int width, int height )
299 {
300     if( m_pActiveLayout )
301     {
302         m_pActiveLayout->getImage()->copyToWindow( *getOSWindow(), left, top,
303                                                    width, height, left, top );
304     }
305 }
306
307
308 void TopWindow::setActiveLayout( GenericLayout *pLayout )
309 {
310     pLayout->setWindow( this );
311     m_pActiveLayout = pLayout;
312     // Get the size of the layout and resize the window
313     resize( pLayout->getWidth(), pLayout->getHeight() );
314     updateShape();
315     pLayout->refreshAll();
316 }
317
318
319 const GenericLayout& TopWindow::getActiveLayout() const
320 {
321     return *m_pActiveLayout;
322 }
323
324
325 void TopWindow::innerShow()
326 {
327     // First, refresh the layout and update the shape of the window
328     if( m_pActiveLayout )
329     {
330         updateShape();
331         m_pActiveLayout->refreshAll();
332     }
333     // Show the window
334     GenericWindow::innerShow();
335 }
336
337  
338 void TopWindow::updateShape()
339 {
340     // Set the shape of the window
341     if( m_pActiveLayout )
342     {
343         OSGraphics *pImage = m_pActiveLayout->getImage();
344         if( pImage )
345         {
346             pImage->applyMaskToWindow( *getOSWindow() );
347         }
348     }
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