* $Id$
*
* Authors: Cyril Deguet <asmax@via.ecp.fr>
- * Olivier Teulière <ipkiss@via.ecp.fr>
+ * Olivier Teulière <ipkiss@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include "generic_layout.hpp"
#include "top_window.hpp"
#include "os_factory.hpp"
#include "os_graphics.hpp"
+#include "var_manager.hpp"
+#include "anchor.hpp"
#include "../controls/ctrl_generic.hpp"
+#include "../controls/ctrl_video.hpp"
+#include "../utils/var_bool.hpp"
+#include <set>
GenericLayout::GenericLayout( intf_thread_t *pIntf, int width, int height,
int minWidth, int maxWidth, int minHeight,
int maxHeight ):
- SkinObject( pIntf ), m_pWindow( NULL ), m_width( width ),
- m_height( height ), m_minWidth( minWidth ), m_maxWidth( maxWidth ),
- m_minHeight( minHeight ), m_maxHeight( maxHeight )
+ SkinObject( pIntf ), m_pWindow( NULL ), m_rect( 0, 0, width, height ),
+ m_minWidth( minWidth ), m_maxWidth( maxWidth ),
+ m_minHeight( minHeight ), m_maxHeight( maxHeight ), m_pVideoCtrlSet(),
+ m_visible( false ), m_pVarActive( NULL )
{
// Get the OSFactory
OSFactory *pOsFactory = OSFactory::instance( getIntf() );
// Create the graphics buffer
m_pImage = pOsFactory->createOSGraphics( width, height );
+
+ // Create the "active layout" variable and register it in the manager
+ m_pVarActive = new VarBoolImpl( pIntf );
+ VarManager::instance( pIntf )->registerVar( VariablePtr( m_pVarActive ) );
}
GenericLayout::~GenericLayout()
{
- if( m_pImage )
+ delete m_pImage;
+ list<Anchor*>::const_iterator it;
+ for( it = m_anchorList.begin(); it != m_anchorList.end(); it++ )
{
- delete m_pImage;
+ delete *it;
}
}
void GenericLayout::addControl( CtrlGeneric *pControl,
- const Position &rPosition, int layer )
+ const Position &rPosition, int layer )
{
if( pControl )
{
pControl->setLayout( this, rPosition );
// Draw the control
- pControl->draw( *m_pImage, rPosition.getLeft(), rPosition.getTop() );
+ if( pControl->isVisible() )
+ pControl->draw( *m_pImage, rPosition.getLeft(), rPosition.getTop() );
// Add the control in the list.
- // This list must remain sorted by layer order
+ // This list must remain sorted by layer order
list<LayeredControl>::iterator it;
for( it = m_controlList.begin(); it != m_controlList.end(); it++ )
{
{
m_controlList.push_back( LayeredControl( pControl, layer ) );
}
+
+ // Check if it is a video control
+ if( pControl->getType() == "video" )
+ {
+ m_pVideoCtrlSet.insert( (CtrlVideo*)pControl );
+ }
}
else
{
- msg_Dbg( getIntf(), "Adding NULL control in the layout" );
+ msg_Dbg( getIntf(), "adding NULL control in the layout" );
}
}
void GenericLayout::resize( int width, int height )
{
- if( width == m_width && height == m_height )
- {
- return;
- }
-
// Update the window size
- m_width = width;
- m_height = height;
+ m_rect = SkinsRect( 0, 0 , width, height );
// Recreate a new image
if( m_pImage )
list<LayeredControl>::const_iterator iter;
for( iter = m_controlList.begin(); iter != m_controlList.end(); iter++ )
{
- (*iter).m_pControl->onResize();
- const Position *pPos = (*iter).m_pControl->getPosition();
- if( pPos )
- {
- (*iter).m_pControl->draw( *m_pImage, pPos->getLeft(),
- pPos->getTop() );
- }
+ iter->m_pControl->onResize();
}
// Resize and refresh the associated window
if( pWindow )
{
// Resize the window
- pWindow->refresh( 0, 0, width, height );
pWindow->resize( width, height );
- pWindow->refresh( 0, 0, width, height );
-
// Change the shape of the window and redraw it
- pWindow->updateShape();
- pWindow->refresh( 0, 0, width, height );
+ refreshAll();
}
}
void GenericLayout::refreshAll()
{
- refreshRect( 0, 0, m_width, m_height );
+ refreshRect( 0, 0, m_rect.getWidth(), m_rect.getHeight() );
}
void GenericLayout::refreshRect( int x, int y, int width, int height )
{
+ // Do nothing if the layout is hidden
+ if( !m_visible )
+ return;
+
+ // update the transparency global mask
+ m_pImage->clear( x, y, width, height );
+
// Draw all the controls of the layout
list<LayeredControl>::const_iterator iter;
list<LayeredControl>::const_iterator iterVideo = m_controlList.end();
{
CtrlGeneric *pCtrl = (*iter).m_pControl;
const Position *pPos = pCtrl->getPosition();
- if( pCtrl->isVisible() && pPos )
+ if( pPos && pCtrl->isVisible() )
{
pCtrl->draw( *m_pImage, pPos->getLeft(), pPos->getTop() );
- // Remember the video control (we assume there is at most one video
- // control per layout)
- if( pCtrl->getType() == "video" && pCtrl->getPosition() )
- iterVideo = iter;
}
}
TopWindow *pWindow = getWindow();
if( pWindow )
{
+ // first apply new shape to the window
+ pWindow->updateShape();
+
// Check boundaries
if( x < 0 )
x = 0;
if( y < 0)
y = 0;
- if( x + width > m_width )
- width = m_width - x;
- if( y + height > m_height )
- height = m_height - y;
+ if( x + width > m_rect.getWidth() )
+ width = m_rect.getWidth() - x;
+ if( y + height > m_rect.getHeight() )
+ height = m_rect.getHeight() - y;
+
+ computeRefresh( x, y, width, height );
+ }
+}
+
+class rect
+{
+public:
+ rect( int v_x = 0, int v_y = 0, int v_width = 0, int v_height = 0 )
+ : x( v_x ), y( v_y ), width( v_width ), height( v_height ) { }
+ ~rect() { }
+ int x;
+ int y;
+ int width;
+ int height;
+
+ static bool isIncluded( rect& rect2, rect& rect1 )
+ {
+ int x1 = rect1.x;
+ int y1 = rect1.y;
+ int w1 = rect1.width;
+ int h1 = rect1.height;
+
+ int x2 = rect2.x;
+ int y2 = rect2.y;
+ int w2 = rect2.width;
+ int h2 = rect2.height;
+
+ return x2 >= x1 && x2 < x1 + w1
+ && y2 >= y1 && y2 < y1 + h1
+ && w2 <= w1
+ && h2 <= h1;
+ }
+};
+
+void GenericLayout::computeRefresh( int x, int y, int width, int height )
+{
+ TopWindow *pWindow = getWindow();
+
+#ifndef WIN32
- // Refresh the window... but do not paint on a video control!
- if( iterVideo == m_controlList.end() )
+ pWindow->refresh( x, y, width, height );
+
+#else
+
+ if( !m_pVideoCtrlSet.size() )
+ {
+ // No video control, we can safely repaint the rectangle
+ pWindow->refresh( x, y, width, height );
+ return;
+ }
+
+ int w = width;
+ int h = height;
+
+ set<int> x_set;
+ set<int> y_set;
+ vector<rect> rect_set;
+
+ x_set.insert( x + w );
+ y_set.insert( y + h );
+
+ // retrieve video controls being used
+ // and remember their rectangles
+ set<CtrlVideo*>::const_iterator it;
+ for( it = m_pVideoCtrlSet.begin(); it != m_pVideoCtrlSet.end(); it++ )
+ {
+ if( (*it)->isUsed() )
{
- // No video control, we can safely repain the rectangle
- pWindow->refresh( x, y, width, height );
+ int xx = (*it)->getPosition()->getLeft();
+ int yy = (*it)->getPosition()->getTop();
+ int ww = (*it)->getPosition()->getWidth();
+ int hh = (*it)->getPosition()->getHeight();
+
+ rect r(xx, yy, ww, hh );
+ rect_set.push_back( r );
+
+ if( xx > x && xx < x + w )
+ x_set.insert( xx );
+ if( xx + ww > x && xx + ww < x + w )
+ x_set.insert( xx + ww );
+ if( yy > y && yy < y + h )
+ y_set.insert( yy );
+ if( yy + hh > y && yy + hh < y + h )
+ y_set.insert( yy + hh );
}
- else
+ }
+
+ // for each subregion, test whether they are part
+ // of the video control(s) or not
+ set<int>::const_iterator it_x;
+ set<int>::const_iterator it_y;
+ int x_prev, y_prev;
+
+ for( x_prev = x, it_x = x_set.begin();
+ it_x != x_set.end(); x_prev = *it_x, it_x++ )
+ {
+ int x0 = x_prev;
+ int w0 = *it_x - x_prev;
+
+ for( y_prev = y, it_y = y_set.begin();
+ it_y != y_set.end(); y_prev = *it_y, it_y++ )
{
- // Bad luck, there is a video control somewhere (not necessarily
- // in the repainting zone, btw).
- // We will divide the repainting into 4 regions (top, left, bottom
- // and right). The overlapping parts (i.e. the corners) of these
- // regions will be painted twice, because otherwise the algorithm
- // becomes a real mess :)
-
- // Use short variable names for convenience
- int xx = iterVideo->m_pControl->getPosition()->getLeft();
- int yy = iterVideo->m_pControl->getPosition()->getTop();
- int ww = iterVideo->m_pControl->getPosition()->getWidth();
- int hh = iterVideo->m_pControl->getPosition()->getHeight();
-
- // Top part:
- if( y < yy )
- pWindow->refresh( x, y, width, yy - y );
- // Left part:
- if( x < xx )
- pWindow->refresh( x, y, xx - x, height );
- // Bottom part
- if( y + height > yy + hh )
- pWindow->refresh( x, yy + hh, width, y + height - (yy + hh) );
- // Right part
- if( x + width > xx + ww )
- pWindow->refresh( xx + ww, y, x + width - (xx + ww), height );
+ int y0 = y_prev;
+ int h0 = *it_y - y_prev;
+
+ rect r( x0, y0, w0, h0 );
+ bool b_refresh = true;
+
+ vector<rect>::iterator it;
+ for( it = rect_set.begin(); it != rect_set.end(); it++ )
+ {
+ rect r_ctrl = *it;
+ if( rect::isIncluded( r, r_ctrl ) )
+ {
+ b_refresh = false;
+ break;
+ }
+ }
+
+ // subregion is not part of a video control
+ // needs to be refreshed
+ if( b_refresh )
+ pWindow->refresh( x0, y0, w0 ,h0 );
}
}
+
+#endif
+
}
m_anchorList.push_back( pAnchor );
}
+
+void GenericLayout::onShow()
+{
+ m_visible = true;
+
+ refreshAll();
+}
+
+
+void GenericLayout::onHide()
+{
+ m_visible = false;
+}
+