]> git.sesse.net Git - vlc/blobdiff - modules/gui/skins2/controls/ctrl_tree.cpp
skins2: fix arrows short of 1
[vlc] / modules / gui / skins2 / controls / ctrl_tree.cpp
index bd8aa8179d7503ac1716f719d3324ace4b9e44c9..b8be9b453f9cf4f8f7cb7b31d7e42392265cc0b4 100644 (file)
@@ -1,10 +1,11 @@
 /*****************************************************************************
  * ctrl_tree.cpp
  *****************************************************************************
- * Copyright (C) 2003 VideoLAN
+ * Copyright (C) 2003 the VideoLAN team
  * $Id$
  *
  * Authors: Antoine Cellerier <dionoea@videolan.org>
+ *          ClĂ©ment Stenac <zorglub@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
@@ -22,6 +23,7 @@
  *****************************************************************************/
 
 #include <math.h>
+#include "../utils/var_bool.hpp"
 #include "ctrl_tree.hpp"
 #include "../src/os_factory.hpp"
 #include "../src/os_graphics.hpp"
 #include "../events/evt_key.hpp"
 #include "../events/evt_mouse.hpp"
 #include "../events/evt_scroll.hpp"
-#include "vlc_keys.h"
-#ifdef sun
-#   include "solaris_specific.h" // for lrint
-#endif
+#include <vlc_keys.h>
 
 #define SCROLL_STEP 0.05
 #define LINE_INTERVAL 1  // Number of pixels inserted between 2 lines
@@ -55,7 +54,8 @@ CtrlTree::CtrlTree( intf_thread_t *pIntf,
                     uint32_t bgColor2,
                     uint32_t selColor,
                     const UString &rHelp,
-                    VarBool *pVisible ):
+                    VarBool *pVisible,
+                    VarBool *pFlat ):
     CtrlGeneric( pIntf,rHelp, pVisible), m_rTree( rTree), m_rFont( rFont ),
     m_pBgBitmap( pBgBitmap ), m_pItemBitmap( pItemBitmap ),
     m_pOpenBitmap( pOpenBitmap ), m_pClosedBitmap( pClosedBitmap ),
@@ -67,7 +67,9 @@ CtrlTree::CtrlTree( intf_thread_t *pIntf,
     m_rTree.addObserver( this );
     m_rTree.getPositionVar().addObserver( this );
 
-    m_firstPos = m_rTree.begin();
+    m_flat = pFlat->get();
+
+    m_firstPos = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
 
     makeImage();
 }
