]> git.sesse.net Git - vlc/blob - modules/gui/skins2/src/generic_layout.cpp
Introduce setLayoutMargins for layout margins difference between Qt4.2 and Qt4.3
[vlc] / modules / gui / skins2 / src / generic_layout.cpp
1 /*****************************************************************************
2  * generic_layout.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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #include "generic_layout.hpp"
26 #include "top_window.hpp"
27 #include "os_factory.hpp"
28 #include "os_graphics.hpp"
29 #include "var_manager.hpp"
30 #include "anchor.hpp"
31 #include "../controls/ctrl_generic.hpp"
32 #include "../controls/ctrl_video.hpp"
33 #include "../utils/var_bool.hpp"
34
35
36 GenericLayout::GenericLayout( intf_thread_t *pIntf, int width, int height,
37                               int minWidth, int maxWidth, int minHeight,
38                               int maxHeight ):
39     SkinObject( pIntf ), m_pWindow( NULL ), m_rect( 0, 0, width, height ),
40     m_minWidth( minWidth ), m_maxWidth( maxWidth ),
41     m_minHeight( minHeight ), m_maxHeight( maxHeight ), m_pVideoControl( NULL ),
42     m_visible( false ), m_pVarActive( NULL )
43 {
44     // Get the OSFactory
45     OSFactory *pOsFactory = OSFactory::instance( getIntf() );
46     // Create the graphics buffer
47     m_pImage = pOsFactory->createOSGraphics( width, height );
48
49     // Create the "active layout" variable and register it in the manager
50     m_pVarActive = new VarBoolImpl( pIntf );
51     VarManager::instance( pIntf )->registerVar( VariablePtr( m_pVarActive ) );
52 }
53
54
55 GenericLayout::~GenericLayout()
56 {
57     if( m_pImage )
58     {
59         delete m_pImage;
60     }
61     list<Anchor*>::const_iterator it;
62     for( it = m_anchorList.begin(); it != m_anchorList.end(); it++ )
63     {
64         delete *it;
65     }
66 }
67
68
69 void GenericLayout::setWindow( TopWindow *pWindow )
70 {
71     m_pWindow = pWindow;
72 }
73
74
75 void GenericLayout::onControlCapture( const CtrlGeneric &rCtrl )
76 {
77     // Just forward the request to the window
78     TopWindow *pWindow = getWindow();
79     if( pWindow )
80     {
81         pWindow->onControlCapture( rCtrl );
82     }
83 }
84
85
86 void GenericLayout::onControlRelease( const CtrlGeneric &rCtrl )
87 {
88     // Just forward the request to the window
89     TopWindow *pWindow = getWindow();
90     if( pWindow )
91     {
92         pWindow->onControlRelease( rCtrl );
93     }
94 }
95
96
97 void GenericLayout::addControl( CtrlGeneric *pControl,
98                                 const Position &rPosition, int layer )
99 {
100     if( pControl )
101     {
102         // Associate this layout to the control
103         pControl->setLayout( this, rPosition );
104
105         // Draw the control
106         pControl->draw( *m_pImage, rPosition.getLeft(), rPosition.getTop() );
107
108         // Add the control in the list.
109         // This list must remain sorted by layer order
110         list<LayeredControl>::iterator it;
111         for( it = m_controlList.begin(); it != m_controlList.end(); it++ )
112         {
113             if( layer < (*it).m_layer )
114             {
115                 m_controlList.insert( it, LayeredControl( pControl, layer ) );
116                 break;
117             }
118         }
119         // If this control is in front of all the previous ones
120         if( it == m_controlList.end() )
121         {
122             m_controlList.push_back( LayeredControl( pControl, layer ) );
123         }
124
125         // Check if it is a video control
126         if( pControl->getType() == "video" )
127         {
128             m_pVideoControl = (CtrlVideo*)pControl;
129         }
130     }
131     else
132     {
133         msg_Dbg( getIntf(), "adding NULL control in the layout" );
134     }
135 }
136
137
138 const list<LayeredControl> &GenericLayout::getControlList() const
139 {
140     return m_controlList;
141 }
142
143
144 void GenericLayout::onControlUpdate( const CtrlGeneric &rCtrl,
145                                      int width, int height,
146                                      int xOffSet, int yOffSet )
147 {
148     // The size is not valid, refresh the whole layout
149     if( width <= 0 || height <= 0 )
150     {
151         refreshAll();
152         return;
153     }
154
155     const Position *pPos = rCtrl.getPosition();
156     if( pPos )
157     {
158         refreshRect( pPos->getLeft() + xOffSet,
159                      pPos->getTop() + yOffSet,
160                      width, height );
161     }
162 }
163
164
165 void GenericLayout::resize( int width, int height )
166 {
167     // Update the window size
168     m_rect = SkinsRect( 0, 0 , width, height );
169
170     // Recreate a new image
171     if( m_pImage )
172     {
173         delete m_pImage;
174         OSFactory *pOsFactory = OSFactory::instance( getIntf() );
175         m_pImage = pOsFactory->createOSGraphics( width, height );
176     }
177
178     // Notify all the controls that the size has changed and redraw them
179     list<LayeredControl>::const_iterator iter;
180     for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
181     {
182         iter->m_pControl->onResize();
183     }
184
185     // Resize and refresh the associated window
186     TopWindow *pWindow = getWindow();
187     if( pWindow )
188     {
189         // Resize the window
190         pWindow->resize( width, height );
191         refreshAll();
192         // Change the shape of the window and redraw it
193         pWindow->updateShape();
194         refreshAll();
195     }
196 }
197
198
199 void GenericLayout::refreshAll()
200 {
201     refreshRect( 0, 0, m_rect.getWidth(), m_rect.getHeight() );
202 }
203
204
205 void GenericLayout::refreshRect( int x, int y, int width, int height )
206 {
207     // Do nothing if the layout is hidden
208     if( !m_visible )
209         return;
210
211     // Draw all the controls of the layout
212     list<LayeredControl>::const_iterator iter;
213     list<LayeredControl>::const_iterator iterVideo = m_controlList.end();
214     for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
215     {
216         CtrlGeneric *pCtrl = (*iter).m_pControl;
217         const Position *pPos = pCtrl->getPosition();
218         if( pPos && pCtrl->isVisible() )
219         {
220             pCtrl->draw( *m_pImage, pPos->getLeft(), pPos->getTop() );
221         }
222     }
223
224     // Refresh the associated window
225     TopWindow *pWindow = getWindow();
226     if( pWindow )
227     {
228         // Check boundaries
229         if( x < 0 )
230             x = 0;
231         if( y < 0)
232             y = 0;
233         if( x + width > m_rect.getWidth() )
234             width = m_rect.getWidth() - x;
235         if( y + height > m_rect.getHeight() )
236             height = m_rect.getHeight() - y;
237
238         // Refresh the window... but do not paint on a visible video control!
239         if( !m_pVideoControl || !m_pVideoControl->isVisible() )
240         {
241             // No video control, we can safely repaint the rectangle
242             pWindow->refresh( x, y, width, height );
243         }
244         else
245         {
246             // Bad luck, there is a video control somewhere (not necessarily
247             // in the repainting zone, btw).
248             // We will divide the repainting into 4 regions (top, left, bottom
249             // and right). The overlapping parts (i.e. the corners) of these
250             // regions will be painted twice, because otherwise the algorithm
251             // becomes a real mess :)
252
253             // Use short variable names for convenience
254             int xx = m_pVideoControl->getPosition()->getLeft();
255             int yy = m_pVideoControl->getPosition()->getTop();
256             int ww = m_pVideoControl->getPosition()->getWidth();
257             int hh = m_pVideoControl->getPosition()->getHeight();
258
259             // Top part:
260             if( y < yy )
261                 pWindow->refresh( x, y, width, yy - y );
262             // Left part:
263             if( x < xx )
264                 pWindow->refresh( x, y, xx - x, height );
265             // Bottom part
266             if( y + height > yy + hh )
267                 pWindow->refresh( x, yy + hh, width, y + height - (yy + hh) );
268             // Right part
269             if( x + width > xx + ww )
270                 pWindow->refresh( xx + ww, y, x + width - (xx + ww), height );
271         }
272     }
273 }
274
275
276 const list<Anchor*>& GenericLayout::getAnchorList() const
277 {
278     return m_anchorList;
279 }
280
281
282 void GenericLayout::addAnchor( Anchor *pAnchor )
283 {
284     m_anchorList.push_back( pAnchor );
285 }
286
287
288 void GenericLayout::onShow()
289 {
290     m_visible = true;
291
292     refreshAll();
293     // TODO find a better way to handle the vout ?
294     if( m_pVideoControl )
295     {
296         m_pVideoControl->setVisible( true );
297     }
298 }
299
300
301 void GenericLayout::onHide()
302 {
303     m_visible = false;
304
305     // TODO find a better way to handle the vout ?
306     if( m_pVideoControl )
307     {
308         m_pVideoControl->setVisible( false );
309     }
310 }
311