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