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