]> git.sesse.net Git - vlc/blob - modules/gui/skins2/src/generic_layout.cpp
skins2: improve refresh of layouts
[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 #include <set>
35
36
37 GenericLayout::GenericLayout( intf_thread_t *pIntf, int width, int height,
38                               int minWidth, int maxWidth, int minHeight,
39                               int maxHeight ):
40     SkinObject( pIntf ), m_pWindow( NULL ), m_rect( 0, 0, width, height ),
41     m_minWidth( minWidth ), m_maxWidth( maxWidth ),
42     m_minHeight( minHeight ), m_maxHeight( maxHeight ), m_pVideoCtrlSet(),
43     m_visible( false ), m_pVarActive( NULL )
44 {
45     // Get the OSFactory
46     OSFactory *pOsFactory = OSFactory::instance( getIntf() );
47     // Create the graphics buffer
48     m_pImage = pOsFactory->createOSGraphics( width, height );
49
50     // Create the "active layout" variable and register it in the manager
51     m_pVarActive = new VarBoolImpl( pIntf );
52     VarManager::instance( pIntf )->registerVar( VariablePtr( m_pVarActive ) );
53 }
54
55
56 GenericLayout::~GenericLayout()
57 {
58     delete m_pImage;
59
60     list<Anchor*>::const_iterator it;
61     for( it = m_anchorList.begin(); it != m_anchorList.end(); it++ )
62     {
63         delete *it;
64     }
65
66     list<LayeredControl>::const_iterator iter;
67     for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
68     {
69         CtrlGeneric *pCtrl = (*iter).m_pControl;
70         pCtrl->unsetLayout();
71     }
72
73 }
74
75
76 void GenericLayout::setWindow( TopWindow *pWindow )
77 {
78     m_pWindow = pWindow;
79 }
80
81
82 void GenericLayout::onControlCapture( const CtrlGeneric &rCtrl )
83 {
84     // Just forward the request to the window
85     TopWindow *pWindow = getWindow();
86     if( pWindow )
87     {
88         pWindow->onControlCapture( rCtrl );
89     }
90 }
91
92
93 void GenericLayout::onControlRelease( const CtrlGeneric &rCtrl )
94 {
95     // Just forward the request to the window
96     TopWindow *pWindow = getWindow();
97     if( pWindow )
98     {
99         pWindow->onControlRelease( rCtrl );
100     }
101 }
102
103
104 void GenericLayout::addControl( CtrlGeneric *pControl,
105                                 const Position &rPosition, int layer )
106 {
107     if( pControl )
108     {
109         // Associate this layout to the control
110         pControl->setLayout( this, rPosition );
111
112         // Add the control in the list.
113         // This list must remain sorted by layer order
114         list<LayeredControl>::iterator it;
115         for( it = m_controlList.begin(); it != m_controlList.end(); it++ )
116         {
117             if( layer < (*it).m_layer )
118             {
119                 m_controlList.insert( it, LayeredControl( pControl, layer ) );
120                 break;
121             }
122         }
123         // If this control is in front of all the previous ones
124         if( it == m_controlList.end() )
125         {
126             m_controlList.push_back( LayeredControl( pControl, layer ) );
127         }
128
129         // Check if it is a video control
130         if( pControl->getType() == "video" )
131         {
132             m_pVideoCtrlSet.insert( (CtrlVideo*)pControl );
133         }
134     }
135     else
136     {
137         msg_Dbg( getIntf(), "adding NULL control in the layout" );
138     }
139 }
140
141
142 const list<LayeredControl> &GenericLayout::getControlList() const
143 {
144     return m_controlList;
145 }
146
147
148 void GenericLayout::onControlUpdate( const CtrlGeneric &rCtrl,
149                                      int width, int height,
150                                      int xOffSet, int yOffSet )
151 {
152     // Do nothing if the layout or control is hidden
153     if( !m_visible )
154         return;
155
156     const Position *pPos = rCtrl.getPosition();
157     if( width > 0 && height > 0 )
158     {
159         // make sure region is within the layout
160         rect region( pPos->getLeft() + xOffSet,
161                      pPos->getTop() + yOffSet,
162                      width, height );
163         rect layout( 0, 0, m_rect.getWidth(), m_rect.getHeight() );
164         rect inter;
165         if( rect::intersect( layout, region, &inter ) )
166         {
167             refreshRect( inter.x, inter.y, inter.width, inter.height );
168         }
169     }
170 }
171
172
173 void GenericLayout::resize( int width, int height )
174 {
175     // Update the window size
176     m_rect = SkinsRect( 0, 0 , width, height );
177
178     // Recreate a new image
179     if( m_pImage )
180     {
181         delete m_pImage;
182         OSFactory *pOsFactory = OSFactory::instance( getIntf() );
183         m_pImage = pOsFactory->createOSGraphics( width, height );
184     }
185
186     // Notify all the controls that the size has changed and redraw them
187     list<LayeredControl>::const_iterator iter;
188     for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
189     {
190         iter->m_pControl->onResize();
191     }
192
193     // Resize and refresh the associated window
194     TopWindow *pWindow = getWindow();
195     if( pWindow )
196     {
197         // Resize the window
198         pWindow->resize( width, height );
199         // Change the shape of the window and redraw it
200         refreshAll();
201     }
202 }
203
204
205 void GenericLayout::refreshAll()
206 {
207     refreshRect( 0, 0, m_rect.getWidth(), m_rect.getHeight() );
208 }
209
210
211 void GenericLayout::refreshRect( int x, int y, int width, int height )
212 {
213     // Do nothing if the layout is hidden
214     if( !m_visible )
215         return;
216
217     // update the transparency global mask
218     m_pImage->clear( x, y, width, height );
219
220     // Draw all the controls of the layout
221     list<LayeredControl>::const_iterator iter;
222     list<LayeredControl>::const_iterator iterVideo = m_controlList.end();
223     for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
224     {
225         CtrlGeneric *pCtrl = (*iter).m_pControl;
226         if( pCtrl->isVisible() )
227         {
228             pCtrl->draw( *m_pImage, x, y, width, height );
229         }
230     }
231
232     // Refresh the associated window
233     TopWindow *pWindow = getWindow();
234     if( pWindow )
235     {
236         // first apply new shape to the window
237         pWindow->updateShape();
238
239         pWindow->refresh( x, y, width, height );
240     }
241 }
242
243
244 const list<Anchor*>& GenericLayout::getAnchorList() const
245 {
246     return m_anchorList;
247 }
248
249
250 void GenericLayout::addAnchor( Anchor *pAnchor )
251 {
252     m_anchorList.push_back( pAnchor );
253 }
254
255
256 void GenericLayout::onShow()
257 {
258     m_visible = true;
259
260     refreshAll();
261 }
262
263
264 void GenericLayout::onHide()
265 {
266     m_visible = false;
267 }
268