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