*
* Authors: Antoine Cellerier <dionoea@videolan.org>
* Clément Stenac <zorglub@videolan.org>
+ * Erwan Tulou <erwan10 At videolan DoT org>
*
* 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
#include "../events/evt_key.hpp"
#include "../events/evt_mouse.hpp"
#include "../events/evt_scroll.hpp"
+#include "../events/evt_dragndrop.hpp"
+#include "../vars/playtree.hpp"
#include <vlc_keys.h>
-#define SCROLL_STEP 0.05
#define LINE_INTERVAL 1 // Number of pixels inserted between 2 lines
CtrlGeneric( pIntf,rHelp, pVisible), m_rTree( rTree), m_rFont( rFont ),
m_pBgBitmap( pBgBitmap ), m_pItemBitmap( pItemBitmap ),
m_pOpenBitmap( pOpenBitmap ), m_pClosedBitmap( pClosedBitmap ),
- m_pScaledBitmap( NULL ),
- m_fgColor( fgColor ), m_playColor( playColor ), m_bgColor1( bgColor1 ),
- m_bgColor2( bgColor2 ), m_selColor( selColor ),
- m_pLastSelected( NULL ), m_pImage( NULL ), m_dontMove( false )
+ m_pScaledBitmap( NULL ), m_pImage( NULL ),
+ m_fgColor( fgColor ), m_playColor( playColor ),
+ m_bgColor1( bgColor1 ), m_bgColor2( bgColor2 ), m_selColor( selColor ),
+ m_firstPos( m_rTree.end() ), m_lastClicked( m_rTree.end() ),
+ m_itOver( m_rTree.end() ), m_flat( pFlat->get() ), m_capacity( -1.0 ),
+ m_bRefreshOnDelete( false )
{
- // Observe the tree and position variables
+ // Observe the tree
m_rTree.addObserver( this );
- m_rTree.getPositionVar().addObserver( this );
-
- m_flat = pFlat->get();
-
- m_firstPos = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
-
- makeImage();
+ m_rTree.setFlat( m_flat );
}
CtrlTree::~CtrlTree()
{
- m_rTree.getPositionVar().delObserver( this );
m_rTree.delObserver( this );
- delete m_pScaledBitmap;
delete m_pImage;
+ delete m_pScaledBitmap;
}
int CtrlTree::itemHeight()
return bitmapWidth + 2;
}
-int CtrlTree::maxItems()
+float CtrlTree::maxItems()
{
const Position *pPos = getPosition();
if( !pPos )
{
return -1;
}
- return pPos->getHeight() / itemHeight();
+ return (float)pPos->getHeight() / itemHeight();
}
-
void CtrlTree::onUpdate( Subject<VarTree, tree_update> &rTree,
tree_update *arg )
{
(void)rTree;
- if( arg->type == arg->UpdateItem ) // Item update
+ if( arg->type == arg->ItemInserted )
{
- if( arg->b_active_item )
- autoScroll();
- if( isItemVisible( arg->i_id ) )
+ if( isItemVisible( arg->it ) )
{
makeImage();
notifyLayout();
}
+ setSliderFromFirst();
}
- else if ( arg->type == arg->ResetAll ) // Global change or deletion
- {
- m_firstPos = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
-
- makeImage();
- notifyLayout();
- }
- else if ( arg->type == arg->AppendItem ) // Item-append
+ else if( arg->type == arg->ItemUpdated )
{
- if( m_flat && m_firstPos->size() )
+ if( arg->it->isPlaying() )
{
- m_firstPos = m_rTree.getNextLeaf( m_firstPos );
+ m_rTree.ensureExpanded( arg->it );
+ ensureVisible( arg->it );
makeImage();
notifyLayout();
+ setSliderFromFirst();
}
- else if( isItemVisible( arg->i_id ) )
+ else if( isItemVisible( arg->it ) )
{
makeImage();
notifyLayout();
}
}
- else if( arg->type == arg->DeleteItem ) // item-del
+ else if( arg->type == arg->DeletingItem )
{
- /* Make sure firstPos is valid */
- VarTree::Iterator it_old = m_firstPos;
- while( m_firstPos->isDeleted() &&
- m_firstPos != (m_flat ? m_rTree.firstLeaf()
- : m_rTree.begin()) )
+ if( isItemVisible( arg->it ) )
+ m_bRefreshOnDelete = true;
+ // remove all references to arg->it
+ // if it is the one about to be deleted
+ if( m_firstPos == arg->it )
{
- m_firstPos = m_flat ? m_rTree.getPrevLeaf( m_firstPos )
- : m_rTree.getPrevVisibleItem( m_firstPos );
+ m_firstPos = getNearestItem( arg->it );
}
- if( m_firstPos->isDeleted() )
- m_firstPos = m_rTree.begin();
-
- if( m_firstPos != it_old || isItemVisible( arg->i_id ) )
+ if( m_lastClicked == arg->it )
{
- makeImage();
- notifyLayout();
+ m_lastClicked = getNearestItem( arg->it );
+ m_lastClicked->setSelected( arg->it->isSelected() );
}
}
-}
-
-void CtrlTree::onUpdate( Subject<VarPercent> &rPercent, void* arg)
-{
- (void)rPercent; (void)arg;
- // Determine what is the first item to display
- VarTree::Iterator it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
-
- if( m_dontMove ) return;
-
- int excessItems;
- if( m_flat )
- excessItems = m_rTree.countLeafs() - maxItems();
- else
- excessItems = m_rTree.visibleItems() - maxItems();
-
- if( excessItems > 0)
+ else if( arg->type == arg->ItemDeleted )
{
- VarPercent &rVarPos = m_rTree.getPositionVar();
- // a simple (int)(...) causes rounding errors !
-#ifdef _MSC_VER
-# define lrint (int)
-#endif
- if( m_flat )
- it = m_rTree.getLeaf(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1 );
- else
- it = m_rTree.getVisibleItem(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1 );
+ if( m_bRefreshOnDelete )
+ {
+ m_bRefreshOnDelete = false;
+
+ makeImage();
+ notifyLayout();
+ }
+ setSliderFromFirst();
}
- if( m_firstPos != it )
+ else if( arg->type == arg->ResetAll )
{
- // Redraw the control if the position has changed
- m_firstPos = it;
+ m_lastClicked = m_rTree.end();
+ m_firstPos = getFirstFromSlider();
+
makeImage();
notifyLayout();
+ setSliderFromFirst();
+ }
+ else if( arg->type == arg->SliderChanged )
+ {
+ Iterator it = getFirstFromSlider();
+ if( m_firstPos != it )
+ {
+ m_firstPos = it;
+ makeImage();
+ notifyLayout();
+ }
}
}
void CtrlTree::onResize()
{
- // Determine what is the first item to display
- VarTree::Iterator it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
-
- int excessItems;
- if( m_flat )
- excessItems = m_rTree.countLeafs() - maxItems();
- else
- excessItems = m_rTree.visibleItems() - maxItems();
-
- if( excessItems > 0)
- {
- VarPercent &rVarPos = m_rTree.getPositionVar();
- // a simple (int)(...) causes rounding errors !
-#ifdef _MSC_VER
-# define lrint (int)
-#endif
- if( m_flat )
- it = m_rTree.getLeaf(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1 );
- else
- it = m_rTree.getVisibleItem(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1 );
- }
- // Redraw the control if the position has changed
- m_firstPos = it;
- makeImage();
+ onPositionChange();
}
void CtrlTree::onPositionChange()
{
+ m_capacity = maxItems();
+ setScrollStep();
+ m_firstPos = getFirstFromSlider();
makeImage();
}
void CtrlTree::handleEvent( EvtGeneric &rEvent )
{
- bool bChangedPosition = false;
- VarTree::Iterator toShow; bool needShow = false;
+ bool needShow = false;
+ bool needRefresh = false;
+ Iterator toShow = m_firstPos;
if( rEvent.getAsString().find( "key:down" ) != string::npos )
{
int key = ((EvtKey&)rEvent).getKey();
- VarTree::Iterator it;
- bool previousWasSelected = false;
/* Delete the selection */
if( key == KEY_DELETE )
{
- /* Find first non selected item before m_pLastSelected */
- VarTree::Iterator it_sel = m_flat ? m_rTree.firstLeaf()
- : m_rTree.begin();
- for( it = (m_flat ? m_rTree.firstLeaf() : m_rTree.begin());
- it != m_rTree.end();
- it = (m_flat ? m_rTree.getNextLeaf( it )
- : m_rTree.getNextVisibleItem( it )) )
- {
- if( &*it == m_pLastSelected ) break;
- if( !it->isSelected() ) it_sel = it;
- }
-
/* Delete selected stuff */
m_rTree.delSelected();
-
- /* Verify if there is still sthg selected (e.g read-only items) */
- m_pLastSelected = NULL;
- for( it = (m_flat ? m_rTree.firstLeaf() : m_rTree.begin());
- it != m_rTree.end();
- it = (m_flat ? m_rTree.getNextLeaf( it )
- : m_rTree.getNextVisibleItem( it )) )
- {
- if( it->isSelected() )
- m_pLastSelected = &*it;
- }
-
- /* if everything was deleted, use it_sel as last selection */
- if( !m_pLastSelected )
- {
- it_sel->setSelected( true );
- m_pLastSelected = &*it_sel;
- }
-
- // Redraw the control
- makeImage();
- notifyLayout();
}
else if( key == KEY_PAGEDOWN )
{
- it = m_firstPos;
- int i = (int)(maxItems()*1.5);
- while( i >= 0 )
+ int numSteps = (int)m_capacity / 2;
+ VarPercent &rVarPos = m_rTree.getPositionVar();
+ rVarPos.increment( -numSteps );
+ }
+ else if( key == KEY_PAGEUP )
+ {
+ int numSteps = (int)m_capacity / 2;
+ VarPercent &rVarPos = m_rTree.getPositionVar();
+ rVarPos.increment( numSteps );
+ }
+ else if( key == KEY_UP )
+ {
+ // Scroll up one item
+ m_rTree.unselectTree();
+ if( m_lastClicked != m_rTree.end() )
{
- VarTree::Iterator it_old = it;
- it = m_flat ? m_rTree.getNextLeaf( it )
- : m_rTree.getNextVisibleItem( it );
- /* End is already visible, dont' scroll */
- if( it == m_rTree.end() )
+ if( --m_lastClicked != m_rTree.end() )
{
- it = it_old;
- break;
+ m_lastClicked->setSelected( true );
}
- needShow = true;
- i--;
}
- if( needShow )
+ if( m_lastClicked == m_rTree.end() )
{
- ensureVisible( it );
- makeImage();
- notifyLayout();
+ m_lastClicked = m_firstPos;
+ if( m_lastClicked != m_rTree.end() )
+ m_lastClicked->setSelected( true );
}
+ needRefresh = true;
+ needShow = true; toShow = m_lastClicked;
}
- else if (key == KEY_PAGEUP )
+ else if( key == KEY_DOWN )
{
- it = m_firstPos;
- int i = maxItems();
- while( i >= maxItems()/2 )
+ // Scroll down one item
+ m_rTree.unselectTree();
+ if( m_lastClicked != m_rTree.end() )
{
- it = m_flat ? m_rTree.getPrevLeaf( it )
- : m_rTree.getPrevVisibleItem( it );
- /* End is already visible, dont' scroll */
- if( it == ( m_flat ? m_rTree.firstLeaf() : m_rTree.begin() ) )
+ Iterator it_old = m_lastClicked;
+ if( ++m_lastClicked != m_rTree.end() )
{
- break;
+ m_lastClicked->setSelected( true );
+ }
+ else
+ {
+ it_old->setSelected( true );
+ m_lastClicked = it_old;
}
- i--;
}
- ensureVisible( it );
- makeImage();
- notifyLayout();
+ else
+ {
+ m_lastClicked = m_firstPos;
+ if( m_lastClicked != m_rTree.end() )
+ m_lastClicked->setSelected( true );
+ }
+ needRefresh = true;
+ needShow = true; toShow = m_lastClicked;
}
- else if ( key == KEY_UP ||
- key == KEY_DOWN ||
- key == KEY_LEFT ||
- key == KEY_RIGHT ||
- key == KEY_ENTER ||
- key == ' ' )
+ else if( key == KEY_RIGHT )
{
- for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
- it != m_rTree.end();
- it = m_flat ? m_rTree.getNextLeaf( it )
- : m_rTree.getNextVisibleItem( it ) )
+ // Go down one level (and expand node)
+ Iterator& it = m_lastClicked;
+ if( it != m_rTree.end() )
{
- VarTree::Iterator next = m_flat ?
- m_rTree.getNextLeaf( it ) :
- m_rTree.getNextVisibleItem( it );
- if( key == KEY_UP )
+ if( !m_flat && !it->isExpanded() && it->size() )
{
- // Scroll up one item
- if( ( it->parent()
- && it != it->parent()->begin() )
- || &*it != m_pLastSelected )
- {
- bool nextWasSelected = ( &*next == m_pLastSelected );
- it->setSelected( nextWasSelected );
- if( nextWasSelected )
- {
- m_pLastSelected = &*it;
- needShow = true; toShow = it;
- }
- }
+ it->setExpanded( true );
+ needRefresh = true;
}
- else if( key == KEY_DOWN )
+ else
{
- // Scroll down one item
- if( ( it->parent()
- && next != it->parent()->end() )
- || &*it != m_pLastSelected )
+ m_rTree.unselectTree();
+ Iterator it_old = m_lastClicked;
+ if( ++m_lastClicked != m_rTree.end() )
{
- it->setSelected( previousWasSelected );
+ m_lastClicked->setSelected( true );
}
- if( previousWasSelected )
+ else
{
- m_pLastSelected = &*it;
- needShow = true; toShow = it;
- previousWasSelected = false;
+ it_old->setSelected( true );
+ m_lastClicked = it_old;
}
- else
+ needRefresh = true;
+ needShow = true; toShow = m_lastClicked;
+ }
+ }
+ }
+ else if( key == KEY_LEFT )
+ {
+ // Go up one level (and close node)
+ Iterator& it = m_lastClicked;
+ if( it != m_rTree.end() )
+ {
+ if( m_flat )
+ {
+ m_rTree.unselectTree();
+ if( --m_lastClicked != m_rTree.end() )
{
- previousWasSelected = ( &*it == m_pLastSelected );
+ m_lastClicked->setSelected( true );
}
-
- // Fix last tree item selection
- if( ( m_flat ? m_rTree.getNextLeaf( it )
- : m_rTree.getNextVisibleItem( it ) ) == m_rTree.end()
- && &*it == m_pLastSelected )
+ else
{
- it->setSelected( true );
+ m_lastClicked = m_firstPos;
+ if( m_lastClicked != m_rTree.end() )
+ m_lastClicked->setSelected( true );
}
+ needRefresh = true;
+ needShow = true; toShow = m_lastClicked;
}
- else if( key == KEY_RIGHT )
+ else
{
- // Go down one level (and expand node)
- if( &*it == m_pLastSelected )
+ if( it->isExpanded() )
{
- if( it->isExpanded() )
- {
- if( it->size() )
- {
- it->setSelected( false );
- it->begin()->setSelected( true );
- m_pLastSelected = &*(it->begin());
- }
- else
- {
- m_rTree.action( &*it );
- }
- }
- else
- {
- it->setExpanded( true );
- bChangedPosition = true;
- }
+ it->setExpanded( false );
+ needRefresh = true;
}
- }
- else if( key == KEY_LEFT )
- {
- // Go up one level (and close node)
- if( &*it == m_pLastSelected )
+ else
{
- if( it->isExpanded() && it->size() )
- {
- it->setExpanded( false );
- bChangedPosition = true;
- }
- else
+ Iterator it_parent = it.getParent();
+ if( it_parent != m_rTree.end() )
{
- if( it->parent() && it->parent() != &m_rTree)
- {
- it->setSelected( false );
- m_pLastSelected = it->parent();
- m_pLastSelected->setSelected( true );
- }
+ it->setSelected( false );
+ m_lastClicked = it_parent;
+ m_lastClicked->setSelected( true );
+ needRefresh = true;
+ needShow = true; toShow = m_lastClicked;
}
}
}
- else if( key == KEY_ENTER || key == ' ' )
- {
- // Go up one level (and close node)
- if( &*it == m_pLastSelected )
- {
- m_rTree.action( &*it );
- }
- }
}
- if( needShow )
- ensureVisible( toShow );
- // Redraw the control
- makeImage();
- notifyLayout();
+ }
+ else if( key == KEY_ENTER || key == ' ' )
+ {
+ // Go up one level (and close node)
+ if( m_lastClicked != m_rTree.end() )
+ {
+ m_rTree.action( &*m_lastClicked );
+ }
}
else
{
var_SetInteger( getIntf()->p_libvlc, "key-pressed",
rEvtKey.getModKey() );
}
-
}
else if( rEvent.getAsString().find( "mouse:left" ) != string::npos )
{
EvtMouse &rEvtMouse = (EvtMouse&)rEvent;
const Position *pos = getPosition();
- int yPos = ( rEvtMouse.getYPos() - pos->getTop() ) / itemHeight();
int xPos = rEvtMouse.getXPos() - pos->getLeft();
- VarTree::Iterator it;
+ int yPos = ( rEvtMouse.getYPos() - pos->getTop() ) / itemHeight();
- if( rEvent.getAsString().find( "mouse:left:down:ctrl,shift" ) !=
- string::npos )
+ Iterator itClicked = findItemAtPos( yPos );
+ if( itClicked != m_rTree.end() )
{
- VarTree::Iterator itClicked = findItemAtPos( yPos );
- // Flag to know if the current item must be selected
- bool select = false;
- for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
- it != m_rTree.end();
- it = m_flat ? m_rTree.getNextLeaf( it )
- : m_rTree.getNextVisibleItem( it ) )
+ if( rEvent.getAsString().find( "mouse:left:down:ctrl,shift" ) !=
+ string::npos )
{
- bool nextSelect = select;
- if( it == itClicked || &*it == m_pLastSelected )
+ // Flag to know if the current item must be selected
+ bool select = false;
+ for( Iterator it = m_firstPos; it != m_rTree.end(); ++it )
{
- if( select )
- {
- nextSelect = false;
- }
- else
+ bool nextSelect = select;
+ if( it == itClicked || it == m_lastClicked )
{
- select = true;
- nextSelect = true;
+ if( select )
+ {
+ nextSelect = false;
+ }
+ else
+ {
+ select = true;
+ if( itClicked != m_lastClicked )
+ nextSelect = true;
+ }
}
+ it->setSelected( it->isSelected() || select );
+ select = nextSelect;
+ needRefresh = true;
}
- it->setSelected( it->isSelected() || select );
- select = nextSelect;
}
- // Redraw the control
- makeImage();
- notifyLayout();
- }
- else if( rEvent.getAsString().find( "mouse:left:down:ctrl" ) !=
- string::npos )
- {
- // Invert the selection of the item
- it = findItemAtPos( yPos );
- if( it != m_rTree.end() )
+ else if( rEvent.getAsString().find( "mouse:left:down:ctrl" ) !=
+ string::npos )
{
- it->toggleSelected();
- m_pLastSelected = &*it;
+ // Invert the selection of the item
+ itClicked->toggleSelected();
+ m_lastClicked = itClicked;
+ needRefresh = true;
}
- // Redraw the control
- makeImage();
- notifyLayout();
- }
- else if( rEvent.getAsString().find( "mouse:left:down:shift" ) !=
- string::npos )
- {
- VarTree::Iterator itClicked = findItemAtPos( yPos );
- // Flag to know if the current item must be selected
- bool select = false;
- for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
- it != m_rTree.end();
- it = m_flat ? m_rTree.getNextLeaf( it )
- : m_rTree.getNextVisibleItem( it ) )
+ else if( rEvent.getAsString().find( "mouse:left:down:shift" ) !=
+ string::npos )
{
- bool nextSelect = select;
- if( it == itClicked || &*it == m_pLastSelected )
+ bool select = false;
+ for( Iterator it = m_firstPos; it != m_rTree.end(); ++it )
{
- if( select )
- {
- nextSelect = false;
- }
- else
+ bool nextSelect = select;
+ if( it == itClicked || it == m_lastClicked )
{
- select = true;
- nextSelect = true;
+ if( select )
+ {
+ nextSelect = false;
+ }
+ else
+ {
+ select = true;
+ if( itClicked != m_lastClicked )
+ nextSelect = true;
+ }
}
+ it->setSelected( select );
+ select = nextSelect;
}
- it->setSelected( select );
- select = nextSelect;
+ needRefresh = true;
}
- // Redraw the control
- makeImage();
- notifyLayout();
- }
- else if( rEvent.getAsString().find( "mouse:left:down" ) !=
- string::npos )
- {
- it = findItemAtPos(yPos);
- if( it != m_rTree.end() )
+ else if( rEvent.getAsString().find( "mouse:left:down" ) !=
+ string::npos )
{
- if( ( it->size() && xPos > (it->depth() - 1) * itemImageWidth()
- && xPos < it->depth() * itemImageWidth() )
- && !m_flat )
+ if( !m_flat &&
+ itClicked->size() &&
+ xPos > (itClicked->depth() - 1) * itemImageWidth() &&
+ xPos < itClicked->depth() * itemImageWidth() )
{
// Fold/unfold the item
- it->toggleExpanded();
- bChangedPosition = true;
+ itClicked->toggleExpanded();
}
else
{
// Unselect any previously selected item
- VarTree::Iterator it2;
- for( it2 = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
- it2 != m_rTree.end();
- it2 = m_flat ? m_rTree.getNextLeaf( it2 )
- : m_rTree.getNextVisibleItem( it2 ) )
- {
- it2->setSelected( false );
- }
+ m_rTree.unselectTree();
// Select the new item
- if( it != m_rTree.end() )
- {
- it->setSelected( true );
- m_pLastSelected = &*it;
- }
+ itClicked->setSelected( true );
+ m_lastClicked = itClicked;
}
+ needRefresh = true;
}
- // Redraw the control
- makeImage();
- notifyLayout();
- }
- else if( rEvent.getAsString().find( "mouse:left:dblclick" ) !=
- string::npos )
- {
- it = findItemAtPos(yPos);
- if( it != m_rTree.end() )
+ else if( rEvent.getAsString().find( "mouse:left:dblclick" ) !=
+ string::npos )
{
// Execute the action associated to this item
- m_rTree.action( &*it );
+ m_rTree.action( &*itClicked );
}
- // Redraw the control
- makeImage();
- notifyLayout();
}
}
else if( rEvent.getAsString().find( "scroll" ) != string::npos )
{
- // XXX ctrl_slider.cpp has two more (but slightly different)
- // XXX implementations of `scroll'. Figure out where it belongs.
-
int direction = static_cast<EvtScroll&>(rEvent).getDirection();
-
- double percentage = m_rTree.getPositionVar().get();
- double step = 2.0 / (double)( m_flat ? m_rTree.countLeafs()
- : m_rTree.visibleItems() );
if( direction == EvtScroll::kUp )
- {
- percentage += step;
- }
+ m_rTree.getPositionVar().increment( +1 );
else
- {
- percentage -= step;
- }
- m_rTree.getPositionVar().set( percentage );
+ m_rTree.getPositionVar().increment( -1 );
}
- /* We changed the nodes, let's fix the position var */
- if( bChangedPosition )
+ else if( rEvent.getAsString().find( "drag:over" ) != string::npos )
{
- VarTree::Iterator it;
- int iFirst = 0;
- for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
- it != m_rTree.end();
- it = m_flat ? m_rTree.getNextLeaf( it )
- : m_rTree.getNextVisibleItem( it ) )
+ EvtDragOver& evt = static_cast<EvtDragOver&>(rEvent);
+ const Position *pos = getPosition();
+ int yPos = ( evt.getYPos() - pos->getTop() ) / itemHeight();
+
+ Iterator it = findItemAtPos( yPos );
+ if( it != m_itOver )
{
- if( it == m_firstPos )
- break;
- iFirst++;
+ if( it != m_rTree.end() )
+ it->setExpanded( true );
+ m_itOver = it;
+ needRefresh = true;
}
+ }
+
+ else if( rEvent.getAsString().find( "drag:drop" ) != string::npos )
+ {
+ EvtDragDrop& evt = static_cast<EvtDragDrop&>(rEvent);
+ Playtree& rPlaytree = static_cast<Playtree&>(m_rTree);
+ rPlaytree.insertItems( *m_itOver, evt.getFiles(), false );
+ m_itOver = m_rTree.end();
+ needRefresh = true;
+ }
- int indexMax = ( m_flat ? m_rTree.countLeafs()
- : m_rTree.visibleItems() ) - 1;
- float f_new = (float)iFirst / (float)indexMax;
+ else if( rEvent.getAsString().find( "drag:leave" ) != string::npos )
+ {
+ m_itOver = m_rTree.end();
+ needRefresh = true;
+ }
- m_dontMove = true;
- m_rTree.getPositionVar().set( 1.0 - f_new );
- m_dontMove = false;
+ if( needShow )
+ {
+ if( toShow == m_rTree.end() ||
+ !ensureVisible( toShow ) )
+ needRefresh = true;
+ }
+ if( needRefresh )
+ {
+ setSliderFromFirst();
+
+ makeImage();
+ notifyLayout();
}
}
inter.x, inter.y, inter.width, inter.height );
}
-bool CtrlTree::ensureVisible( VarTree::Iterator item )
-{
- m_rTree.ensureExpanded( item );
-
- int firstPosIndex = m_rTree.getRank( m_firstPos, m_flat) - 1;
- int focusItemIndex = m_rTree.getRank( item, m_flat) - 1;
-
- if( focusItemIndex < firstPosIndex ||
- focusItemIndex > firstPosIndex + maxItems() - 1 )
- {
- // Scroll to have the wanted stream visible
- VarPercent &rVarPos = m_rTree.getPositionVar();
- int indexMax = ( m_flat ? m_rTree.countLeafs()
- : m_rTree.visibleItems() ) - 1;
- rVarPos.set( 1.0 - (double)focusItemIndex / (double)indexMax );
- return true;
- }
- return false;
-}
-
-void CtrlTree::autoScroll()
-{
- // Find the current playing stream
- VarTree::Iterator it;
-
- for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
- it != m_rTree.end();
- it = m_flat ? m_rTree.getNextLeaf( it )
- : m_rTree.getNextItem( it ) )
- {
- if( it->isPlaying() )
- {
- ensureVisible( it );
- break;
- }
- }
-}
-
-
void CtrlTree::makeImage()
{
stats_TimerStart( getIntf(), "[Skins] Playlist image",
OSFactory *pOsFactory = OSFactory::instance( getIntf() );
m_pImage = pOsFactory->createOSGraphics( width, height );
- VarTree::Iterator it = m_firstPos;
+ Iterator it = m_firstPos;
if( m_pBgBitmap )
{
}
m_pImage->drawBitmap( *m_pScaledBitmap, 0, 0 );
- for( int yPos = 0; yPos < height; yPos += i_itemHeight )
+ for( int yPos = 0;
+ yPos < height && it != m_rTree.end();
+ yPos += i_itemHeight, ++it )
{
- if( it != m_rTree.end() )
+ if( it->isSelected() )
{
- if( it->isSelected() )
- {
- int rectHeight = __MIN( i_itemHeight, height - yPos );
- m_pImage->fillRect( 0, yPos, width, rectHeight,
- m_selColor );
- }
- do
- {
- it = m_flat ? m_rTree.getNextLeaf( it )
- : m_rTree.getNextVisibleItem( it );
- } while( it != m_rTree.end() && it->isDeleted() );
+ int rectHeight = __MIN( i_itemHeight, height - yPos );
+ m_pImage->fillRect( 0, yPos, width, rectHeight, m_selColor );
}
}
}
else
{
- // FIXME (TRYME)
// Fill background with background color
uint32_t bgColor = m_bgColor1;
m_pImage->fillRect( 0, 0, width, height, bgColor );
+ // Overwrite with alternate colors (bgColor1, bgColor2)
for( int yPos = 0; yPos < height; yPos += i_itemHeight )
{
int rectHeight = __MIN( i_itemHeight, height - yPos );
{
uint32_t color = ( it->isSelected() ? m_selColor : bgColor );
m_pImage->fillRect( 0, yPos, width, rectHeight, color );
- do
- {
- it = m_flat ? m_rTree.getNextLeaf( it )
- : m_rTree.getNextVisibleItem( it );
- } while( it != m_rTree.end() && it->isDeleted() );
+ ++it;
}
bgColor = ( bgColor == m_bgColor1 ? m_bgColor2 : m_bgColor1 );
}
int bitmapWidth = itemImageWidth();
- int yPos = 0;
it = m_firstPos;
- while( it != m_rTree.end() && yPos < height )
+ for( int yPos = 0; yPos < height && it != m_rTree.end(); ++it )
{
const GenericBitmap *m_pCurBitmap;
UString *pStr = it->getString();
- uint32_t color = ( it->isPlaying() ? m_playColor : m_fgColor );
-
- // Draw the text
if( pStr != NULL )
{
+ uint32_t color = it->isPlaying() ? m_playColor : m_fgColor;
int depth = m_flat ? 1 : it->depth();
- GenericBitmap *pText = m_rFont.drawString( *pStr, color, width - bitmapWidth * depth );
+ GenericBitmap *pText =
+ m_rFont.drawString( *pStr, color, width-bitmapWidth*depth );
if( !pText )
{
stats_TimerStop( getIntf(), STATS_TIMER_SKINS_PLAYTREE_IMAGE );
return;
}
if( it->size() )
- m_pCurBitmap = it->isExpanded() ? m_pOpenBitmap : m_pClosedBitmap;
+ m_pCurBitmap =
+ it->isExpanded() ? m_pOpenBitmap : m_pClosedBitmap;
else
m_pCurBitmap = m_pItemBitmap;
delete pText;
break;
}
+ // Draw the icon in front of the text
m_pImage->drawBitmap( *m_pCurBitmap, 0, 0,
bitmapWidth * (depth - 1 ), yPos2,
m_pCurBitmap->getWidth(),
yPos = 0;
}
int lineHeight = __MIN( pText->getHeight() - ySrc, height - yPos );
+ // Draw the text
m_pImage->drawBitmap( *pText, 0, ySrc, bitmapWidth * depth, yPos,
pText->getWidth(),
lineHeight, true );
yPos += (pText->getHeight() - ySrc );
+
+ if( it == m_itOver )
+ {
+ // Draw the underline bar below the text for drag&drop
+ m_pImage->fillRect(
+ bitmapWidth * (depth - 1 ), yPos - 2,
+ bitmapWidth + pText->getWidth(), __MAX( lineHeight/5, 3 ),
+ m_selColor );
+ }
delete pText;
}
- do
- {
- it = m_flat ? m_rTree.getNextLeaf( it )
- : m_rTree.getNextVisibleItem( it );
- } while( it != m_rTree.end() && it->isDeleted() );
}
stats_TimerStop( getIntf(), STATS_TIMER_SKINS_PLAYTREE_IMAGE );
}
-VarTree::Iterator CtrlTree::findItemAtPos( int pos )
+CtrlTree::Iterator CtrlTree::findItemAtPos( int pos )
{
// The first item is m_firstPos.
// We decrement pos as we try the other items, until pos == 0.
- VarTree::Iterator it;
- for( it = m_firstPos; it != m_rTree.end() && pos != 0;
- it = m_flat ? m_rTree.getNextLeaf( it )
- : m_rTree.getNextVisibleItem( it ) )
+ Iterator it = m_firstPos;
+ for( ; it != m_rTree.end() && pos != 0; ++it, pos-- );
+
+ return it;
+}
+
+CtrlTree::Iterator CtrlTree::getFirstFromSlider()
+{
+ // a simple (int)(...) causes rounding errors !
+#ifdef _MSC_VER
+# define lrint (int)
+#endif
+ VarPercent &rVarPos = m_rTree.getPositionVar();
+ double percentage = rVarPos.get();
+
+ int excessItems = m_flat ? (m_rTree.countLeafs() - (int)m_capacity)
+ : (m_rTree.visibleItems() - (int)m_capacity);
+
+ int index = (excessItems > 0 ) ?
+ lrint( (1.0 - percentage)*(double)excessItems ) :
+ 0;
+
+ Iterator it_first = m_rTree.getItem( index );
+
+ if( m_lastClicked == m_rTree.end() )
{
- pos--;
+ m_lastClicked = it_first;
+ if( m_lastClicked != m_rTree.end() )
+ m_lastClicked->setSelected( true );
}
- return it;
+ return it_first;
}
-bool CtrlTree::isItemVisible( int id )
+void CtrlTree::setScrollStep()
{
- VarTree::Iterator it = m_rTree.findById( id );
+ VarPercent &rVarPos = m_rTree.getPositionVar();
- int rank1 = m_rTree.getRank( m_firstPos, m_flat );
- int rank2 = m_rTree.getRank( it, m_flat );
- return ( rank2 >= rank1 && rank2 <= rank1 + maxItems() -1 );
+ int excessItems = m_flat ? (m_rTree.countLeafs() - (int)m_capacity)
+ : (m_rTree.visibleItems() - (int)m_capacity);
+
+ if( excessItems > 0 )
+ rVarPos.setStep( (float)1 / excessItems );
+ else
+ rVarPos.setStep( 1.0 );
+}
+
+void CtrlTree::setSliderFromFirst()
+{
+ VarPercent &rVarPos = m_rTree.getPositionVar();
+
+ int excessItems = m_flat ? (m_rTree.countLeafs() - (int)m_capacity)
+ : (m_rTree.visibleItems() - (int)m_capacity);
+
+ int index = m_rTree.getIndex( m_firstPos );
+ if( excessItems > 0 )
+ {
+ rVarPos.set( 1.0 - (float)index/(float)excessItems );
+ rVarPos.setStep( 1.0 / excessItems );
+ }
+ else
+ {
+ rVarPos.set( 1.0 );
+ rVarPos.setStep( 1.0 );
+ }
+}
+
+bool CtrlTree::isItemVisible( const Iterator& it_ref )
+{
+ if( it_ref == m_rTree.end() )
+ return false;
+
+ Iterator it = m_firstPos;
+ if( it == m_rTree.end() )
+ return true;
+
+ // Ensure a partially visible last item is taken into account
+ int max = (int)m_capacity;
+ if( (float)max < m_capacity )
+ max++;
+
+ for( int i = 0; i < max && it != m_rTree.end(); ++it, i++ )
+ {
+ if( it == it_ref )
+ return true;
+ }
+ return false;
+}
+
+bool CtrlTree::ensureVisible( const Iterator& item )
+{
+ Iterator it = m_firstPos;
+ int max = (int)m_capacity;
+ for( int i = 0; i < max && it != m_rTree.end(); ++it, i++ )
+ {
+ if( it == item )
+ return false;
+ }
+
+ m_rTree.setSliderFromItem( item );
+ return true;
+}
+
+CtrlTree::Iterator CtrlTree::getNearestItem( const Iterator& item )
+{
+ // return the previous item if it exists
+ Iterator newItem = item;
+ if( --newItem != m_rTree.end() && newItem != item )
+ return newItem;
+
+ // return the next item if no previous item found
+ newItem = item;
+ return ++newItem;
}
class GenericBitmap;
/// Class for control tree
-class CtrlTree: public CtrlGeneric, public Observer<VarTree, tree_update>,
- public Observer<VarPercent>
+class CtrlTree: public CtrlGeneric, public Observer<VarTree, tree_update>
{
public:
+ typedef VarTree::IteratorVisible Iterator;
+
CtrlTree( intf_thread_t *pIntf,
VarTree &rTree,
const GenericFont &rFont,
/// Make sure an item is visible
/// \param item an iterator to a tree item
/// \return true if it changed the position
- bool ensureVisible( VarTree::Iterator item );
+ bool ensureVisible( const Iterator& it );
private:
/// Tree associated to the control
const GenericBitmap *m_pClosedBitmap;
/// scaled bitmap
GenericBitmap *m_pScaledBitmap;
+ /// Image of the control
+ OSGraphics *m_pImage;
+
/// Color of normal test
uint32_t m_fgColor;
/// Color of the playing item
uint32_t m_bgColor1, m_bgColor2;
/// Background of selected items
uint32_t m_selColor;
- /// Pointer on the last selected item in the tree
- VarTree *m_pLastSelected;
- /// Image of the control
- OSGraphics *m_pImage;
- /// First item in the visible area
- VarTree::Iterator m_firstPos;
- /// Don't move if the position variable is updated
- bool m_dontMove;
+ /// First item in the visible area
+ Iterator m_firstPos;
+ /// Pointer on the last clicked item in the tree
+ Iterator m_lastClicked;
+ ///
+ Iterator m_itOver;
/// Do we want to "flaten" the tree ?
bool m_flat;
+ /// Number of visible lines
+ float m_capacity;
+ /// flag for item deletion
+ bool m_bRefreshOnDelete;
/// Method called when the tree variable is modified
- virtual void onUpdate( Subject<VarTree, tree_update> &rTree ,
+ virtual void onUpdate( Subject<VarTree, tree_update> &rTree,
tree_update *);
- // Method called when the position variable of the tree is modified
- virtual void onUpdate( Subject<VarPercent> &rPercent , void *);
-
/// Called when the position is set
virtual void onPositionChange();
/// Compute the number of lines that can be displayed
- int maxItems();
+ float maxItems();
/// Compute the item's height (depends on fonts and images used)
int itemHeight();
/// Compute the width of an item's bitmap
int itemImageWidth();
- /// Check if the tree must be scrolled
- void autoScroll();
-
/// 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 );
-
- /// check if id is within the visible control
- bool isItemVisible( int id );
+ Iterator findItemAtPos( int n );
+
+ /// return the nearest item
+ Iterator getNearestItem( const Iterator& it );
+
+ /// return whether the item is visible or not
+ bool isItemVisible( const Iterator& it );
+
+ void setSliderFromFirst();
+ Iterator getFirstFromSlider();
+ void setScrollStep();
};
#endif
class VarPercent: public Variable, public Subject<VarPercent>
{
public:
- VarPercent( intf_thread_t *pIntf ): Variable( pIntf ), m_value( 0 ) { }
+ VarPercent( intf_thread_t *pIntf ) :
+ Variable( pIntf ), m_value( 0 ), m_step( .05f ) {}
virtual ~VarPercent() { }
/// Get the variable type
virtual float get() const { return m_value; }
/// Get the variable preferred step
- virtual float getStep() const { return .05f; }
+ virtual float getStep() const { return m_step; }
+ virtual void setStep( float val ) { m_step = val; }
+
+ /// Increment or decrement variable
+ void increment( int num ) { return set( m_value + num * m_step ); }
private:
/// Variable type
static const string m_type;
/// Percent value
float m_value;
+ /// preferred step (for scrolling)
+ float m_step;
};
#endif
*
* Authors: Antoine Cellerier <dionoea@videolan.org>
* Clément Stenac <zorglub@videolan.org>
+ * Erwan Tulou <erwan10@videolan.org>
*
* 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
*****************************************************************************/
#include "var_tree.hpp"
-
+#include <math.h>
const string VarTree::m_type = "tree";
VarTree::VarTree( intf_thread_t *pIntf )
- : Variable( pIntf ), m_pParent( NULL ), m_id( 0 ), m_pData( NULL ),
- m_readonly( false ), m_selected( false ), m_playing( false ),
- m_expanded( false ), m_deleted( false )
+ : Variable( pIntf ), m_pParent( NULL ), m_id( 0 ),
+ m_readonly( false ), m_selected( false ),
+ m_playing( false ), m_expanded( false ),
+ m_flat( false ), m_dontMove( false )
{
// Create the position variable
m_cPosition = VariablePtr( new VarPercent( pIntf ) );
getPositionVar().set( 1.0 );
+
+ getPositionVar().addObserver( this );
}
VarTree::VarTree( intf_thread_t *pIntf, VarTree *pParent, int id,
const UStringPtr &rcString, bool selected, bool playing,
- bool expanded, bool readonly, void *pData )
+ bool expanded, bool readonly )
: Variable( pIntf ), m_pParent( pParent ),
- m_id( id ), m_pData( pData ), m_cString( rcString ),
- m_readonly( readonly ), m_selected( selected ), m_playing( playing ),
- m_expanded( expanded ), m_deleted( false )
+ m_id( id ), m_cString( rcString ),
+ m_readonly( readonly ), m_selected( selected ),
+ m_playing( playing ), m_expanded( expanded ),
+ m_flat( false ), m_dontMove( false )
{
// Create the position variable
m_cPosition = VariablePtr( new VarPercent( pIntf ) );
getPositionVar().set( 1.0 );
+
+ getPositionVar().addObserver( this );
+}
+
+VarTree::VarTree( const VarTree& v )
+ : Variable( v.getIntf() ), m_pParent( v.m_pParent ),
+ m_id( v.m_id ), m_cString( v.m_cString ),
+ m_readonly( v.m_readonly ), m_selected( v.m_selected ),
+ m_playing( v.m_playing ), m_expanded( v.m_expanded ),
+ m_flat( false ), m_dontMove( false )
+{
+ // Create the position variable
+ m_cPosition = VariablePtr( new VarPercent( getIntf() ) );
+ getPositionVar().set( 1.0 );
+
+ getPositionVar().addObserver( this );
}
VarTree::~VarTree()
{
-/// \todo check that children are deleted
+ getPositionVar().delObserver( this );
}
-void VarTree::add( int id, const UStringPtr &rcString, bool selected,
- bool playing, bool expanded, bool readonly, void *pData )
+VarTree::Iterator VarTree::add( int id, const UStringPtr &rcString,
+ bool selected, bool playing, bool expanded, bool readonly,
+ int pos )
{
- m_children.push_back( VarTree( getIntf(), this, id, rcString, selected,
- playing, expanded, readonly,
- pData ) );
+ Iterator it;
+ if( pos == -1 )
+ {
+ it = m_children.end();
+ }
+ else
+ {
+ it = m_children.begin();
+ for( int i = 0; i < pos && it != m_children.end(); ++it, i++ );
+ }
+
+ return m_children.insert( it,
+ VarTree( getIntf(), this, id, rcString,
+ selected, playing,
+ expanded, readonly ) );
}
void VarTree::delSelected()
{
- Iterator it = begin();
- while( it != end() )
+ for( Iterator it = m_children.begin(); it != m_children.end(); )
{
- //dig down the tree
- if( size() ) it->delSelected();
- //stay on some level
if( it->m_selected )
{
Iterator oldIt = it;
++it;
m_children.erase( oldIt );
}
- else
- {
- ++it;
- }
}
}
m_children.clear();
}
-VarTree::Iterator VarTree::operator[]( int n )
-{
- Iterator it;
- int i;
- for( it = begin(), i = 0;
- i < n && it != end();
- ++it, i++ );
- return it;
-}
-
-VarTree::ConstIterator VarTree::operator[]( int n ) const
+VarTree::Iterator VarTree::getNextSiblingOrUncle()
{
- ConstIterator it;
- int i;
- for( it = begin(), i = 0;
- i < n && it != end();
- ++it, i++ );
- return it;
+ VarTree *p_parent = parent();
+ if( p_parent )
+ {
+ Iterator it = ++(getSelf());
+ if( it != p_parent->m_children.end() )
+ return it;
+ else
+ return next_uncle();
+ }
+ return root()->m_children.end();
}
-VarTree::Iterator VarTree::getNextSiblingOrUncle()
+VarTree::Iterator VarTree::getPrevSiblingOrUncle()
{
VarTree *p_parent = parent();
if( p_parent )
{
- Iterator it = p_parent->begin();
- while( it != p_parent->end() && &(*it) != this ) ++it;
- if( it != p_parent->end() )
- {
- Iterator current = it;
- ++it;
- if( it != p_parent->end() )
- return it;
- else
- return current->next_uncle();
- }
+ Iterator it = getSelf();
+ if( it != p_parent->m_children.begin() )
+ return --it;
else
- {
- msg_Err( getIntf(), "should never occur" );
- return end();
- }
+ return prev_uncle();
}
- return end();
+ return root()->m_children.end();
}
/* find iterator to next ancestor
VarTree::Iterator VarTree::next_uncle()
{
VarTree *p_parent = parent();
- if( p_parent != NULL )
+ if( p_parent )
{
VarTree *p_grandparent = p_parent->parent();
- while( p_grandparent != NULL )
+ while( p_grandparent )
{
- Iterator it = p_grandparent->begin();
- while( it != p_grandparent->end() && &(*it) != p_parent ) ++it;
- if( it != p_grandparent->end() )
- {
- ++it;
- if( it != p_grandparent->end() )
- {
- return it;
- }
- }
- if( p_grandparent->parent() )
- {
- p_parent = p_grandparent;
- p_grandparent = p_parent->parent();
- }
- else
- p_grandparent = NULL;
+ Iterator it = ++(p_parent->getSelf());
+ if( it != p_grandparent->m_children.end() )
+ return it;
+ p_parent = p_grandparent;
+ p_grandparent = p_parent->parent();
}
}
/* if we didn't return before, it means that we've reached the end */
- return root()->end();
+ return root()->m_children.end();
}
VarTree::Iterator VarTree::prev_uncle()
{
VarTree *p_parent = parent();
- if( p_parent != NULL )
+ if( p_parent )
{
VarTree *p_grandparent = p_parent->parent();
- while( p_grandparent != NULL )
+ while( p_grandparent )
{
- Iterator it = p_grandparent->end();
- while( it != p_grandparent->begin() && &(*it) != p_parent ) --it;
- if( it != p_grandparent->begin() )
- {
- --it;
- if( it != p_grandparent->begin() )
- {
- return it;
- }
- }
- if( p_grandparent->parent() )
- {
- p_parent = p_grandparent;
- p_grandparent = p_parent->parent();
- }
- else
- p_grandparent = NULL;
+ Iterator it = p_parent->getSelf();
+ if( it != p_grandparent->m_children.begin() )
+ return --it;
+ p_parent = p_grandparent;
+ p_grandparent = p_parent->parent();
}
}
/* if we didn't return before, it means that we've reached the end */
- return root()->begin();
+ return root()->m_children.end();
}
int VarTree::visibleItems()
{
int i_count = size();
- Iterator it = begin();
- while( it != end() )
+ for( Iterator it = m_children.begin(); it != m_children.end(); ++it )
{
if( it->m_expanded )
{
i_count += it->visibleItems();
}
- ++it;
}
return i_count;
}
VarTree::Iterator VarTree::getVisibleItem( int n )
{
- Iterator it = begin();
- while( it != end() )
+ Iterator it = m_children.begin();
+ while( it != m_children.end() )
{
n--;
if( n <= 0 )
}
++it;
}
- return end();
+ return m_children.end();
}
VarTree::Iterator VarTree::getLeaf( int n )
{
- Iterator it = begin();
- while( it != end() )
+ Iterator it = m_children.begin();
+ while( it != m_children.end() )
{
if( it->size() )
{
}
++it;
}
- return end();
+ return m_children.end();
}
VarTree::Iterator VarTree::getNextVisibleItem( Iterator it )
{
if( it->m_expanded && it->size() )
{
- it = it->begin();
+ it = it->m_children.begin();
}
else
{
Iterator it_old = it;
++it;
// Was 'it' the last brother? If so, look for uncles
- if( it_old->parent() && it_old->parent()->end() == it )
+ if( it_old->parent() && it_old->parent()->m_children.end() == it )
{
it = it_old->next_uncle();
}
VarTree::Iterator VarTree::getPrevVisibleItem( Iterator it )
{
- Iterator it_old = it;
- if( it == root()->begin() || it == ++(root()->begin()) ) return it;
+ if( it == root()->m_children.begin() )
+ return it;
+
+ if( it == root()->m_children.end() )
+ {
+ --it;
+ while( it->size() && it->m_expanded )
+ it = --(it->m_children.end());
+ return it;
+ }
/* Was it the first child of its parent ? */
- if( it->parent() && it == it->parent()->begin() )
+ VarTree *p_parent = it->parent();
+ if( it == p_parent->m_children.begin() )
{
- /* Yes, get previous uncle */
- it = it_old->prev_uncle();
+ /* Yes, get its parent's it */
+ it = p_parent->getSelf();
}
else
- --it;
-
- /* We have found an expanded uncle, take its last child */
- while( it != root()->begin() && it->size() && it->m_expanded )
{
- it = it->end();
- --it;
+ --it;
+ /* We have found an older brother, take its last visible child */
+ while( it->size() && it->m_expanded )
+ it = --(it->m_children.end());
}
return it;
}
{
if( it->size() )
{
- it = it->begin();
+ it = it->m_children.begin();
}
else
{
Iterator it_old = it;
++it;
// Was 'it' the last brother? If so, look for uncles
- if( it_old->parent() && it_old->parent()->end() == it )
+ if( it_old->parent() && it_old->parent()->m_children.end() == it )
{
it = it_old->next_uncle();
}
VarTree::Iterator VarTree::getPrevItem( Iterator it )
{
- Iterator it_old = it;
- if( it == root()->begin() || it == ++(root()->begin()) ) return it;
+ if( it == root()->m_children.begin() )
+ return it;
+ if( it == root()->m_children.end() )
+ {
+ --it;
+ while( it->size() )
+ it = --(it->m_children.end());
+ return it;
+ }
/* Was it the first child of its parent ? */
- if( it->parent() && it == it->parent()->begin() )
+ VarTree *p_parent = it->parent();
+ if( it == p_parent->m_children.begin() )
{
- /* Yes, get previous uncle */
- it = it_old->prev_uncle();
+ /* Yes, get its parent's it */
+ it = p_parent->getSelf();
}
else
- --it;
-
- /* We have found an expanded uncle, take its last child */
- while( it != root()->begin() && it->size() )
{
- it = it->end();
- --it;
+ --it;
+ /* We have found an older brother, take its last child */
+ while( it->size() )
+ it = --(it->m_children.end());
}
return it;
}
{
it = getNextItem( it );
}
- while( it != root()->end() && it->size() );
+ while( it != root()->m_children.end() && it->size() );
return it;
}
VarTree::Iterator VarTree::getPrevLeaf( Iterator it )
{
- do
- {
- it = getPrevItem( it );
- }
- while( it != root()->begin() && it->size() ); /* FIXME ? */
- if( it == root()->begin() ) it = firstLeaf();
- return it;
+ Iterator it_new = it->getPrevSiblingOrUncle();
+ if( it_new == root()->end() )
+ return it_new;
+ while( it_new->size() )
+ it_new = --(it_new->m_children.end());
+ return it_new;
}
-VarTree::Iterator VarTree::findById( int id )
+VarTree::Iterator VarTree::getParent( Iterator it )
{
- for (Iterator it = begin(); it != end(); ++it )
+ if( it->parent() )
{
- if( it->m_id == id )
- {
- return it;
- }
- Iterator result = it->findById( id );
- if( result != it->end() ) return result;
+ return it->parent()->getSelf();
}
- return end();
+ return m_children.end();
}
-
void VarTree::ensureExpanded( const Iterator& it )
{
/// Don't expand ourselves, only our parents
VarTree *current = &(*it);
current = current->parent();
- while( current->parent() != NULL )
+ while( current->parent() )
{
current->m_expanded = true;
current = current->parent();
int VarTree::countLeafs()
{
- if( size() == 0 ) return 1;
+ if( size() == 0 )
+ return 1;
int i_count = 0;
- Iterator it = begin();
- while( it != end() )
+ for( Iterator it = m_children.begin(); it != m_children.end(); ++it )
{
i_count += it->countLeafs();
- ++it;
}
return i_count;
}
VarTree::Iterator VarTree::firstLeaf()
{
- Iterator b = root()->begin();
+ Iterator b = root()->m_children.begin();
if( b->size() ) return getNextLeaf( b );
return b;
}
-void VarTree::cascadeDelete()
-{
- m_deleted = true;
- for( Iterator it = begin(); it != end(); ++it )
- {
- it->cascadeDelete();
- }
-}
-
-int VarTree::getRank( const Iterator& item, bool flat )
+int VarTree::getIndex( const Iterator& item )
{
- int index = 1;
+ int index = 0;
Iterator it;
- for( it = flat ? firstLeaf() : begin();
- it != end();
- it = flat ? getNextLeaf( it ) : getNextVisibleItem( it ) )
+ for( it = m_flat ? firstLeaf() : m_children.begin();
+ it != m_children.end();
+ it = m_flat ? getNextLeaf( it ) : getNextVisibleItem( it ) )
{
- if( it->isDeleted() )
- continue;
if( it == item )
break;
index++;
}
return (it == item) ? index : -1;
}
+
+VarTree::Iterator VarTree::getItemFromSlider()
+{
+ // a simple (int)(...) causes rounding errors !
+#ifdef _MSC_VER
+# define lrint (int)
+#endif
+ VarPercent &rVarPos = getPositionVar();
+ double percentage = rVarPos.get();
+
+ int indexMax = m_flat ? (countLeafs() - 1)
+ : (visibleItems() - 1);
+
+ int index = lrint( (1.0 - percentage)*(double)indexMax );
+
+ Iterator it_first = m_flat ? getLeaf( index + 1 )
+ : getVisibleItem( index + 1 );
+ return it_first;
+}
+
+void VarTree::setSliderFromItem( const Iterator& it )
+{
+ VarPercent &rVarPos = getPositionVar();
+
+ int indexMax = m_flat ? (countLeafs() - 1)
+ : (visibleItems() - 1);
+
+ int index = getIndex( it );
+ double percentage = (1.0 - (double)index/(double)indexMax);
+
+ m_dontMove = true;
+ rVarPos.set( (float)percentage );
+ m_dontMove = false;
+}
+
+void VarTree::onUpdate( Subject<VarPercent> &rPercent, void* arg )
+{
+ (void)rPercent; (void)arg;
+ onUpdateSlider();
+}
+
+void VarTree::unselectTree()
+{
+ m_selected = false;
+ for( Iterator it = m_children.begin(); it != m_children.end(); ++it )
+ it->unselectTree();
+}
+
+VarTree::IteratorVisible VarTree::getItem( int index )
+{
+ Iterator it =
+ m_flat ? getLeaf( index + 1 )
+ : getVisibleItem( index + 1 );
+
+ return IteratorVisible( it, this );
+}
#define VAR_TREE_HPP
#include <list>
+#include <assert.h>
#include "variable.hpp"
#include "observer.hpp"
#include "ustring.hpp"
#include "var_percent.hpp"
-/// Description of an update to the tree
-typedef struct tree_update
-{
- enum type_t
- {
- UpdateItem,
- AppendItem,
- DeleteItem,
- ResetAll,
- };
-
- enum type_t type;
- int i_id;
- bool b_active_item;
-
-} tree_update;
+class VarTree;
+struct tree_update;
/// Tree variable
-class VarTree: public Variable, public Subject<VarTree, tree_update>
+class VarTree: public Variable,
+ public Subject<VarTree, tree_update>,
+ public Observer<VarPercent>
{
public:
VarTree( intf_thread_t *pIntf );
VarTree( intf_thread_t *pIntf, VarTree *pParent, int id,
const UStringPtr &rcString, bool selected, bool playing,
- bool expanded, bool readonly, void *pData );
+ bool expanded, bool readonly );
+ VarTree( const VarTree& );
virtual ~VarTree();
+ /// Iterators
+ typedef list<VarTree>::iterator Iterator;
+ typedef list<VarTree>::const_iterator ConstIterator;
+
/// 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( int id, const UStringPtr &rcString, bool selected,
- bool playing, bool expanded, bool readonly, void *pData );
+ virtual Iterator add( int id, const UStringPtr &rcString, bool selected,
+ bool playing, bool expanded, bool readonly, int pos = -1 );
/// Remove the selected item from the children's list
virtual void delSelected();
virtual void clear();
inline int getId() { return m_id; }
- inline void *getData() { return m_pData; }
inline UString* getString() {return (UString*)m_cString.get(); }
inline void setString( UStringPtr val ) { m_cString = val; }
inline bool isSelected() { return m_selected; };
inline bool isPlaying() { return m_playing; };
inline bool isExpanded() { return m_expanded; };
- inline bool isDeleted() { return m_deleted; };
+ inline bool isFlat() { return m_flat; };
inline void setSelected( bool val ) { m_selected = val; }
inline void setPlaying( bool val ) { m_playing = val; }
inline void setExpanded( bool val ) { m_expanded = val; }
- inline void setDeleted( bool val ) { m_deleted = val; }
+ inline void setFlat( bool val ) { m_flat = val; }
inline void toggleSelected() { m_selected = !m_selected; }
- inline void toggleExpanded() { m_expanded = !m_expanded; }
+ inline void toggleExpanded() { setExpanded( !m_expanded ); }
/// Get the number of children
int size() const { return m_children.size(); }
- /// Iterators
- typedef list<VarTree>::iterator Iterator;
- typedef list<VarTree>::const_iterator ConstIterator;
+ /// iterator over visible items
+ class IteratorVisible : public Iterator
+ {
+ public:
+ IteratorVisible( const VarTree::Iterator& it, VarTree* pRootTree )
+ : VarTree::Iterator( it ), m_pRootTree( pRootTree ) {}
+
+ IteratorVisible& operator++()
+ {
+ Iterator& it = *this;
+ assert( it != end() );
+ it = isFlat() ? m_pRootTree->getNextLeaf( it ) :
+ m_pRootTree->getNextVisibleItem( it );
+ return *this;
+ }
+
+ IteratorVisible& operator--()
+ {
+ Iterator& it = *this;
+ it = isFlat() ? m_pRootTree->getPrevLeaf( it ) :
+ m_pRootTree->getPrevVisibleItem( it );
+ return *this;
+ }
+
+ IteratorVisible getParent()
+ {
+ IteratorVisible& it = *this;
+ if( it->parent() && it->parent() != m_pRootTree )
+ {
+ return IteratorVisible( it->parent()->getSelf(), m_pRootTree );
+ }
+ return end();
+ }
+
+ private:
+ inline IteratorVisible begin() { return m_pRootTree->begin(); }
+ inline IteratorVisible end() { return m_pRootTree->end(); }
+ inline bool isFlat() { return m_pRootTree->m_flat; }
+ VarTree* m_pRootTree;
+ };
- /// Begining of the children's list
- Iterator begin() { return m_children.begin(); }
- ConstIterator begin() const { return m_children.begin(); }
+ /// Beginning of the children's list
+ IteratorVisible begin()
+ {
+ return IteratorVisible(
+ m_flat ? firstLeaf() : m_children.begin(), this );
+ }
/// End of children's list
- Iterator end() { return m_children.end(); }
- ConstIterator end() const { return m_children.end(); }
+ IteratorVisible end() { return IteratorVisible( m_children.end(), this ); }
/// Back of children's list
VarTree &back() { return m_children.back(); }
- /// Return an iterator on the n'th element of the children's list
- Iterator operator[]( int n );
- ConstIterator operator[]( int n ) const;
-
/// Parent node
VarTree *parent() { return m_pParent; }
/// Get next sibling
Iterator getNextSiblingOrUncle();
+ Iterator getPrevSiblingOrUncle();
+
+ Iterator getSelf()
+ {
+ assert( m_pParent );
+ Iterator it = m_pParent->m_children.begin();
+ for( ; &*it != this && it != m_pParent->m_children.end(); ++it );
+ assert( it != m_pParent->m_children.end() );
+ return it;
+ }
+
+ int getIndex()
+ {
+ if( m_pParent )
+ {
+ int i_pos = 0;
+ for( Iterator it = m_pParent->m_children.begin();
+ it != m_pParent->m_children.end(); ++it, i_pos++ )
+ if( &(*it) == this )
+ return i_pos;
+ }
+ return -1;
+ }
Iterator next_uncle();
Iterator prev_uncle();
void removeChild( Iterator it ) { m_children.erase( it ); }
/// Execute the action associated to this item
- virtual void action( VarTree *pItem ) { (void)pItem; }
+ virtual void action( VarTree *pItem ) { VLC_UNUSED(pItem); }
/// Get a reference on the position variable
VarPercent &getPositionVar() const
/// Given an iterator to an item, return the previous leaf
Iterator getPrevLeaf( Iterator it );
- /// return rank of visible item starting from 1
- int getRank( const Iterator& it, bool flat );
+ /// Given an iterator to an item, return the parent item
+ Iterator getParent( Iterator it );
- /// Find a children node with the given id
- Iterator findById( int id );
+ /// return index of visible item (starting from 0)
+ int getIndex( const Iterator& it );
/// Ensure an item is expanded
void ensureExpanded( const Iterator& it );
- /// flag a whole subtree for deletion
- void cascadeDelete();
+ ///
+ Iterator getItemFromSlider();
+ void setSliderFromItem( const Iterator& it );
+
+ ///
+ void onUpdate( Subject<VarPercent> &rPercent, void* arg);
/// Get depth (root depth is 0)
int depth()
return depth;
}
+ virtual void onUpdateSlider() {}
+
+ void unselectTree();
+
+ VarTree::IteratorVisible getItem( int index );
+
+protected:
+
+ /// List of children
+ list<VarTree> m_children;
+
private:
/// Get root node
return parent;
}
- /// List of children
- list<VarTree> m_children;
-
/// Pointer to parent node
VarTree *m_pParent;
int m_id;
- void *m_pData;
UStringPtr m_cString;
/// indicators
bool m_selected;
bool m_playing;
bool m_expanded;
- bool m_deleted;
+ bool m_flat;
+ bool m_dontMove;
/// Variable type
static const string m_type;
VariablePtr m_cPosition;
};
+/// Description of an update to the tree
+typedef struct tree_update
+{
+ enum type_t
+ {
+ ItemUpdated,
+ ItemInserted,
+ ItemDeleted,
+ DeletingItem,
+ ResetAll,
+ SliderChanged,
+ };
+ enum type_t type;
+ VarTree::IteratorVisible it;
+
+ tree_update( enum type_t t, VarTree::IteratorVisible item ) :
+ type( t ), it( item ) {}
+} tree_update;
+
#endif
*
* Authors: Antoine Cellerier <dionoea@videolan.org>
* Clément Stenac <zorglub@videolan.org>
+ * Erwan Tulou <erwan10@videolan.org>
*
* 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
#include "playtree.hpp"
#include <vlc_playlist.h>
+#include <vlc_url.h>
#include "../utils/ustring.hpp"
-Playtree::Playtree( intf_thread_t *pIntf ): VarTree( pIntf )
+Playtree::Playtree( intf_thread_t *pIntf )
+ : VarTree( pIntf ), m_pPlaylist( pIntf->p_sys->p_playlist )
{
- // Get the VLC playlist object
- m_pPlaylist = pIntf->p_sys->p_playlist;
-
+ getPositionVar().addObserver( this );
buildTree();
}
Playtree::~Playtree()
{
+ getPositionVar().delObserver( this );
}
void Playtree::delSelected()
{
- Iterator it = begin();
- playlist_Lock( getIntf()->p_sys->p_playlist );
- for( it = begin(); it != end(); it = getNextItem( it ) )
+ for( Iterator it = m_children.begin(); it != m_children.end(); )
{
if( it->isSelected() && !it->isReadonly() )
{
- it->cascadeDelete();
- }
- }
- /// \todo Do this better (handle item-deleted)
- tree_update descr;
- descr.type = tree_update::DeleteItem;
- notify( &descr );
- it = begin();
- while( it != end() )
- {
- if( it->isDeleted() )
- {
- VarTree::Iterator it2;
- playlist_item_t *p_item = (playlist_item_t *)(it->getData());
- if( p_item->i_children == -1 )
- {
- playlist_DeleteFromInput( getIntf()->p_sys->p_playlist,
- p_item->p_input, pl_Locked );
- it2 = getNextItem( it ) ;
- }
- else
+ playlist_Lock( m_pPlaylist );
+
+ playlist_item_t *pItem =
+ playlist_ItemGetById( m_pPlaylist, it->getId() );
+ if( pItem )
{
- playlist_NodeDelete( getIntf()->p_sys->p_playlist, p_item,
- true, false );
- it2 = it->getNextSiblingOrUncle();
+ if( pItem->i_children == -1 )
+ {
+ playlist_DeleteFromInput( m_pPlaylist, pItem->p_input,
+ pl_Locked );
+ }
+ else
+ {
+ playlist_NodeDelete( m_pPlaylist, pItem, true, false );
+ }
}
- it->parent()->removeChild( it );
- it = it2;
+ playlist_Unlock( m_pPlaylist );
+
+ it = it->getNextSiblingOrUncle();
}
else
{
it = getNextItem( it );
}
}
- playlist_Unlock( getIntf()->p_sys->p_playlist );
}
-void Playtree::action( VarTree *pItem )
+void Playtree::action( VarTree *pElem )
{
playlist_Lock( m_pPlaylist );
- VarTree::Iterator it;
- playlist_item_t *p_item = (playlist_item_t *)pItem->getData();
- playlist_item_t *p_parent = p_item;
- while( p_parent )
+ playlist_item_t *pItem =
+ playlist_ItemGetById( m_pPlaylist, pElem->getId() );
+ if( pItem )
{
- if( p_parent == m_pPlaylist->p_root_category )
- break;
- p_parent = p_parent->p_parent;
+ playlist_Control( m_pPlaylist, PLAYLIST_VIEWPLAY,
+ pl_Locked, pItem->p_parent, pItem );
}
- if( p_parent )
- {
- playlist_Control( m_pPlaylist, PLAYLIST_VIEWPLAY, pl_Locked, p_parent, p_item );
- }
playlist_Unlock( m_pPlaylist );
}
void Playtree::onChange()
{
buildTree();
- tree_update descr;
- descr.type = tree_update::ResetAll;
+ tree_update descr( tree_update::ResetAll, end() );
notify( &descr );
}
void Playtree::onUpdateItem( int id )
{
Iterator it = findById( id );
- if( it != end() )
+ if( it != m_children.end() )
{
// Update the item
- playlist_item_t* pNode = (playlist_item_t*)(it->getData());
+ playlist_Lock( m_pPlaylist );
+ playlist_item_t *pNode =
+ playlist_ItemGetById( m_pPlaylist, it->getId() );
+ if( !pNode )
+ {
+ playlist_Unlock( m_pPlaylist );
+ return;
+ }
+
UString *pName = new UString( getIntf(), pNode->p_input->psz_name );
- it->setString( UStringPtr( pName ) );
+ playlist_Unlock( m_pPlaylist );
- tree_update descr;
- descr.type = tree_update::UpdateItem;
- descr.i_id = id;
- descr.b_active_item = false;
- notify( &descr );
+ if( *pName != *(it->getString()) )
+ {
+ it->setString( UStringPtr( pName ) );
+
+ tree_update descr(
+ tree_update::ItemUpdated, IteratorVisible( it, this ) );
+ notify( &descr );
+ }
}
else
{
- msg_Warn(getIntf(), "cannot find node with id %d", id );
+ msg_Warn( getIntf(), "cannot find node with id %d", id );
}
}
void Playtree::onUpdateCurrent( bool b_active )
{
- for( VarTree::Iterator it = begin(); it != end(); it = getNextItem( it ) )
- {
- if( it->isPlaying() )
- {
- it->setPlaying( false );
-
- tree_update descr;
- descr.type = tree_update::UpdateItem;
- descr.i_id = it->getId();
- descr.b_active_item = false;
- notify( &descr );
- break;
- }
- }
-
if( b_active )
{
playlist_Lock( m_pPlaylist );
}
Iterator it = findById( current->i_id );
- if( it != end() )
+ if( it != m_children.end() )
+ {
it->setPlaying( true );
+ tree_update descr(
+ tree_update::ItemUpdated, IteratorVisible( it, this ) );
+ notify( &descr );
+ }
+
playlist_Unlock( m_pPlaylist );
+ }
+ else
+ {
+ for( Iterator it = m_children.begin(); it != m_children.end();
+ it = getNextItem( it ) )
+ {
+ if( it->isPlaying() )
+ {
+ it->setPlaying( false );
- tree_update descr;
- descr.type = tree_update::UpdateItem;
- descr.i_id = current->i_id;
- descr.b_active_item = true;
- notify( &descr );
+ tree_update descr(
+ tree_update::ItemUpdated, IteratorVisible( it, this ) );
+ notify( &descr );
+ break;
+ }
+ }
}
}
void Playtree::onDelete( int i_id )
{
- Iterator item = findById( i_id ) ;
- if( item != end() )
+ Iterator it = findById( i_id ) ;
+ if( it != m_children.end() )
{
- VarTree* parent = item->parent();
+ VarTree* parent = it->parent();
+ if( parent )
+ {
+ tree_update descr(
+ tree_update::DeletingItem, IteratorVisible( it, this ) );
+ notify( &descr );
- item->setDeleted( true );
+ parent->removeChild( it );
+ m_allItems.erase( i_id );
- tree_update descr;
- descr.type = tree_update::DeleteItem;
- descr.i_id = i_id;
- notify( &descr );
-
- if( parent )
- parent->removeChild( item );
+ tree_update descr2(
+ tree_update::ItemDeleted, end() );
+ notify( &descr2 );
+ }
}
}
void Playtree::onAppend( playlist_add_t *p_add )
{
- Iterator node = findById( p_add->i_node );
- if( node != end() )
+ Iterator it_node = findById( p_add->i_node );
+ if( it_node != m_children.end() )
{
playlist_Lock( m_pPlaylist );
- playlist_item_t *p_item =
+ playlist_item_t *pItem =
playlist_ItemGetById( m_pPlaylist, p_add->i_item );
- if( !p_item )
+ if( !pItem )
{
playlist_Unlock( m_pPlaylist );
return;
}
+ int pos;
+ for( pos = 0; pos < pItem->p_parent->i_children; pos++ )
+ if( pItem->p_parent->pp_children[pos] == pItem ) break;
+
UString *pName = new UString( getIntf(),
- p_item->p_input->psz_name );
- node->add( p_add->i_item, UStringPtr( pName ),
- false,false, false, p_item->i_flags & PLAYLIST_RO_FLAG,
- p_item );
+ pItem->p_input->psz_name );
+
+ playlist_item_t* current = playlist_CurrentPlayingItem( m_pPlaylist );
+
+ Iterator it = it_node->add(
+ p_add->i_item, UStringPtr( pName ), false, pItem == current,
+ false, pItem->i_flags & PLAYLIST_RO_FLAG, pos );
+
+ m_allItems[pItem->i_id] = &*it;
+
playlist_Unlock( m_pPlaylist );
- tree_update descr;
- descr.type = tree_update::AppendItem;
- descr.i_id = p_add->i_item;
+ tree_update descr(
+ tree_update::ItemInserted,
+ IteratorVisible( it, this ) );
notify( &descr );
}
}
void Playtree::buildNode( playlist_item_t *pNode, VarTree &rTree )
{
+ UString *pName = new UString( getIntf(), pNode->p_input->psz_name );
+ Iterator it = rTree.add(
+ pNode->i_id, UStringPtr( pName ), false,
+ playlist_CurrentPlayingItem(m_pPlaylist) == pNode,
+ false, pNode->i_flags & PLAYLIST_RO_FLAG );
+ m_allItems[pNode->i_id] = &*it;
+
for( int i = 0; i < pNode->i_children; i++ )
{
- UString *pName = new UString( getIntf(),
- pNode->pp_children[i]->p_input->psz_name );
- rTree.add(
- pNode->pp_children[i]->i_id, UStringPtr( pName ), false,
- playlist_CurrentPlayingItem(m_pPlaylist) == pNode->pp_children[i],
- false, pNode->pp_children[i]->i_flags & PLAYLIST_RO_FLAG,
- pNode->pp_children[i] );
- if( pNode->pp_children[i]->i_children > 0 )
- {
- buildNode( pNode->pp_children[i], rTree.back() );
- }
+ buildNode( pNode->pp_children[i], *it );
}
}
clear();
playlist_Lock( m_pPlaylist );
- clear();
+ for( int i = 0; i < m_pPlaylist->p_root->i_children; i++ )
+ {
+ buildNode( m_pPlaylist->p_root->pp_children[i], *this );
+ }
- /* TODO: Let user choose view - Stick with category ATM */
+ playlist_Unlock( m_pPlaylist );
+}
- /* Set the root's name */
- UString *pName = new UString( getIntf(),
- m_pPlaylist->p_root_category->p_input->psz_name );
- setString( UStringPtr( pName ) );
+void Playtree::onUpdateSlider()
+{
+ tree_update descr( tree_update::SliderChanged, end() );
+ notify( &descr );
+}
- buildNode( m_pPlaylist->p_root_category, *this );
+void Playtree::insertItems( VarTree& elem, const list<string>& files, bool start )
+{
+ bool first = true;
+ VarTree* p_elem = &elem;
+ playlist_item_t* p_node = NULL;
+ int i_pos = -1;
+
+ playlist_Lock( m_pPlaylist );
+ if( p_elem->getId() == m_pPlaylist->p_local_category->i_id )
+ {
+ p_node = m_pPlaylist->p_local_category;
+ i_pos = 0;
+ }
+ else if( p_elem->getId() == m_pPlaylist->p_ml_category->i_id )
+ {
+ p_node = m_pPlaylist->p_ml_category;
+ i_pos = 0;
+ }
+ else if( p_elem->size() )
+ {
+ p_node = playlist_ItemGetById( m_pPlaylist, p_elem->getId() );
+ i_pos = 0;
+ }
+ else
+ {
+ p_node = playlist_ItemGetById( m_pPlaylist,
+ p_elem->parent()->getId() );
+ i_pos = p_elem->getIndex();
+ i_pos++;
+ }
+
+ if( !p_node )
+ goto fin;
+
+ for( list<string>::const_iterator it = files.begin();
+ it != files.end(); ++it, i_pos++, first = false )
+ {
+ char* psz_uri = make_URI( it->c_str(), NULL );
+ if( !psz_uri )
+ continue;
+
+ input_item_t* pItem = input_item_New( m_pPlaylist, psz_uri, NULL );
+ if( pItem )
+ {
+ int i_mode = PLAYLIST_APPEND;
+ if( first && start )
+ i_mode |= PLAYLIST_GO;
+
+ playlist_NodeAddInput( m_pPlaylist, pItem, p_node,
+ i_mode, i_pos, pl_Locked );
+ }
+ free( psz_uri );
+ }
+
+fin:
playlist_Unlock( m_pPlaylist );
}
+VarTree::Iterator Playtree::findById( int id )
+{
+ map<int,VarTree*>::iterator it = m_allItems.find( id );
+ if( it == m_allItems.end() )
+ return m_children.end();
+ else
+ return it->second->getSelf();
+}
#include <vlc_playlist.h>
#include "../utils/var_tree.hpp"
+#include <map>
+
/// Variable for VLC playlist (new tree format)
class Playtree: public VarTree
{
/// Function called to notify playlist item delete
void onDelete( int );
+ ///
+ void onUpdateSlider();
+
+ ///
+ void insertItems( VarTree& item, const list<string>& files, bool start );
+
private:
/// VLC playlist object
playlist_t *m_pPlaylist;
+ ///
+ map< int, VarTree* > m_allItems;
+
/// Build the list from the VLC playlist
void buildTree();
+ /// Retrieve an iterator from playlist_item_t->id
+ Iterator findById( int id );
+
/// Update Node's children
void buildNode( playlist_item_t *p_node, VarTree &m_pNode );
};