Commit cb2ad9ec authored by Olivier Teulière's avatar Olivier Teulière

* skins2 (tree playlist):

     - Fixed a selection bug in CtrlTree
     - Simplified some algorithms using helper methods
     - A few coding style fixes
parent 4ab6e7c7
......@@ -41,6 +41,7 @@
#define SCROLL_STEP 0.05
#define LINE_INTERVAL 1 // Number of pixels inserted between 2 lines
CtrlTree::CtrlTree( intf_thread_t *pIntf,
VarTree &rTree,
const GenericFont &rFont,
......@@ -151,7 +152,7 @@ void CtrlTree::onUpdate( Subject<VarPercent> &rPercent )
#ifdef _MSC_VER
# define lrint (int)
#endif
it = m_rTree.visibleItem(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1);
it = m_rTree.getVisibleItem(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1);
}
if( m_lastPos != it )
{
......@@ -180,7 +181,7 @@ void CtrlTree::onResize()
#ifdef _MSC_VER
# define lrint (int)
#endif
it = m_rTree.visibleItem(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1);
it = m_rTree.getVisibleItem(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1);
}
// Redraw the control if the position has changed
m_lastPos = it;
......@@ -206,7 +207,7 @@ void CtrlTree::onResize()
// We cannot keep the current first item
m_lastPos = excessItems;
}*/
it = m_rTree.visibleItem( excessItems );
it = m_rTree.getVisibleItem( excessItems );
}
makeImage();
notifyLayout();
......@@ -219,20 +220,6 @@ void CtrlTree::onPositionChange()
notifyLayout();
}
#define IT_DISP_LOOP_END( a ) \
if( a ->m_expanded && a ->size() ) \
{ \
a = a ->begin(); \
} \
else \
{ \
VarTree::Iterator it_old = a; \
a ++; \
if( it_old->parent() && it_old->parent()->end() == a ) \
{ \
a = it_old->uncle(); \
} \
}
void CtrlTree::handleEvent( EvtGeneric &rEvent )
{
if( rEvent.getAsString().find( "key:down" ) != string::npos )
......@@ -240,13 +227,13 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
int key = ((EvtKey&)rEvent).getKey();
VarTree::Iterator it;
bool previousWasSelected = false;
for( it = m_rTree.begin(); it != m_rTree.end(); )
for( it = m_rTree.begin(); it != m_rTree.end();
it = m_rTree.getNextVisibleItem( it ) )
{
VarTree::Iterator next = it;
IT_DISP_LOOP_END( next );
VarTree::Iterator next = m_rTree.getNextVisibleItem( it );
if( key == KEY_UP )
{
//Scroll up one item
// Scroll up one item
if( ( it->parent()
&& it != it->parent()->begin() )
|| &*it != m_pLastSelected )
......@@ -330,7 +317,6 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
m_rTree.action( &*it );
}
}
it = next;
}
// Redraw the control
......@@ -345,19 +331,18 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
int yPos = ( rEvtMouse.getYPos() - pos->getTop() ) / itemHeight();
int xPos = rEvtMouse.getXPos() - pos->getLeft();
VarTree::Iterator it;
int index = 0;
if( rEvent.getAsString().find( "mouse:left:down:ctrl,shift" ) !=
string::npos )
{
// Flag to know if the currend item must be selected
VarTree::Iterator itClicked = findItemAtPos( yPos );
// Flag to know if the current item must be selected
bool select = false;
index = -1;
for( it = m_rTree.begin(); it != m_rTree.end(); )
for( it = m_rTree.begin(); it != m_rTree.end();
it = m_rTree.getNextVisibleItem( it ) )
{
bool nextSelect = select;
if( it == m_lastPos ) index = 0;
if( index == yPos || &*it == m_pLastSelected )
if( it == itClicked || &*it == m_pLastSelected )
{
if( select )
{
......@@ -371,37 +356,30 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
}
it->m_selected = (*it).m_selected || select;
select = nextSelect;
if( index != -1 )
index++;
IT_DISP_LOOP_END( it );
}
}
else if( rEvent.getAsString().find( "mouse:left:down:ctrl" ) !=
string::npos )
{
for( it = m_lastPos; it != m_rTree.end(); )
{
if( index == yPos )
// Invert the selection of the item
it = findItemAtPos( yPos );
if( it != m_rTree.end() )
{
it->m_selected = !it->m_selected;
m_pLastSelected = &*it;
break;
}
index++;
IT_DISP_LOOP_END( it );
}
}
else if( rEvent.getAsString().find( "mouse:left:down:shift" ) !=
string::npos )
{
// Flag to know if the currend item must be selected
VarTree::Iterator itClicked = findItemAtPos( yPos );
// Flag to know if the current item must be selected
bool select = false;
index = -1;
for( it = m_rTree.begin(); it != m_rTree.end(); )
for( it = m_rTree.begin(); it != m_rTree.end();
it = m_rTree.getNextVisibleItem( it ) )
{
bool nextSelect = select;
if( it == m_lastPos ) index = 0;
if( index == yPos || &*it == m_pLastSelected )
if( it == itClicked || &*it == m_pLastSelected )
{
if( select )
{
......@@ -415,36 +393,31 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
}
it->m_selected = select;
select = nextSelect;
if( index != -1 )
index++;
IT_DISP_LOOP_END( it );
}
}
else if( rEvent.getAsString().find( "mouse:left:down" ) !=
string::npos )
{
for( it = m_lastPos; it != m_rTree.end(); )
// Unselect any previously selected item
for( it = m_rTree.begin(); it != m_rTree.end();
it = m_rTree.getNextVisibleItem( it ) )
{
if( index == yPos )
it->m_selected = false;
}
// Select the new item
it = findItemAtPos(yPos);
if( it != m_rTree.end() )
{
it->m_selected = true;
m_pLastSelected = &*it;
}
else
{
it->m_selected = false;
}
index ++;
IT_DISP_LOOP_END( it );
}
}
else if( rEvent.getAsString().find( "mouse:left:dblclick" ) !=
string::npos )
{
for( it = m_lastPos; it != m_rTree.end(); )
{
if( index == yPos )
it = findItemAtPos(yPos);
if( it != m_rTree.end() )
{
if( it->size() && xPos < it->depth() * itemImageWidth() )
{
......@@ -452,19 +425,10 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
}
else
{
it->m_selected = true;
m_pLastSelected = &*it;
// Execute the action associated to this item
m_rTree.action( &*it );
}
}
else
{
it->m_selected = false;
}
index ++;
IT_DISP_LOOP_END( it );
}
}
// Redraw the control
......@@ -511,22 +475,22 @@ void CtrlTree::autoScroll()
// Find the current playing stream
int playIndex = 0;
VarTree::Iterator it;
for( it = m_rTree.begin(); it != m_rTree.end(); )
for( it = m_rTree.begin(); it != m_rTree.end();
it = m_rTree.getNextVisibleItem( it ) )
{
if( it->m_playing ) break;
playIndex++;
IT_DISP_LOOP_END( it );
}
if( it == m_rTree.end() ) return;
// Find m_lastPos
int lastPosIndex = 0;
for( it = m_rTree.begin(); it != m_rTree.end(); )
for( it = m_rTree.begin(); it != m_rTree.end();
it = m_rTree.getNextVisibleItem( it ) )
{
if( it == m_lastPos ) break;
lastPosIndex++;
IT_DISP_LOOP_END( it );
}
if( it == m_rTree.end() ) return;
......@@ -579,15 +543,15 @@ void CtrlTree::makeImage()
for( int yPos = 0; yPos < height; yPos += i_itemHeight )
{
int rectHeight = __MIN( i_itemHeight, height - yPos );
if( it != m_rTree.end() )
{
if( (*it).m_selected )
{
int rectHeight = __MIN( i_itemHeight, height - yPos );
m_pImage->fillRect( 0, yPos, width, rectHeight,
m_selColor );
}
IT_DISP_LOOP_END( it );
it = m_rTree.getNextVisibleItem( it );
}
}
}
......@@ -604,7 +568,7 @@ void CtrlTree::makeImage()
{
uint32_t color = ( it->m_selected ? m_selColor : bgColor );
m_pImage->fillRect( 0, yPos, width, rectHeight, color );
IT_DISP_LOOP_END( it );
it = m_rTree.getNextVisibleItem( it );
}
else
{
......@@ -625,18 +589,27 @@ void CtrlTree::makeImage()
UString *pStr = (UString*)(it->m_cString.get());
uint32_t color = ( it->m_playing ? m_playColor : m_fgColor );
// Draw the text
if( pStr != NULL ){
if( pStr != NULL )
{
int depth = it->depth();
GenericBitmap *pText = m_rFont.drawString( *pStr, color, width - bitmapWidth * depth );
if( !pText )
{
return;
}
m_pCurBitmap = it->size() ? ( it->m_expanded ? m_pOpenBitmap : m_pClosedBitmap ) : m_pItemBitmap ;
if( it->size() )
m_pCurBitmap = it->m_expanded ? m_pOpenBitmap : m_pClosedBitmap;
else
m_pCurBitmap = m_pItemBitmap;
if( m_pCurBitmap )
{
int yPos2 = yPos+(i_itemHeight-m_pCurBitmap->getHeight()+1)/2;
m_pImage->drawBitmap( *m_pCurBitmap, 0, 0, bitmapWidth * (depth - 1 ), yPos2, m_pCurBitmap->getWidth(), __MIN( m_pCurBitmap->getHeight(), height - yPos2), true );
m_pImage->drawBitmap( *m_pCurBitmap, 0, 0,
bitmapWidth * (depth - 1 ), yPos2,
m_pCurBitmap->getWidth(),
__MIN( m_pCurBitmap->getHeight(),
height - yPos2), true );
}
else
{
......@@ -656,6 +629,21 @@ void CtrlTree::makeImage()
yPos += (pText->getHeight() - ySrc );
delete pText;
}
IT_DISP_LOOP_END( it );
it = m_rTree.getNextVisibleItem( it );
}
}
VarTree::Iterator CtrlTree::findItemAtPos( int pos )
{
// The first item is m_lastPos.
// We decrement pos as we try the other items, until pos == 0.
VarTree::Iterator it;
for( it = m_lastPos; it != m_rTree.end() && pos != 0;
it = m_rTree.getNextVisibleItem( it ) )
{
pos--;
}
return it;
}
......@@ -2,7 +2,7 @@
* ctrl_tree.hpp
*****************************************************************************
* Copyright (C) 2003 VideoLAN
* $Id: ctrl_list.hpp 11009 2005-05-14 14:39:05Z ipkiss $
* $Id$
*
* Authors: Antoine Cellerier
*
......@@ -124,6 +124,13 @@ class CtrlTree: public CtrlGeneric, public Observer<VarTree>,
/// Draw the image of the control
void makeImage();
/// Return the n'th displayed item (starting at position 0)
/**
* Return m_rTree.end() if such an item cannot be found (n < 0, or
* n too big)
*/
VarTree::Iterator findItemAtPos( int n );
};
#endif
......@@ -23,16 +23,17 @@
#include "var_tree.hpp"
const string VarTree::m_type = "tree";
VarTree::VarTree( intf_thread_t *pIntf, VarTree *m_pParent2 )
:Variable( pIntf )
VarTree::VarTree( intf_thread_t *pIntf, VarTree *pParent )
: Variable( pIntf )
{
m_selected = false;
m_playing = false;
m_expanded = true;
m_pData = NULL;
m_pParent = m_pParent2;
m_pParent = pParent;
// Create the position variable
m_cPosition = VariablePtr( new VarPercent( pIntf ) );
......@@ -44,7 +45,11 @@ VarTree::~VarTree()
// TODO : check that children are deleted
}
void VarTree::add( const UStringPtr &rcString, bool selected, bool playing, bool expanded, void *pData )
void VarTree::add( const UStringPtr &rcString,
bool selected,
bool playing,
bool expanded,
void *pData )
{
m_children.push_back( VarTree( getIntf(), this ) );
back().m_cString = rcString;
......@@ -107,7 +112,6 @@ VarTree::ConstIterator VarTree::operator[]( int n ) const
* ... which means parent++ or grandparent++ or grandgrandparent++ ... */
VarTree::Iterator VarTree::uncle()
{
// fprintf( stderr, "trying to find uncle\n");
VarTree *p_parent = parent();
if( p_parent != NULL )
{
......@@ -115,7 +119,7 @@ VarTree::Iterator VarTree::uncle()
while( p_grandparent != NULL )
{
Iterator it = p_grandparent->begin();
while( !(it == p_grandparent->end()) && &(*it) != p_parent ) it++;
while( it != p_grandparent->end() && &(*it) != p_parent ) it++;
if( it != p_grandparent->end() )
{
it++;
......@@ -138,11 +142,11 @@ VarTree::Iterator VarTree::uncle()
return root()->end();
}
void VarTree::checkParents( VarTree *m_pParent2 )
void VarTree::checkParents( VarTree *pParent )
{
m_pParent = m_pParent2;
m_pParent = pParent;
Iterator it = begin();
while( it!=end() )
while( it != end() )
{
it->checkParents( this );
it++;
......@@ -164,7 +168,7 @@ int VarTree::visibleItems()
return i_count;
}
VarTree::Iterator VarTree::visibleItem( int n )
VarTree::Iterator VarTree::getVisibleItem( int n )
{
Iterator it = begin();
while( it != end() )
......@@ -174,10 +178,30 @@ VarTree::Iterator VarTree::visibleItem( int n )
if( it->m_expanded )
{
int i = n - it->visibleItems();
if( i <= 0 ) return it->visibleItem( n );
if( i <= 0 ) return it->getVisibleItem( n );
n = i;
}
it++;
}
return end();
}
VarTree::Iterator VarTree::getNextVisibleItem( Iterator it )
{
if( it->m_expanded && it->size() )
{
it = it->begin();
}
else
{
VarTree::Iterator it_old = it;
it++;
// Was 'it' the last brother? If so, look for uncles
if( it_old->parent() && it_old->parent()->end() == it )
{
it = it_old->uncle();
}
}
return it;
}
......@@ -35,14 +35,18 @@
class VarTree: public Variable, public Subject<VarTree>
{
public:
VarTree( intf_thread_t *pIntf, VarTree *m_pParent2 );
VarTree( intf_thread_t *pIntf, VarTree *pParent );
virtual ~VarTree();
/// Get the variable type
virtual const string &getType() const { return m_type; }
/// Add a pointer on string in the children's list
virtual void add( const UStringPtr &rcString, bool selected=true, bool playing=true, bool expanded=true, void *pData=NULL );
virtual void add( const UStringPtr &rcString,
bool selected = true,
bool playing = true,
bool expanded = true,
void *pData = NULL );
/// Remove the selected item from the children's list
virtual void delSelected();
......@@ -80,15 +84,28 @@ class VarTree: public Variable, public Subject<VarTree>
/// Parent node
VarTree *parent() { return m_pParent; }
void VarTree::checkParents( VarTree *m_pParent2 );
void VarTree::checkParents( VarTree *pParent );
Iterator uncle();
/// Get root node
VarTree *root() { VarTree *parent=this; while( parent->parent() != NULL ) parent = parent->parent(); return parent; }
VarTree *root()
{
VarTree *parent = this;
while( parent->parent() != NULL )
parent = parent->parent();
return parent;
}
/// Get depth (root depth is 0)
int depth() { VarTree *parent=this; int depth=0; while( ( parent = parent->parent() ) != NULL ) depth++; return depth; }
int depth()
{
VarTree *parent = this;
int depth = 0;
while( ( parent = parent->parent() ) != NULL )
depth++;
return depth;
}
/// Execute the action associated to this item
virtual void action( VarTree *pItem ) {}
......@@ -104,18 +121,21 @@ class VarTree: public Variable, public Subject<VarTree>
int visibleItems();
/// Return iterator to the n'th visible item
Iterator visibleItem( int n );
Iterator getVisibleItem( int n );
/// Given an iterator to a visible item, return the next visible item
Iterator getNextVisibleItem( Iterator it );
private:
// intf_thread_t *pIntf;
///list of children
/// List of children
list<VarTree> m_children;
///Pointer to parent node
/// Pointer to parent node
VarTree *m_pParent;
///Variable type
/// Variable type
static const string m_type;
/// Position variable
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment