]> git.sesse.net Git - vlc/blob - modules/gui/skins2/src/generic_layout.cpp
710adbc57a4b082da919c9fde70c1310bfc68ec8
[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 "../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     // Check boundaries
148     if( width < m_minWidth )
149     {
150         width = m_minWidth;
151     }
152     if( width > m_maxWidth )
153     {
154         width = m_maxWidth;
155     }
156     if( height < m_minHeight )
157     {
158         height = m_minHeight;
159     }
160     if( height > m_maxHeight )
161     {
162         height = m_maxHeight;
163     }
164
165     if( width == m_width && height == m_height )
166     {
167         return;
168     }
169
170     // Update the window size
171     m_width = width;
172     m_height = height;
173
174     // Recreate a new image
175     if( m_pImage )
176     {
177         delete m_pImage;
178         OSFactory *pOsFactory = OSFactory::instance( getIntf() );
179         m_pImage = pOsFactory->createOSGraphics( width, height );
180     }
181
182     // Notify all the controls that the size has changed and redraw them
183     list<LayeredControl>::const_iterator iter;
184     for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
185     {
186         iter->m_pControl->onResize();
187         const Position *pPos = iter->m_pControl->getPosition();
188         if( pPos && iter->m_pControl->isVisible() )
189         {
190             iter->m_pControl->draw( *m_pImage, pPos->getLeft(),
191                                     pPos->getTop() );
192         }
193     }
194
195     // Resize and refresh the associated window
196     TopWindow *pWindow = getWindow();
197     if( pWindow )
198     {
199         // Resize the window
200         pWindow->refresh( 0, 0, width, height );
201         pWindow->resize( width, height );
202         pWindow->refresh( 0, 0, width, height );
203
204         // Change the shape of the window and redraw it
205         pWindow->updateShape();
206         pWindow->refresh( 0, 0, width, height );
207     }
208 }
209
210
211 void GenericLayout::refreshAll()
212 {
213     refreshRect( 0, 0, m_width, m_height );
214 }
215
216
217 void GenericLayout::refreshRect( int x, int y, int width, int height )
218 {
219     // Draw all the controls of the layout
220     list<LayeredControl>::const_iterator iter;
221     list<LayeredControl>::const_iterator iterVideo = m_controlList.end();
222     for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
223     {
224         CtrlGeneric *pCtrl = (*iter).m_pControl;
225         const Position *pPos = pCtrl->getPosition();
226         if( pPos && pCtrl->isVisible() )
227         {
228             pCtrl->draw( *m_pImage, pPos->getLeft(), pPos->getTop() );
229             // Remember the video control (we assume there is at most one video
230             // control per layout)
231             if( pCtrl->getType() == "video" && pCtrl->getPosition() )
232                 iterVideo = iter;
233         }
234     }
235
236     // Refresh the associated window
237     TopWindow *pWindow = getWindow();
238     if( pWindow )
239     {
240         // Check boundaries
241         if( x < 0 )
242             x = 0;
243         if( y < 0)
244             y = 0;
245         if( x + width > m_width )
246             width = m_width - x;
247         if( y + height > m_height )
248             height = m_height - y;
249
250         // Refresh the window... but do not paint on a video control!
251         if( iterVideo == m_controlList.end() )
252         {
253             // No video control, we can safely repaint the rectangle
254             pWindow->refresh( x, y, width, height );
255         }
256         else
257         {
258             // Bad luck, there is a video control somewhere (not necessarily
259             // in the repainting zone, btw).
260             // We will divide the repainting into 4 regions (top, left, bottom
261             // and right). The overlapping parts (i.e. the corners) of these
262             // regions will be painted twice, because otherwise the algorithm
263             // becomes a real mess :)
264
265             // Use short variable names for convenience
266             int xx = iterVideo->m_pControl->getPosition()->getLeft();
267             int yy = iterVideo->m_pControl->getPosition()->getTop();
268             int ww = iterVideo->m_pControl->getPosition()->getWidth();
269             int hh = iterVideo->m_pControl->getPosition()->getHeight();
270
271             // Top part:
272             if( y < yy )
273                 pWindow->refresh( x, y, width, yy - y );
274             // Left part:
275             if( x < xx )
276                 pWindow->refresh( x, y, xx - x, height );
277             // Bottom part
278             if( y + height > yy + hh )
279                 pWindow->refresh( x, yy + hh, width, y + height - (yy + hh) );
280             // Right part
281             if( x + width > xx + ww )
282                 pWindow->refresh( xx + ww, y, x + width - (xx + ww), height );
283         }
284     }
285 }
286
287
288 const list<Anchor*>& GenericLayout::getAnchorList() const
289 {
290     return m_anchorList;
291 }
292
293
294 void GenericLayout::addAnchor( Anchor *pAnchor )
295 {
296     m_anchorList.push_back( pAnchor );
297 }
298