From 0f968b65396064faf5bdd6da605ef95413a12824 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Cl=C3=A9ment=20Stenac?= Date: Sun, 12 Feb 2006 11:18:43 +0000 Subject: [PATCH] Playtree: handle delete nicely --- modules/gui/skins2/commands/cmd_vars.cpp | 7 +++ modules/gui/skins2/commands/cmd_vars.hpp | 20 +++++++ modules/gui/skins2/controls/ctrl_tree.cpp | 66 ++++++++++++++++------- modules/gui/skins2/src/vlcproc.cpp | 29 +++++++++- modules/gui/skins2/src/vlcproc.hpp | 6 +++ modules/gui/skins2/utils/var_tree.cpp | 30 +++++++++-- modules/gui/skins2/utils/var_tree.hpp | 18 ++++++- modules/gui/skins2/vars/playtree.cpp | 63 +++++++++++++++++----- modules/gui/skins2/vars/playtree.hpp | 3 ++ 9 files changed, 201 insertions(+), 41 deletions(-) diff --git a/modules/gui/skins2/commands/cmd_vars.cpp b/modules/gui/skins2/commands/cmd_vars.cpp index 33b4a35581..ce08f35813 100644 --- a/modules/gui/skins2/commands/cmd_vars.cpp +++ b/modules/gui/skins2/commands/cmd_vars.cpp @@ -71,6 +71,13 @@ void CmdPlaytreeAppend::execute() rVar.onAppend( m_pAdd ); } +void CmdPlaytreeDelete::execute() +{ + // Notify the playtree variable + Playtree &rVar = VlcProc::instance( getIntf() )->getPlaytreeVar(); + rVar.onDelete( m_id ); +} + void CmdSetText::execute() { // Change the text variable diff --git a/modules/gui/skins2/commands/cmd_vars.hpp b/modules/gui/skins2/commands/cmd_vars.hpp index ae93a80b26..608ee4e659 100644 --- a/modules/gui/skins2/commands/cmd_vars.hpp +++ b/modules/gui/skins2/commands/cmd_vars.hpp @@ -77,6 +77,26 @@ class CmdPlaytreeAppend: public CmdGeneric playlist_add_t * m_pAdd; }; +/// Command to notify the playtree of an item deletion +class CmdPlaytreeDelete: public CmdGeneric +{ + public: + CmdPlaytreeDelete( intf_thread_t *pIntf, int i_id ) : + CmdGeneric( pIntf ), m_id( i_id ) {} + virtual ~CmdPlaytreeDelete() {} + + /// This method does the real job of the command + virtual void execute(); + + /// Return the type of the command + virtual string getType() const { return "playtree append"; } + + private: + int m_id; +}; + + + /// Command to set a text variable class CmdSetText: public CmdGeneric diff --git a/modules/gui/skins2/controls/ctrl_tree.cpp b/modules/gui/skins2/controls/ctrl_tree.cpp index e7272b3960..86863a6c75 100644 --- a/modules/gui/skins2/controls/ctrl_tree.cpp +++ b/modules/gui/skins2/controls/ctrl_tree.cpp @@ -150,7 +150,22 @@ void CtrlTree::onUpdate( Subject &rTree, } else if ( arg->i_type == 2 ) // Item-append { - /// \todo Check if the item is really visible in the view (we only check if it in the document) + /// \todo Check if the item is really visible in the view + // (we only check if it in the document) + if( arg->b_visible == true ) + { + makeImage(); + } + } + else if( arg->i_type == 3 ) // item-del + { + /* Make sure firstPos and lastSelected are still valid */ + while( m_firstPos->m_deleted && m_firstPos != m_rTree.root()->begin() ) + { + m_firstPos = m_rTree.getPrevVisibleItem( m_firstPos ); + } + if( m_firstPos->m_deleted ) m_firstPos = m_rTree.root()->begin(); + if( arg->b_visible == true ) { makeImage(); @@ -453,27 +468,30 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent ) string::npos ) { it = findItemAtPos(yPos); - if( it->size() && xPos > (it->depth() - 1) * itemImageWidth() - && xPos < it->depth() * itemImageWidth() ) - { - // Fold/unfold the item - it->m_expanded = !it->m_expanded; - bChangedPosition = true; - } - else + if( it != m_rTree.end() ) { - // Unselect any previously selected item - VarTree::Iterator it2; - for( it2 = m_rTree.begin(); it2 != m_rTree.end(); - it2 = m_rTree.getNextVisibleItem( it2 ) ) + if( it->size() && xPos > (it->depth() - 1) * itemImageWidth() + && xPos < it->depth() * itemImageWidth() ) { - it2->m_selected = false; + // Fold/unfold the item + it->m_expanded = !it->m_expanded; + bChangedPosition = true; } - // Select the new item - if( it != m_rTree.end() ) + else { - it->m_selected = true; - m_pLastSelected = &*it; + // Unselect any previously selected item + VarTree::Iterator it2; + for( it2 = m_rTree.begin(); it2 != m_rTree.end(); + it2 = m_rTree.getNextVisibleItem( it2 ) ) + { + it2->m_selected = false; + } + // Select the new item + if( it != m_rTree.end() ) + { + it->m_selected = true; + m_pLastSelected = &*it; + } } } } @@ -666,7 +684,10 @@ void CtrlTree::makeImage() m_pImage->fillRect( 0, yPos, width, rectHeight, m_selColor ); } - it = m_rTree.getNextVisibleItem( it ); + do + { + it = m_rTree.getNextVisibleItem( it ); + } while( it->m_deleted ); } } } @@ -683,7 +704,10 @@ void CtrlTree::makeImage() { uint32_t color = ( it->m_selected ? m_selColor : bgColor ); m_pImage->fillRect( 0, yPos, width, rectHeight, color ); - it = m_rTree.getNextVisibleItem( it ); + do + { + it = m_rTree.getNextVisibleItem( it ); + } while( it->m_deleted ); } else { @@ -746,7 +770,9 @@ void CtrlTree::makeImage() yPos += (pText->getHeight() - ySrc ); delete pText; } + do { it = m_rTree.getNextVisibleItem( it ); + } while( it->m_deleted ); } } diff --git a/modules/gui/skins2/src/vlcproc.cpp b/modules/gui/skins2/src/vlcproc.cpp index 5def1429fb..ee0840c28b 100644 --- a/modules/gui/skins2/src/vlcproc.cpp +++ b/modules/gui/skins2/src/vlcproc.cpp @@ -128,7 +128,7 @@ VlcProc::VlcProc( intf_thread_t *pIntf ): SkinObject( pIntf ), // Called when a playlist item is deleted // TODO: properly handle item-deleted var_AddCallback( pIntf->p_sys->p_playlist, "item-deleted", - onIntfChange, this ); + onItemDelete, this ); // Called when the "interface shower" wants us to show the skin var_AddCallback( pIntf->p_sys->p_playlist, "intf-show", onIntfShow, this ); @@ -174,7 +174,7 @@ VlcProc::~VlcProc() var_DelCallback( getIntf()->p_sys->p_playlist, "item-append", onItemAppend, this ); var_DelCallback( getIntf()->p_sys->p_playlist, "item-deleted", - onIntfChange, this ); + onItemDelete, this ); var_DelCallback( getIntf()->p_sys->p_playlist, "intf-show", onIntfShow, this ); var_DelCallback( getIntf()->p_sys->p_playlist, "playlist-current", @@ -443,6 +443,31 @@ int VlcProc::onItemAppend( vlc_object_t *pObj, const char *pVariable, return VLC_SUCCESS; } +int VlcProc::onItemDelete( vlc_object_t *pObj, const char *pVariable, + vlc_value_t oldVal, vlc_value_t newVal, + void *pParam ) +{ + VlcProc *pThis = (VlcProc*)pParam; + + int i_id = newVal.i_int; + + CmdGenericPtr ptrTree; + CmdPlaytreeDelete *pCmdTree = new CmdPlaytreeDelete( pThis->getIntf(), + i_id); + ptrTree = CmdGenericPtr( pCmdTree ); + + // Create a playlist notify command (for old style playlist) + CmdNotifyPlaylist *pCmd = new CmdNotifyPlaylist( pThis->getIntf() ); + + // Push the command in the asynchronous command queue + AsyncQueue *pQueue = AsyncQueue::instance( pThis->getIntf() ); + pQueue->push( CmdGenericPtr( pCmd ) ); + pQueue->push( ptrTree , false ); + + return VLC_SUCCESS; +} + + int VlcProc::onPlaylistChange( vlc_object_t *pObj, const char *pVariable, diff --git a/modules/gui/skins2/src/vlcproc.hpp b/modules/gui/skins2/src/vlcproc.hpp index 9b65fc8927..363b23343c 100644 --- a/modules/gui/skins2/src/vlcproc.hpp +++ b/modules/gui/skins2/src/vlcproc.hpp @@ -173,6 +173,12 @@ class VlcProc: public SkinObject vlc_value_t oldVal, vlc_value_t newVal, void *pParam ); + /// Callback for item-change variable + static int onItemDelete( vlc_object_t *pObj, const char *pVariable, + vlc_value_t oldVal, vlc_value_t newVal, + void *pParam ); + + /// Callback for playlist-current variable static int onPlaylistChange( vlc_object_t *pObj, const char *pVariable, vlc_value_t oldVal, vlc_value_t newVal, diff --git a/modules/gui/skins2/utils/var_tree.cpp b/modules/gui/skins2/utils/var_tree.cpp index e6d8c1159f..230c187c76 100644 --- a/modules/gui/skins2/utils/var_tree.cpp +++ b/modules/gui/skins2/utils/var_tree.cpp @@ -28,7 +28,8 @@ const string VarTree::m_type = "tree"; VarTree::VarTree( intf_thread_t *pIntf ) : Variable( pIntf ), m_id( 0 ), m_selected( false ), m_playing( false ), - m_expanded( false ), m_pData( NULL ), m_pParent( NULL ) + m_expanded( false ), m_deleted( false ), m_readonly( false), + m_pData( NULL ), m_pParent( NULL ) { // Create the position variable m_cPosition = VariablePtr( new VarPercent( pIntf ) ); @@ -37,11 +38,14 @@ VarTree::VarTree( intf_thread_t *pIntf ) VarTree::VarTree( intf_thread_t *pIntf, VarTree *pParent, int id, const UStringPtr &rcString, bool selected, bool playing, - bool expanded, void *pData ) + bool expanded, bool readonly, + void *pData ) : Variable( pIntf ), m_id( id ), m_cString( rcString ), m_selected( selected ), m_playing( playing ), m_expanded( expanded ), + m_deleted( false ), m_readonly( readonly ), m_pData( pData ), m_pParent( pParent ) { + fprintf( stderr, "Expanded is %i - RO %i\n", m_expanded, m_readonly ); // Create the position variable m_cPosition = VariablePtr( new VarPercent( pIntf ) ); getPositionVar().set( 1.0 ); @@ -53,10 +57,12 @@ VarTree::~VarTree() } void VarTree::add( int id, const UStringPtr &rcString, bool selected, - bool playing, bool expanded, void *pData ) + bool playing, bool expanded, bool readonly, + void *pData ) { m_children.push_back( VarTree( getIntf(), this, id, rcString, selected, - playing, expanded, pData ) ); + playing, expanded, readonly, + pData ) ); } void VarTree::delSelected() @@ -105,6 +111,22 @@ VarTree::ConstIterator VarTree::operator[]( int n ) const return it; } +VarTree::Iterator VarTree::getNextSibling( VarTree::Iterator current ) +{ + VarTree *p_parent = current->parent(); + if( p_parent && current != p_parent->end() ) + { + Iterator it = current->parent()->begin(); + while( it != p_parent->end() && it != current ) it++; + if( it != p_parent->end() ) + { + it++; + } + return root()->end(); + } + return root()->end(); +} + /* find iterator to next ancestor * ... which means parent++ or grandparent++ or grandgrandparent++ ... */ VarTree::Iterator VarTree::next_uncle() diff --git a/modules/gui/skins2/utils/var_tree.hpp b/modules/gui/skins2/utils/var_tree.hpp index 96cd19bf12..ef2cd4ff29 100644 --- a/modules/gui/skins2/utils/var_tree.hpp +++ b/modules/gui/skins2/utils/var_tree.hpp @@ -49,7 +49,7 @@ class VarTree: public Variable, public Subject VarTree( intf_thread_t *pIntf, VarTree *pParent, int id, const UStringPtr &rcString, bool selected, bool playing, - bool expanded, void *pData ); + bool expanded,bool readonly, void *pData ); virtual ~VarTree(); @@ -58,7 +58,8 @@ class VarTree: public Variable, public Subject /// Add a pointer on string in the children's list virtual void add( int id, const UStringPtr &rcString, bool selected, - bool playing, bool expanded, void *pData ); + bool playing, bool expanded, bool readonly, + void *pData ); /// Remove the selected item from the children's list virtual void delSelected(); @@ -72,8 +73,11 @@ class VarTree: public Variable, public Subject bool m_selected; bool m_playing; bool m_expanded; + bool m_deleted; void *m_pData; + inline bool isReadonly() { return m_readonly; }; + /// Get the number of children int size() const { return m_children.size(); } @@ -100,6 +104,9 @@ class VarTree: public Variable, public Subject VarTree *parent() { return m_pParent; } void checkParents( VarTree *pParent ); + /// Get next sibling + Iterator getNextSibling( Iterator ); + Iterator next_uncle(); Iterator prev_uncle(); @@ -122,6 +129,11 @@ class VarTree: public Variable, public Subject return depth; } + void removeChild( VarTree::Iterator item ) + { + m_children.erase( item ); + } + /// Execute the action associated to this item virtual void action( VarTree *pItem ) {} @@ -160,6 +172,8 @@ class VarTree: public Variable, public Subject /// Pointer to parent node VarTree *m_pParent; + bool m_readonly; + /// Variable type static const string m_type; diff --git a/modules/gui/skins2/vars/playtree.cpp b/modules/gui/skins2/vars/playtree.cpp index 2ba159e7d4..3b3b9225c9 100644 --- a/modules/gui/skins2/vars/playtree.cpp +++ b/modules/gui/skins2/vars/playtree.cpp @@ -58,31 +58,49 @@ Playtree::~Playtree() void Playtree::delSelected() { - Iterator it; - for (it = begin(); it != end() ; it = getNextVisibleItem( it ) ) + Iterator it = begin(); + vlc_mutex_lock( &getIntf()->p_sys->p_playlist->object_lock ); + for( it = begin(); it != end(); it = getNextVisibleItem( it ) ) { - if( (*it).m_selected ) + if( (*it).m_selected && !(*it).isReadonly() ) { + (*it).m_deleted = true; + } + } + /// \todo Do this better (handle item-deleted) + tree_update descr; + descr.i_type = 3; + notify( &descr ); + it = begin(); + while( it != end() ) + { + if( (*it).m_deleted ) + { + VarTree::Iterator it2; playlist_item_t *p_item = (playlist_item_t *)(it->m_pData); if( p_item->i_children == -1 ) { - playlist_LockDelete( getIntf()->p_sys->p_playlist, + playlist_Delete( getIntf()->p_sys->p_playlist, p_item->input.i_id ); + it2 = getNextVisibleItem( it ) ; + it->parent()->removeChild( it ); + it = it2; } else { - vlc_mutex_lock( &getIntf()->p_sys->p_playlist->object_lock ); playlist_NodeDelete( getIntf()->p_sys->p_playlist, p_item, VLC_TRUE, VLC_FALSE ); - vlc_mutex_unlock( &getIntf()->p_sys->p_playlist->object_lock ); + it2 = getNextSibling( it ); + it->parent()->removeChild( it ); + it = it2; } } + else + { + it = getNextVisibleItem( it ); + } } - /// \todo Do this better (handle item-deleted) - buildTree(); - tree_update descr; - descr.i_type = 1; - notify( &descr ); + vlc_mutex_unlock( &getIntf()->p_sys->p_playlist->object_lock ); } void Playtree::action( VarTree *pItem ) @@ -137,6 +155,23 @@ void Playtree::onUpdateItem( int id ) notify( &descr ); } +/// \todo keep a list of "recently removed" to avoid looking up if we +// already removed it +void Playtree::onDelete( int i_id ) +{ + tree_update descr; + descr.i_id = i_id; + descr.i_type = 3; + Iterator item = findById( i_id ) ; + if( item != end() ) + { + if( item->parent() ) + item->parent()->removeChild( item ); + descr.b_visible = item->parent() ? true : item->parent()->m_expanded; + notify( &descr ); + } +} + void Playtree::onAppend( playlist_add_t *p_add ) { i_items_to_append --; @@ -152,7 +187,8 @@ void Playtree::onAppend( playlist_add_t *p_add ) if( !p_item ) return; UString *pName = new UString( getIntf(), p_item->input.psz_name ); node->add( p_add->i_item, UStringPtr( pName ), - false,false, false, p_item ); + false,false, false, p_item->i_flags & PLAYLIST_RO_FLAG, + p_item ); } } tree_update descr; @@ -172,7 +208,8 @@ void Playtree::buildNode( playlist_item_t *pNode, VarTree &rTree ) rTree.add( pNode->pp_children[i]->input.i_id, UStringPtr( pName ), false, m_pPlaylist->status.p_item == pNode->pp_children[i], - false, 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 ) { buildNode( pNode->pp_children[i], rTree.back() ); diff --git a/modules/gui/skins2/vars/playtree.hpp b/modules/gui/skins2/vars/playtree.hpp index 294c72623c..4e390099c7 100644 --- a/modules/gui/skins2/vars/playtree.hpp +++ b/modules/gui/skins2/vars/playtree.hpp @@ -48,6 +48,9 @@ class Playtree: public VarTree /// Function called to notify playlist item append void onAppend( playlist_add_t * ); + /// Function called to notify playlist item delete + void onDelete( int ); + /// Items waiting to be appended int i_items_to_append; -- 2.39.2