1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 the VideoLAN team
7 * Authors: Cyril Deguet <asmax@via.ecp.fr>
8 * Olivier Teulière <ipkiss@via.ecp.fr>
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.
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.
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 *****************************************************************************/
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"
31 #include "../controls/ctrl_generic.hpp"
32 #include "../controls/ctrl_video.hpp"
33 #include "../utils/var_bool.hpp"
37 GenericLayout::GenericLayout( intf_thread_t *pIntf, int width, int height,
38 int minWidth, int maxWidth, int minHeight,
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 )
46 OSFactory *pOsFactory = OSFactory::instance( getIntf() );
47 // Create the graphics buffer
48 m_pImage = pOsFactory->createOSGraphics( width, height );
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 ) );
56 GenericLayout::~GenericLayout()
59 list<Anchor*>::const_iterator it;
60 for( it = m_anchorList.begin(); it != m_anchorList.end(); it++ )
67 void GenericLayout::setWindow( TopWindow *pWindow )
73 void GenericLayout::onControlCapture( const CtrlGeneric &rCtrl )
75 // Just forward the request to the window
76 TopWindow *pWindow = getWindow();
79 pWindow->onControlCapture( rCtrl );
84 void GenericLayout::onControlRelease( const CtrlGeneric &rCtrl )
86 // Just forward the request to the window
87 TopWindow *pWindow = getWindow();
90 pWindow->onControlRelease( rCtrl );
95 void GenericLayout::addControl( CtrlGeneric *pControl,
96 const Position &rPosition, int layer )
100 // Associate this layout to the control
101 pControl->setLayout( this, rPosition );
104 pControl->draw( *m_pImage, rPosition.getLeft(), rPosition.getTop() );
106 // Add the control in the list.
107 // This list must remain sorted by layer order
108 list<LayeredControl>::iterator it;
109 for( it = m_controlList.begin(); it != m_controlList.end(); it++ )
111 if( layer < (*it).m_layer )
113 m_controlList.insert( it, LayeredControl( pControl, layer ) );
117 // If this control is in front of all the previous ones
118 if( it == m_controlList.end() )
120 m_controlList.push_back( LayeredControl( pControl, layer ) );
123 // Check if it is a video control
124 if( pControl->getType() == "video" )
126 m_pVideoCtrlSet.insert( (CtrlVideo*)pControl );
131 msg_Dbg( getIntf(), "adding NULL control in the layout" );
136 const list<LayeredControl> &GenericLayout::getControlList() const
138 return m_controlList;
142 void GenericLayout::onControlUpdate( const CtrlGeneric &rCtrl,
143 int width, int height,
144 int xOffSet, int yOffSet )
146 // The size is not valid, refresh the whole layout
147 if( width <= 0 || height <= 0 )
153 const Position *pPos = rCtrl.getPosition();
156 refreshRect( pPos->getLeft() + xOffSet,
157 pPos->getTop() + yOffSet,
163 void GenericLayout::resize( int width, int height )
165 // Update the window size
166 m_rect = SkinsRect( 0, 0 , width, height );
168 // Recreate a new image
172 OSFactory *pOsFactory = OSFactory::instance( getIntf() );
173 m_pImage = pOsFactory->createOSGraphics( width, height );
176 // Notify all the controls that the size has changed and redraw them
177 list<LayeredControl>::const_iterator iter;
178 for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
180 iter->m_pControl->onResize();
183 // Resize and refresh the associated window
184 TopWindow *pWindow = getWindow();
188 pWindow->resize( width, height );
190 // Change the shape of the window and redraw it
191 pWindow->updateShape();
197 void GenericLayout::refreshAll()
199 refreshRect( 0, 0, m_rect.getWidth(), m_rect.getHeight() );
203 void GenericLayout::refreshRect( int x, int y, int width, int height )
205 // Do nothing if the layout is hidden
209 // Draw all the controls of the layout
210 list<LayeredControl>::const_iterator iter;
211 list<LayeredControl>::const_iterator iterVideo = m_controlList.end();
212 for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
214 CtrlGeneric *pCtrl = (*iter).m_pControl;
215 const Position *pPos = pCtrl->getPosition();
216 if( pPos && pCtrl->isVisible() )
218 pCtrl->draw( *m_pImage, pPos->getLeft(), pPos->getTop() );
222 // Refresh the associated window
223 TopWindow *pWindow = getWindow();
231 if( x + width > m_rect.getWidth() )
232 width = m_rect.getWidth() - x;
233 if( y + height > m_rect.getHeight() )
234 height = m_rect.getHeight() - y;
236 // Refresh the window... but do not paint on a visible video control!
237 if( !m_pVideoCtrlSet.size() )
239 // No video control, we can safely repaint the rectangle
240 pWindow->refresh( x, y, width, height );
244 // video control(s) present, we need more calculations
245 computeRefresh( x, y, width, height );
253 rect( int v_x = 0, int v_y = 0,
254 int v_width = 0, int v_height = 0 )
255 : x( v_x), y( v_y ), width( v_width), height( v_height)
263 static bool isIncluded( rect& rect2, rect& rect1 )
267 int w1 = rect1.width;
268 int h1 = rect1.height;
272 int w2 = rect2.width;
273 int h2 = rect2.height;
275 return x2 >= x1 && x2 < x1 + w1
276 && y2 >= y1 && y2 < y1 + h1
282 void GenericLayout::computeRefresh( int x, int y, int width, int height )
286 TopWindow *pWindow = getWindow();
290 vector<rect> rect_set;
292 x_set.insert( x + w );
293 y_set.insert( y + h );
295 // retrieve video controls being used
296 // and remember their rectangles
297 set<CtrlVideo*>::const_iterator it;
298 for( it = m_pVideoCtrlSet.begin(); it != m_pVideoCtrlSet.end(); it++ )
300 if( (*it)->isUsed() )
302 int xx = (*it)->getPosition()->getLeft();
303 int yy = (*it)->getPosition()->getTop();
304 int ww = (*it)->getPosition()->getWidth();
305 int hh = (*it)->getPosition()->getHeight();
307 rect r(xx, yy, ww, hh );
308 rect_set.push_back( r );
310 if( xx > x && xx < x + w )
312 if( xx + ww > x && xx + ww < x + w )
313 x_set.insert( xx + ww );
314 if( yy > y && yy < y + h )
316 if( yy + hh > y && yy + hh < y + h )
317 y_set.insert( yy + hh );
321 // for each subregion, test whether they are part
322 // of the video control(s) or not
323 set<int>::const_iterator it_x;
324 set<int>::const_iterator it_y;
327 for( x_prev = x, it_x = x_set.begin();
328 it_x != x_set.end(); x_prev = *it_x, it_x++ )
331 int w0 = *it_x - x_prev;
333 for( y_prev = y, it_y = y_set.begin();
334 it_y != y_set.end(); y_prev = *it_y, it_y++ )
337 int h0 = *it_y - y_prev;
339 rect r( x0, y0, w0, h0 );
340 bool b_refresh = true;
342 vector<rect>::iterator it;
343 for( it = rect_set.begin(); it != rect_set.end(); it++ )
346 if( rect::isIncluded( r, r_ctrl ) )
353 // subregion is not part of a video control
354 // needs to be refreshed
356 pWindow->refresh( x0, y0, w0 ,h0 );
362 const list<Anchor*>& GenericLayout::getAnchorList() const
368 void GenericLayout::addAnchor( Anchor *pAnchor )
370 m_anchorList.push_back( pAnchor );
374 void GenericLayout::onShow()
382 void GenericLayout::onHide()