From cb2ad9ec570fec13ea17a46a43518d8ef4ef84c1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Olivier=20Teuli=C3=A8re?= Date: Sat, 3 Sep 2005 15:17:57 +0000 Subject: [PATCH] * skins2 (tree playlist): - Fixed a selection bug in CtrlTree - Simplified some algorithms using helper methods - A few coding style fixes --- modules/gui/skins2/controls/ctrl_tree.cpp | 164 ++++++++++------------ modules/gui/skins2/controls/ctrl_tree.hpp | 9 +- modules/gui/skins2/utils/var_tree.cpp | 46 ++++-- modules/gui/skins2/utils/var_tree.hpp | 40 ++++-- 4 files changed, 149 insertions(+), 110 deletions(-) diff --git a/modules/gui/skins2/controls/ctrl_tree.cpp b/modules/gui/skins2/controls/ctrl_tree.cpp index 2e05f1ba43..67f683cef7 100644 --- a/modules/gui/skins2/controls/ctrl_tree.cpp +++ b/modules/gui/skins2/controls/ctrl_tree.cpp @@ -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 &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(); ) + // Invert the selection of the item + it = findItemAtPos( yPos ); + if( it != m_rTree.end() ) { - if( index == yPos ) - { - it->m_selected = !it->m_selected; - m_pLastSelected = &*it; - break; - } - index++; - IT_DISP_LOOP_END( it ); + it->m_selected = !it->m_selected; + m_pLastSelected = &*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,55 +393,41 @@ 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 = true; - m_pLastSelected = &*it; - } - else - { - it->m_selected = false; - } - index ++; - IT_DISP_LOOP_END( it ); + it->m_selected = false; + } + // Select the new item + it = findItemAtPos(yPos); + if( it != m_rTree.end() ) + { + it->m_selected = true; + m_pLastSelected = &*it; } } else if( rEvent.getAsString().find( "mouse:left:dblclick" ) != string::npos ) { - for( it = m_lastPos; it != m_rTree.end(); ) + it = findItemAtPos(yPos); + if( it != m_rTree.end() ) { - if( index == yPos ) + if( it->size() && xPos < it->depth() * itemImageWidth() ) { - if( it->size() && xPos < it->depth() * itemImageWidth() ) - { - it->m_expanded = !it->m_expanded; - } - else - { - it->m_selected = true; - m_pLastSelected = &*it; - // Execute the action associated to this item - m_rTree.action( &*it ); - } + it->m_expanded = !it->m_expanded; } else { - it->m_selected = false; + // Execute the action associated to this item + m_rTree.action( &*it ); } - index ++; - IT_DISP_LOOP_END( it ); } } @@ -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 { @@ -649,13 +622,28 @@ void CtrlTree::makeImage() ySrc = - yPos; yPos = 0; } - int lineHeight = __MIN( pText->getHeight() - ySrc, height - yPos ); + int lineHeight = __MIN( pText->getHeight() - ySrc, height - yPos ); m_pImage->drawBitmap( *pText, 0, ySrc, bitmapWidth * depth, yPos, pText->getWidth(), lineHeight, true ); 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; +} + diff --git a/modules/gui/skins2/controls/ctrl_tree.hpp b/modules/gui/skins2/controls/ctrl_tree.hpp index 6d262b607a..f4a39f2d47 100644 --- a/modules/gui/skins2/controls/ctrl_tree.hpp +++ b/modules/gui/skins2/controls/ctrl_tree.hpp @@ -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, /// 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 diff --git a/modules/gui/skins2/utils/var_tree.cpp b/modules/gui/skins2/utils/var_tree.cpp index c5e5caa7a0..12b7f707a6 100644 --- a/modules/gui/skins2/utils/var_tree.cpp +++ b/modules/gui/skins2/utils/var_tree.cpp @@ -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; +} + diff --git a/modules/gui/skins2/utils/var_tree.hpp b/modules/gui/skins2/utils/var_tree.hpp index 5d561765a0..39a1835842 100644 --- a/modules/gui/skins2/utils/var_tree.hpp +++ b/modules/gui/skins2/utils/var_tree.hpp @@ -35,14 +35,18 @@ class VarTree: public Variable, public Subject { 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,22 +84,35 @@ class VarTree: public Variable, public Subject /// 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 ) {} /// Get a reference on the position variable VarPercent &getPositionVar() const - { return *((VarPercent*)m_cPosition.get()); } + { return *((VarPercent*)m_cPosition.get()); } /// Get a counted pointer on the position variable const VariablePtr &getPositionVarPtr() const { return m_cPosition; } @@ -104,18 +121,21 @@ class VarTree: public Variable, public Subject 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 m_children; - ///Pointer to parent node + /// Pointer to parent node VarTree *m_pParent; - ///Variable type + /// Variable type static const string m_type; /// Position variable -- 2.39.5