@@ -76,22 +78,22 @@ CtrlTree::~CtrlTree()
 {
     m_rTree.getPositionVar().delObserver( this );
     m_rTree.delObserver( this );
-    if( m_pImage )
-    {
-        delete m_pImage;
-    }
+    delete m_pImage;
 }
 
 int CtrlTree::itemHeight()
 {
     int itemHeight = m_rFont.getSize();
-    if( m_pClosedBitmap )
-    {
-        itemHeight = __MAX( m_pClosedBitmap->getHeight(), itemHeight );
-    }
-    if( m_pOpenBitmap )
+    if( !m_flat )
     {
-        itemHeight = __MAX( m_pOpenBitmap->getHeight(), itemHeight );
+        if( m_pClosedBitmap )
+        {
+            itemHeight = __MAX( m_pClosedBitmap->getHeight(), itemHeight );
+        }
+        if( m_pOpenBitmap )
+        {
+            itemHeight = __MAX( m_pOpenBitmap->getHeight(), itemHeight );
+        }
     }
     if( m_pItemBitmap )
     {
@@ -104,13 +106,16 @@ int CtrlTree::itemHeight()
 int CtrlTree::itemImageWidth()
 {
     int bitmapWidth = 5;
-    if( m_pClosedBitmap )
-    {
-        bitmapWidth = __MAX( m_pClosedBitmap->getWidth(), bitmapWidth );
-    }
-    if( m_pOpenBitmap )
+    if( !m_flat )
     {
-        bitmapWidth = __MAX( m_pOpenBitmap->getWidth(), bitmapWidth );
+        if( m_pClosedBitmap )
+        {
+            bitmapWidth = __MAX( m_pClosedBitmap->getWidth(), bitmapWidth );
+        }
+        if( m_pOpenBitmap )
+        {
+            bitmapWidth = __MAX( m_pOpenBitmap->getWidth(), bitmapWidth );
+        }
     }
     if( m_pItemBitmap )
     {
@@ -130,9 +135,11 @@ int CtrlTree::maxItems()
 }
 
 
-void CtrlTree::onUpdate( Subject<VarTree, tree_update*> &rTree,
+void CtrlTree::onUpdate( Subject<VarTree, tree_update> &rTree,
                          tree_update *arg )
 {
+    m_firstPos = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
+
     if( arg->i_type == 0 ) // Item update
     {
         if( arg->b_active_item )
@@ -145,11 +152,12 @@ void CtrlTree::onUpdate( Subject<VarTree, tree_update*> &rTree,
     /// \todo handle delete in a more clever way
     else if ( arg->i_type == 1 ) // Global change or deletion
     {
-        m_firstPos = m_rTree.begin();
         makeImage();
     }
     else if ( arg->i_type == 2 ) // Item-append
     {
+        if( m_flat && m_firstPos->size() )
+            m_firstPos = m_rTree.getNextLeaf( m_firstPos );
         /// \todo Check if the item is really visible in the view
         // (we only check if it in the document)
         if( arg->b_visible == true )
@@ -162,9 +170,12 @@ void CtrlTree::onUpdate( Subject<VarTree, tree_update*> &rTree,
         /* 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 );
+            m_firstPos = m_flat ? m_rTree.getPrevLeaf( m_firstPos )
+                                : m_rTree.getPrevVisibleItem( m_firstPos );
         }
-        if( m_firstPos->m_deleted ) m_firstPos = m_rTree.root()->begin();
+        if( m_firstPos->m_deleted )
+            m_firstPos = m_flat ? m_rTree.firstLeaf()
+                                : m_rTree.root()->begin();
 
         if( arg->b_visible == true )
         {
@@ -174,14 +185,18 @@ void CtrlTree::onUpdate( Subject<VarTree, tree_update*> &rTree,
     notifyLayout();
 }
 
-void CtrlTree::onUpdate( Subject<VarPercent, void*> &rPercent, void* arg)
+void CtrlTree::onUpdate( Subject<VarPercent> &rPercent, void* arg)
 {
     // Determine what is the first item to display
-    VarTree::Iterator it = m_rTree.begin();
+    VarTree::Iterator it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
 
     if( m_dontMove ) return;
 
-    int excessItems = m_rTree.visibleItems() - maxItems();
+    int excessItems;
+    if( m_flat )
+        excessItems = m_rTree.countLeafs() - maxItems();
+    else
+        excessItems = m_rTree.visibleItems() - maxItems();
 
     if( excessItems > 0)
     {
@@ -190,7 +205,10 @@ void CtrlTree::onUpdate( Subject<VarPercent, void*> &rPercent, void* arg)
 #ifdef _MSC_VER
 #   define lrint (int)
 #endif
-        it = m_rTree.getVisibleItem(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1);
+        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_firstPos != it )
     {
@@ -204,9 +222,13 @@ void CtrlTree::onUpdate( Subject<VarPercent, void*> &rPercent, void* arg)
 void CtrlTree::onResize()
 {
     // Determine what is the first item to display
-    VarTree::Iterator it = m_rTree.begin();
+    VarTree::Iterator it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
 
-    int excessItems = m_rTree.visibleItems() - maxItems();
+    int excessItems;
+    if( m_flat )
+        excessItems = m_rTree.countLeafs() - maxItems();
+    else
+        excessItems = m_rTree.visibleItems() - maxItems();
 
     if( excessItems > 0)
     {
@@ -215,18 +237,19 @@ void CtrlTree::onResize()
 #ifdef _MSC_VER
 #   define lrint (int)
 #endif
-        it = m_rTree.getVisibleItem(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1);
+        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();
-    notifyLayout();
 }
 
 void CtrlTree::onPositionChange()
 {
     makeImage();
-    notifyLayout();
 }
 
 void CtrlTree::handleEvent( EvtGeneric &rEvent )
@@ -242,7 +265,28 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
         /* 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->m_selected ) it_sel = it;
+            }
+
+            /* Delete selected stuff */
             m_rTree.delSelected();
+
+            /* Select it_sel */
+            it_sel->m_selected = true;
+            m_pLastSelected = &*it_sel;
+
+            // Redraw the control
+            makeImage();
+            notifyLayout();
         }
         else if( key == KEY_PAGEDOWN )
         {
@@ -251,7 +295,8 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
             while( i >= 0 )
             {
                 VarTree::Iterator it_old = it;
-                it = m_rTree.getNextVisibleItem( it );
+                it = m_flat ? m_rTree.getNextLeaf( it )
+                            : m_rTree.getNextVisibleItem( it );
                 /* End is already visible, dont' scroll */
                 if( it == m_rTree.end() )
                 {
@@ -266,7 +311,6 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
                 ensureVisible( it );
                 makeImage();
                 notifyLayout();
-                return;
             }
         }
         else if (key == KEY_PAGEUP )
@@ -275,9 +319,10 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
             int i = maxItems();
             while( i >= maxItems()/2 )
             {
-                it = m_rTree.getPrevVisibleItem( it );
+                it = m_flat ? m_rTree.getPrevLeaf( it )
+                            : m_rTree.getPrevVisibleItem( it );
                 /* End is already visible, dont' scroll */
-                if( it == m_rTree.begin() )
+                if( it == ( m_flat ? m_rTree.firstLeaf() : m_rTree.begin() ) )
                 {
                     break;
                 }
@@ -286,111 +331,135 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
             ensureVisible( it );
             makeImage();
             notifyLayout();
-            return;
         }
-
-
-        for( it = m_rTree.begin(); it != m_rTree.end();
-             it = m_rTree.getNextVisibleItem( it ) )
+        else if ( key == KEY_UP ||
+                  key == KEY_DOWN ||
+                  key == KEY_LEFT ||
+                  key == KEY_RIGHT ||
+                  key == KEY_ENTER ||
+                  key == ' ' )
         {
-            VarTree::Iterator next = m_rTree.getNextVisibleItem( it );
-            if( key == KEY_UP )
+            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 ) )
             {
-                // Scroll up one item
-                if( ( it->parent()
-                      && it != it->parent()->begin() )
-                    || &*it != m_pLastSelected )
+                VarTree::Iterator next = m_flat ?
+                                         m_rTree.getNextLeaf( it ) :
+                                         m_rTree.getNextVisibleItem( it );
+                if( key == KEY_UP )
                 {
-                    bool nextWasSelected = ( &*next == m_pLastSelected );
-                    it->m_selected = nextWasSelected;
-                    if( nextWasSelected )
+                    // Scroll up one item
+                    if( ( it->parent()
+                          && it != it->parent()->begin() )
+                        || &*it != m_pLastSelected )
                     {
-                        m_pLastSelected = &*it;
-                        needShow = true; toShow = it;
+                        bool nextWasSelected = ( &*next == m_pLastSelected );
+                        it->m_selected = nextWasSelected;
+                        if( nextWasSelected )
+                        {
+                            m_pLastSelected = &*it;
+                            needShow = true; toShow = it;
+                        }
                     }
                 }
-            }
-            else if( key == KEY_DOWN )
-            {
-                // Scroll down one item
-                if( ( it->parent()
-                      && next != it->parent()->end() )
-                    || &*it != m_pLastSelected )
-                {
-                    (*it).m_selected = previousWasSelected;
-                }
-                if( previousWasSelected )
-                {
-                    m_pLastSelected = &*it;
-                    needShow = true; toShow = it;
-                    previousWasSelected = false;
-                }
-                else
+                else if( key == KEY_DOWN )
                 {
-                    previousWasSelected = ( &*it == m_pLastSelected );
+                    // Scroll down one item
+                    if( ( it->parent()
+                          && next != it->parent()->end() )
+                        || &*it != m_pLastSelected )
+                    {
+                        (*it).m_selected = previousWasSelected;
+                    }
+                    if( previousWasSelected )
+                    {
+                        m_pLastSelected = &*it;
+                        needShow = true; toShow = it;
+                        previousWasSelected = false;
+                    }
+                    else
+                    {
+                        previousWasSelected = ( &*it == m_pLastSelected );
+                    }
+
+                    // Fix last tree item selection
+                    if( ( m_flat ? m_rTree.getNextLeaf( it )
+                        : m_rTree.getNextVisibleItem( it ) ) == m_rTree.end()
+                     && &*it == m_pLastSelected )
+                    {
+                        (*it).m_selected = true;
+                    }
                 }
-            }
-            else if( key == KEY_RIGHT )
-            {
-                // Go down one level (and expand node)
-                if( &*it == m_pLastSelected )
+                else if( key == KEY_RIGHT )
                 {
-                    if( it->m_expanded )
+                    // Go down one level (and expand node)
+                    if( &*it == m_pLastSelected )
                     {
-                        if( it->size() )
+                        if( it->m_expanded )
                         {
-                            it->m_selected = false;
-                            it->begin()->m_selected = true;
-                            m_pLastSelected = &*(it->begin());
+                            if( it->size() )
+                            {
+                                it->m_selected = false;
+                                it->begin()->m_selected = true;
+                                m_pLastSelected = &*(it->begin());
+                            }
+                            else
+                            {
+                                m_rTree.action( &*it );
+                            }
                         }
                         else
                         {
-                            m_rTree.action( &*it );
+                            it->m_expanded = true;
+                            bChangedPosition = true;
                         }
                     }
-                    else
-                    {
-                        it->m_expanded = true;
-                        bChangedPosition = true;
-                    }
                 }
-            }
-            else if( key == KEY_LEFT )
-            {
-                // Go up one level (and close node)
-                if( &*it == m_pLastSelected )
+                else if( key == KEY_LEFT )
                 {
-                    if( it->m_expanded && it->size() )
-                    {
-                        it->m_expanded = false;
-                        bChangedPosition = true;
-                    }
-                    else
+                    // Go up one level (and close node)
+                    if( &*it == m_pLastSelected )
                     {
-                        if( it->parent() && it->parent() != &m_rTree)
+                        if( it->m_expanded && it->size() )
                         {
-                            it->m_selected = false;
-                            m_pLastSelected = it->parent();
-                            m_pLastSelected->m_selected = true;
+                            it->m_expanded = false;
+                            bChangedPosition = true;
+                        }
+                        else
+                        {
+                            if( it->parent() && it->parent() != &m_rTree)
+                            {
+                                it->m_selected = false;
+                                m_pLastSelected = it->parent();
+                                m_pLastSelected->m_selected = true;
+                            }
                         }
                     }
                 }
-            }
-            else if( key == KEY_ENTER || key == KEY_SPACE )
-            {
-                // Go up one level (and close node)
-                if( &*it == m_pLastSelected )
+                else if( key == KEY_ENTER || key == ' ' )
                 {
-                    m_rTree.action( &*it );
+                    // 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
+        {
+            // other keys to be forwarded to vlc core
+            EvtKey& rEvtKey = (EvtKey&)rEvent;
+            var_SetInteger( getIntf()->p_libvlc, "key-pressed",
+                            rEvtKey.getModKey() );
         }
-        if( needShow )
-            ensureVisible( toShow );
 
-        // Redraw the control
-        makeImage();
-        notifyLayout();
     }
 
     else if( rEvent.getAsString().find( "mouse:left" ) != string::npos )
@@ -407,8 +476,10 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
             VarTree::Iterator itClicked = findItemAtPos( yPos );
             // Flag to know if the current item must be selected
             bool select = false;
-            for( it = m_rTree.begin(); it != m_rTree.end();
-                 it = m_rTree.getNextVisibleItem( it ) )
+            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 ) )
             {
                 bool nextSelect = select;
                 if( it == itClicked || &*it == m_pLastSelected )
@@ -444,8 +515,10 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
             VarTree::Iterator itClicked = findItemAtPos( yPos );
             // Flag to know if the current item must be selected
             bool select = false;
-            for( it = m_rTree.begin(); it != m_rTree.end();
-                 it = m_rTree.getNextVisibleItem( it ) )
+            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 ) )
             {
                 bool nextSelect = select;
                 if( it == itClicked || &*it == m_pLastSelected )
@@ -470,8 +543,9 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
             it = findItemAtPos(yPos);
             if( it != m_rTree.end() )
             {
-                if( it->size() && xPos > (it->depth() - 1) * itemImageWidth()
-                    && xPos < it->depth() * itemImageWidth() )
+                if( ( it->size() && xPos > (it->depth() - 1) * itemImageWidth()
+                      && xPos < it->depth() * itemImageWidth() )
+                 && !m_flat )
                 {
                     // Fold/unfold the item
                     it->m_expanded = !it->m_expanded;
@@ -481,8 +555,10 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
                 {
                     // Unselect any previously selected item
                     VarTree::Iterator it2;
-                    for( it2 = m_rTree.begin(); it2 != m_rTree.end();
-                         it2 = m_rTree.getNextVisibleItem( 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->m_selected = false;
                     }
@@ -513,10 +589,14 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
 
     else if( rEvent.getAsString().find( "scroll" ) != string::npos )
     {
-        int direction = ((EvtScroll&)rEvent).getDirection();
+        // 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_rTree.visibleItems();
+        double step = 2.0 / (double)( m_flat ? m_rTree.countLeafs()
+                                             : m_rTree.visibleItems() );
         if( direction == EvtScroll::kUp )
         {
             percentage += step;
@@ -534,8 +614,10 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
         VarTree::Iterator it;
         int i = 0;
         int iFirst = 0;
-        for( it = m_rTree.begin(); it != m_rTree.end();
-             it = m_rTree.getNextVisibleItem( it ) )
+        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 ) )
         {
             i++;
             if( it == m_firstPos )
@@ -545,8 +627,10 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
             }
         }
         iFirst += maxItems();
-        if( iFirst >= m_rTree.visibleItems() ) iFirst = m_rTree.visibleItems();
-        float f_new = (float)iFirst / (float)m_rTree.visibleItems();
+        if( iFirst >= (m_flat ? m_rTree.countLeafs() : m_rTree.visibleItems()) )
+            iFirst = m_flat ? m_rTree.countLeafs() : m_rTree.visibleItems();
+        float f_new = (float)iFirst / (float)( m_flat ? m_rTree.countLeafs()
+                                                      :m_rTree.visibleItems() );
         m_dontMove = true;
         m_rTree.getPositionVar().set( 1.0 - f_new );
         m_dontMove = false;
@@ -556,17 +640,23 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
 bool CtrlTree::mouseOver( int x, int y ) const
 {
     const Position *pPos = getPosition();
-    return ( pPos
-       ? x >= 0 && x <= pPos->getWidth() && y >= 0 && y <= pPos->getHeight()
-       : false);
+    return !pPos ? false :
+        x >= 0 && x <= pPos->getWidth() && y >= 0 && y <= pPos->getHeight();
 }
 
-void CtrlTree::draw( OSGraphics &rImage, int xDest, int yDest )
+void CtrlTree::draw( OSGraphics &rImage, int xDest, int yDest, int w, int h)
 {
-    if( m_pImage )
-    {
-        rImage.drawGraphics( *m_pImage, 0, 0, xDest, yDest );
-    }
+    const Position *pPos = getPosition();
+    rect region( pPos->getLeft(), pPos->getTop(),
+                 pPos->getWidth(), pPos->getHeight() );
+    rect clip( xDest, yDest, w, h );
+    rect inter;
+
+    if( rect::intersect( region, clip, &inter ) && m_pImage )
+        rImage.drawGraphics( *m_pImage,
+                      inter.x - pPos->getLeft(),
+                      inter.y - pPos->getTop(),
+                      inter.x, inter.y, inter.width, inter.height );
 }
 
 bool CtrlTree::ensureVisible( VarTree::Iterator item )
@@ -577,8 +667,10 @@ bool CtrlTree::ensureVisible( VarTree::Iterator item )
 
     m_rTree.ensureExpanded( item );
 
-    for( it = m_rTree.begin(); it != m_rTree.end();
-         it = m_rTree.getNextVisibleItem( it ) )
+    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_id == item->m_id ) break;
         focusItemIndex++;
@@ -591,8 +683,10 @@ bool CtrlTree::ensureVisible( int focusItemIndex )
     // Find  m_firstPos
     VarTree::Iterator it;
     int firstPosIndex = 0;
-    for( it = m_rTree.begin(); it != m_rTree.end();
-         it = m_rTree.getNextVisibleItem( it ) )
+    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_firstPos ) break;
         firstPosIndex++;
@@ -603,12 +697,13 @@ bool CtrlTree::ensureVisible( int focusItemIndex )
 
     if( it != m_rTree.end()
         && ( focusItemIndex < firstPosIndex
-           || focusItemIndex > firstPosIndex + maxItems() ) )
+           || focusItemIndex > firstPosIndex + maxItems() - 1 ) )
     {
         // Scroll to have the wanted stream visible
         VarPercent &rVarPos = m_rTree.getPositionVar();
-        rVarPos.set( 1.0 - (double)focusItemIndex /
-                           (double)m_rTree.visibleItems() );
+        int indexMax = ( m_flat ? m_rTree.countLeafs()
+                                : m_rTree.visibleItems() ) - 1;
+        rVarPos.set( 1.0 - (double)focusItemIndex / (double)indexMax );
         return true;
     }
     return false;
@@ -620,8 +715,10 @@ void CtrlTree::autoScroll()
     int playIndex = 0;
     VarTree::Iterator it;
 
-    for( it = m_rTree.begin(); it != m_rTree.end();
-         it = m_rTree.getNextItem( 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->m_playing )
         {
@@ -629,8 +726,10 @@ void CtrlTree::autoScroll()
            break;
         }
     }
-    for( it = m_rTree.begin(); it != m_rTree.end();
-         it = m_rTree.getNextVisibleItem( it ) )
+    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_playing )
            break;
@@ -648,10 +747,7 @@ void CtrlTree::makeImage()
 {
     stats_TimerStart( getIntf(), "[Skins] Playlist image",
                       STATS_TIMER_SKINS_PLAYTREE_IMAGE );
-    if( m_pImage )
-    {
-        delete m_pImage;
-    }
+    delete m_pImage;
 
     // Get the size of the control
     const Position *pPos = getPosition();
@@ -689,8 +785,9 @@ void CtrlTree::makeImage()
                 }
                 do
                 {
-                    it = m_rTree.getNextVisibleItem( it );
-                } while( it->m_deleted );
+                    it = m_flat ? m_rTree.getNextLeaf( it )
+                                : m_rTree.getNextVisibleItem( it );
+                } while( it != m_rTree.end() && it->m_deleted );
             }
         }
     }
@@ -703,18 +800,17 @@ 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_rTree.end() )
+                m_pImage->fillRect( 0, yPos, width, rectHeight, bgColor );
+            else
             {
                 uint32_t color = ( it->m_selected ? m_selColor : bgColor );
                 m_pImage->fillRect( 0, yPos, width, rectHeight, color );
                 do
                 {
-                    it = m_rTree.getNextVisibleItem( it );
-                } while( it->m_deleted );
-            }
-            else
-            {
-                m_pImage->fillRect( 0, yPos, width, rectHeight, bgColor );
+                    it = m_flat ? m_rTree.getNextLeaf( it )
+                                : m_rTree.getNextVisibleItem( it );
+                } while( it != m_rTree.end() && it->m_deleted );
             }
             bgColor = ( bgColor == m_bgColor1 ? m_bgColor2 : m_bgColor1 );
         }
@@ -733,7 +829,7 @@ void CtrlTree::makeImage()
         // Draw the text
         if( pStr != NULL )
         {
-            int depth = it->depth();
+            int depth = m_flat ? 1 : it->depth();
             GenericBitmap *pText = m_rFont.drawString( *pStr, color, width - bitmapWidth * depth );
             if( !pText )
             {
@@ -774,9 +870,11 @@ void CtrlTree::makeImage()
             yPos += (pText->getHeight() - ySrc );
             delete pText;
         }
-        do {
-        it = m_rTree.getNextVisibleItem( it );
-        } while( it->m_deleted );
+        do
+        {
+            it = m_flat ? m_rTree.getNextLeaf( it )
+                : m_rTree.getNextVisibleItem( it );
+        } while( it != m_rTree.end() && it->m_deleted );
     }
     stats_TimerStop( getIntf(), STATS_TIMER_SKINS_PLAYTREE_IMAGE );
 }
@@ -787,7 +885,8 @@ VarTree::Iterator CtrlTree::findItemAtPos( int pos )
     // 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_rTree.getNextVisibleItem( it ) )
+         it = m_flat ? m_rTree.getNextLeaf( it )
+                     : m_rTree.getNextVisibleItem( it ) )
     {
         pos--;
     }