ctrl_tree.cpp
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:28k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * ctrl_tree.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2003 the VideoLAN team
  5.  * $Id: 50b46750269edb20e16d5690d87f073f8a3fe3dd $
  6.  *
  7.  * Authors: Antoine Cellerier <dionoea@videolan.org>
  8.  *          Clément Stenac <zorglub@videolan.org>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. #include <math.h>
  25. #include "../utils/var_bool.hpp"
  26. #include "ctrl_tree.hpp"
  27. #include "../src/os_factory.hpp"
  28. #include "../src/os_graphics.hpp"
  29. #include "../src/generic_bitmap.hpp"
  30. #include "../src/generic_font.hpp"
  31. #include "../src/scaled_bitmap.hpp"
  32. #include "../utils/position.hpp"
  33. #include "../utils/ustring.hpp"
  34. #include "../events/evt_key.hpp"
  35. #include "../events/evt_mouse.hpp"
  36. #include "../events/evt_scroll.hpp"
  37. #include "vlc_keys.h"
  38. #define SCROLL_STEP 0.05
  39. #define LINE_INTERVAL 1  // Number of pixels inserted between 2 lines
  40. CtrlTree::CtrlTree( intf_thread_t *pIntf,
  41.                     VarTree &rTree,
  42.                     const GenericFont &rFont,
  43.                     const GenericBitmap *pBgBitmap,
  44.                     const GenericBitmap *pItemBitmap,
  45.                     const GenericBitmap *pOpenBitmap,
  46.                     const GenericBitmap *pClosedBitmap,
  47.                     uint32_t fgColor,
  48.                     uint32_t playColor,
  49.                     uint32_t bgColor1,
  50.                     uint32_t bgColor2,
  51.                     uint32_t selColor,
  52.                     const UString &rHelp,
  53.                     VarBool *pVisible,
  54.                     VarBool *pFlat ):
  55.     CtrlGeneric( pIntf,rHelp, pVisible), m_rTree( rTree), m_rFont( rFont ),
  56.     m_pBgBitmap( pBgBitmap ), m_pItemBitmap( pItemBitmap ),
  57.     m_pOpenBitmap( pOpenBitmap ), m_pClosedBitmap( pClosedBitmap ),
  58.     m_fgColor( fgColor ), m_playColor( playColor ), m_bgColor1( bgColor1 ),
  59.     m_bgColor2( bgColor2 ), m_selColor( selColor ),
  60.     m_pLastSelected( NULL ), m_pImage( NULL ), m_dontMove( false )
  61. {
  62.     // Observe the tree and position variables
  63.     m_rTree.addObserver( this );
  64.     m_rTree.getPositionVar().addObserver( this );
  65.     m_flat = pFlat->get();
  66.     m_firstPos = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  67.     makeImage();
  68. }
  69. CtrlTree::~CtrlTree()
  70. {
  71.     m_rTree.getPositionVar().delObserver( this );
  72.     m_rTree.delObserver( this );
  73.     delete m_pImage;
  74. }
  75. int CtrlTree::itemHeight()
  76. {
  77.     int itemHeight = m_rFont.getSize();
  78.     if( !m_flat )
  79.     {
  80.         if( m_pClosedBitmap )
  81.         {
  82.             itemHeight = __MAX( m_pClosedBitmap->getHeight(), itemHeight );
  83.         }
  84.         if( m_pOpenBitmap )
  85.         {
  86.             itemHeight = __MAX( m_pOpenBitmap->getHeight(), itemHeight );
  87.         }
  88.     }
  89.     if( m_pItemBitmap )
  90.     {
  91.         itemHeight = __MAX( m_pItemBitmap->getHeight(), itemHeight );
  92.     }
  93.     itemHeight += LINE_INTERVAL;
  94.     return itemHeight;
  95. }
  96. int CtrlTree::itemImageWidth()
  97. {
  98.     int bitmapWidth = 5;
  99.     if( !m_flat )
  100.     {
  101.         if( m_pClosedBitmap )
  102.         {
  103.             bitmapWidth = __MAX( m_pClosedBitmap->getWidth(), bitmapWidth );
  104.         }
  105.         if( m_pOpenBitmap )
  106.         {
  107.             bitmapWidth = __MAX( m_pOpenBitmap->getWidth(), bitmapWidth );
  108.         }
  109.     }
  110.     if( m_pItemBitmap )
  111.     {
  112.         bitmapWidth = __MAX( m_pItemBitmap->getWidth(), bitmapWidth );
  113.     }
  114.     return bitmapWidth + 2;
  115. }
  116. int CtrlTree::maxItems()
  117. {
  118.     const Position *pPos = getPosition();
  119.     if( !pPos )
  120.     {
  121.         return -1;
  122.     }
  123.     return pPos->getHeight() / itemHeight();
  124. }
  125. void CtrlTree::onUpdate( Subject<VarTree, tree_update> &rTree,
  126.                          tree_update *arg )
  127. {
  128.     if( arg->i_type == 0 ) // Item update
  129.     {
  130.         if( arg->b_active_item )
  131.         {
  132.             autoScroll();
  133.             ///todo We should make image if we are visible in the view
  134.             makeImage();
  135.         }
  136.     }
  137.     /// todo handle delete in a more clever way
  138.     else if ( arg->i_type == 1 ) // Global change or deletion
  139.     {
  140.         m_firstPos = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  141.         makeImage();
  142.     }
  143.     else if ( arg->i_type == 2 ) // Item-append
  144.     {
  145.         if( m_flat && m_firstPos->size() )
  146.             m_firstPos = m_rTree.getNextLeaf( m_firstPos );
  147.         /// todo Check if the item is really visible in the view
  148.         // (we only check if it in the document)
  149.         if( arg->b_visible == true )
  150.         {
  151.             makeImage();
  152.         }
  153.     }
  154.     else if( arg->i_type == 3 ) // item-del
  155.     {
  156.         /* Make sure firstPos and lastSelected are still valid */
  157.         while( m_firstPos->m_deleted && m_firstPos != m_rTree.root()->begin() )
  158.         {
  159.             m_firstPos = m_flat ? m_rTree.getPrevLeaf( m_firstPos )
  160.                                 : m_rTree.getPrevVisibleItem( m_firstPos );
  161.         }
  162.         if( m_firstPos->m_deleted )
  163.             m_firstPos = m_flat ? m_rTree.firstLeaf()
  164.                                 : m_rTree.root()->begin();
  165.         if( arg->b_visible == true )
  166.         {
  167.             makeImage();
  168.         }
  169.     }
  170.     notifyLayout();
  171. }
  172. void CtrlTree::onUpdate( Subject<VarPercent> &rPercent, void* arg)
  173. {
  174.     // Determine what is the first item to display
  175.     VarTree::Iterator it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  176.     if( m_dontMove ) return;
  177.     int excessItems;
  178.     if( m_flat )
  179.         excessItems = m_rTree.countLeafs() - maxItems();
  180.     else
  181.         excessItems = m_rTree.visibleItems() - maxItems();
  182.     if( excessItems > 0)
  183.     {
  184.         VarPercent &rVarPos = m_rTree.getPositionVar();
  185.         // a simple (int)(...) causes rounding errors !
  186. #ifdef _MSC_VER
  187. #   define lrint (int)
  188. #endif
  189.         if( m_flat )
  190.             it = m_rTree.getLeaf(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1 );
  191.         else
  192.             it = m_rTree.getVisibleItem(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1 );
  193.     }
  194.     if( m_firstPos != it )
  195.     {
  196.         // Redraw the control if the position has changed
  197.         m_firstPos = it;
  198.         makeImage();
  199.         notifyLayout();
  200.     }
  201. }
  202. void CtrlTree::onResize()
  203. {
  204.     // Determine what is the first item to display
  205.     VarTree::Iterator it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  206.     int excessItems;
  207.     if( m_flat )
  208.         excessItems = m_rTree.countLeafs() - maxItems();
  209.     else
  210.         excessItems = m_rTree.visibleItems() - maxItems();
  211.     if( excessItems > 0)
  212.     {
  213.         VarPercent &rVarPos = m_rTree.getPositionVar();
  214.         // a simple (int)(...) causes rounding errors !
  215. #ifdef _MSC_VER
  216. #   define lrint (int)
  217. #endif
  218.         if( m_flat )
  219.             it = m_rTree.getLeaf(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1 );
  220.         else
  221.             it = m_rTree.getVisibleItem(lrint( (1.0 - rVarPos.get()) * (double)excessItems ) + 1 );
  222.     }
  223.     // Redraw the control if the position has changed
  224.     m_firstPos = it;
  225.     makeImage();
  226.     notifyLayout();
  227. }
  228. void CtrlTree::onPositionChange()
  229. {
  230.     makeImage();
  231.     notifyLayout();
  232. }
  233. void CtrlTree::handleEvent( EvtGeneric &rEvent )
  234. {
  235.     bool bChangedPosition = false;
  236.     VarTree::Iterator toShow; bool needShow = false;
  237.     if( rEvent.getAsString().find( "key:down" ) != string::npos )
  238.     {
  239.         int key = ((EvtKey&)rEvent).getKey();
  240.         VarTree::Iterator it;
  241.         bool previousWasSelected = false;
  242.         /* Delete the selection */
  243.         if( key == KEY_DELETE )
  244.         {
  245.             /* Find first non selected item before m_pLastSelected */
  246.             VarTree::Iterator it_sel = m_flat ? m_rTree.firstLeaf()
  247.                                               : m_rTree.begin();
  248.             for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  249.                  it != m_rTree.end();
  250.                  it = m_flat ? m_rTree.getNextLeaf( it )
  251.                              : m_rTree.getNextVisibleItem( it ) )
  252.             {
  253.                 if( &*it == m_pLastSelected ) break;
  254.                 if( !it->m_selected ) it_sel = it;
  255.             }
  256.             /* Delete selected stuff */
  257.             m_rTree.delSelected();
  258.             /* Select it_sel */
  259.             it_sel->m_selected = true;
  260.             m_pLastSelected = &*it_sel;
  261.         }
  262.         else if( key == KEY_PAGEDOWN )
  263.         {
  264.             it = m_firstPos;
  265.             int i = (int)(maxItems()*1.5);
  266.             while( i >= 0 )
  267.             {
  268.                 VarTree::Iterator it_old = it;
  269.                 it = m_flat ? m_rTree.getNextLeaf( it )
  270.                             : m_rTree.getNextVisibleItem( it );
  271.                 /* End is already visible, dont' scroll */
  272.                 if( it == m_rTree.end() )
  273.                 {
  274.                     it = it_old;
  275.                     break;
  276.                 }
  277.                 needShow = true;
  278.                 i--;
  279.             }
  280.             if( needShow )
  281.             {
  282.                 ensureVisible( it );
  283.                 makeImage();
  284.                 notifyLayout();
  285.                 return;
  286.             }
  287.         }
  288.         else if (key == KEY_PAGEUP )
  289.         {
  290.             it = m_firstPos;
  291.             int i = maxItems();
  292.             while( i >= maxItems()/2 )
  293.             {
  294.                 it = m_flat ? m_rTree.getPrevLeaf( it )
  295.                             : m_rTree.getPrevVisibleItem( it );
  296.                 /* End is already visible, dont' scroll */
  297.                 if( it == ( m_flat ? m_rTree.firstLeaf() : m_rTree.begin() ) )
  298.                 {
  299.                     break;
  300.                 }
  301.                 i--;
  302.             }
  303.             ensureVisible( it );
  304.             makeImage();
  305.             notifyLayout();
  306.             return;
  307.         }
  308.         for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  309.              it != m_rTree.end();
  310.              it = m_flat ? m_rTree.getNextLeaf( it )
  311.                          : m_rTree.getNextVisibleItem( it ) )
  312.         {
  313.             VarTree::Iterator next = m_flat ? m_rTree.getNextLeaf( it )
  314.                                             : m_rTree.getNextVisibleItem( it );
  315.             if( key == KEY_UP )
  316.             {
  317.                 // Scroll up one item
  318.                 if( ( it->parent()
  319.                       && it != it->parent()->begin() )
  320.                     || &*it != m_pLastSelected )
  321.                 {
  322.                     bool nextWasSelected = ( &*next == m_pLastSelected );
  323.                     it->m_selected = nextWasSelected;
  324.                     if( nextWasSelected )
  325.                     {
  326.                         m_pLastSelected = &*it;
  327.                         needShow = true; toShow = it;
  328.                     }
  329.                 }
  330.             }
  331.             else if( key == KEY_DOWN )
  332.             {
  333.                 // Scroll down one item
  334.                 if( ( it->parent()
  335.                       && next != it->parent()->end() )
  336.                     || &*it != m_pLastSelected )
  337.                 {
  338.                     (*it).m_selected = previousWasSelected;
  339.                 }
  340.                 if( previousWasSelected )
  341.                 {
  342.                     m_pLastSelected = &*it;
  343.                     needShow = true; toShow = it;
  344.                     previousWasSelected = false;
  345.                 }
  346.                 else
  347.                 {
  348.                     previousWasSelected = ( &*it == m_pLastSelected );
  349.                 }
  350.                 // Fix last tree item selection
  351.                 if( ( m_flat ? m_rTree.getNextLeaf( it )
  352.                     : m_rTree.getNextVisibleItem( it ) ) == m_rTree.end()
  353.                  && &*it == m_pLastSelected )
  354.                 {
  355.                     (*it).m_selected = true;
  356.                 }
  357.             }
  358.             else if( key == KEY_RIGHT )
  359.             {
  360.                 // Go down one level (and expand node)
  361.                 if( &*it == m_pLastSelected )
  362.                 {
  363.                     if( it->m_expanded )
  364.                     {
  365.                         if( it->size() )
  366.                         {
  367.                             it->m_selected = false;
  368.                             it->begin()->m_selected = true;
  369.                             m_pLastSelected = &*(it->begin());
  370.                         }
  371.                         else
  372.                         {
  373.                             m_rTree.action( &*it );
  374.                         }
  375.                     }
  376.                     else
  377.                     {
  378.                         it->m_expanded = true;
  379.                         bChangedPosition = true;
  380.                     }
  381.                 }
  382.             }
  383.             else if( key == KEY_LEFT )
  384.             {
  385.                 // Go up one level (and close node)
  386.                 if( &*it == m_pLastSelected )
  387.                 {
  388.                     if( it->m_expanded && it->size() )
  389.                     {
  390.                         it->m_expanded = false;
  391.                         bChangedPosition = true;
  392.                     }
  393.                     else
  394.                     {
  395.                         if( it->parent() && it->parent() != &m_rTree)
  396.                         {
  397.                             it->m_selected = false;
  398.                             m_pLastSelected = it->parent();
  399.                             m_pLastSelected->m_selected = true;
  400.                         }
  401.                     }
  402.                 }
  403.             }
  404.             else if( key == KEY_ENTER || key == KEY_SPACE )
  405.             {
  406.                 // Go up one level (and close node)
  407.                 if( &*it == m_pLastSelected )
  408.                 {
  409.                     m_rTree.action( &*it );
  410.                 }
  411.             }
  412.         }
  413.         if( needShow )
  414.             ensureVisible( toShow );
  415.         // Redraw the control
  416.         makeImage();
  417.         notifyLayout();
  418.     }
  419.     else if( rEvent.getAsString().find( "mouse:left" ) != string::npos )
  420.     {
  421.         EvtMouse &rEvtMouse = (EvtMouse&)rEvent;
  422.         const Position *pos = getPosition();
  423.         int yPos = ( rEvtMouse.getYPos() - pos->getTop() ) / itemHeight();
  424.         int xPos = rEvtMouse.getXPos() - pos->getLeft();
  425.         VarTree::Iterator it;
  426.         if( rEvent.getAsString().find( "mouse:left:down:ctrl,shift" ) !=
  427.             string::npos )
  428.         {
  429.             VarTree::Iterator itClicked = findItemAtPos( yPos );
  430.             // Flag to know if the current item must be selected
  431.             bool select = false;
  432.             for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  433.                  it != m_rTree.end();
  434.                  it = m_flat ? m_rTree.getNextLeaf( it )
  435.                              : m_rTree.getNextVisibleItem( it ) )
  436.             {
  437.                 bool nextSelect = select;
  438.                 if( it == itClicked || &*it == m_pLastSelected )
  439.                 {
  440.                     if( select )
  441.                     {
  442.                         nextSelect = false;
  443.                     }
  444.                     else
  445.                     {
  446.                         select = true;
  447.                         nextSelect = true;
  448.                     }
  449.                 }
  450.                 it->m_selected = (*it).m_selected || select;
  451.                 select = nextSelect;
  452.             }
  453.         }
  454.         else if( rEvent.getAsString().find( "mouse:left:down:ctrl" ) !=
  455.                  string::npos )
  456.         {
  457.             // Invert the selection of the item
  458.             it = findItemAtPos( yPos );
  459.             if( it != m_rTree.end() )
  460.             {
  461.                 it->m_selected = !it->m_selected;
  462.                 m_pLastSelected = &*it;
  463.             }
  464.         }
  465.         else if( rEvent.getAsString().find( "mouse:left:down:shift" ) !=
  466.                  string::npos )
  467.         {
  468.             VarTree::Iterator itClicked = findItemAtPos( yPos );
  469.             // Flag to know if the current item must be selected
  470.             bool select = false;
  471.             for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  472.                  it != m_rTree.end();
  473.                  it = m_flat ? m_rTree.getNextLeaf( it )
  474.                              : m_rTree.getNextVisibleItem( it ) )
  475.             {
  476.                 bool nextSelect = select;
  477.                 if( it == itClicked || &*it == m_pLastSelected )
  478.                 {
  479.                     if( select )
  480.                     {
  481.                         nextSelect = false;
  482.                     }
  483.                     else
  484.                     {
  485.                         select = true;
  486.                         nextSelect = true;
  487.                     }
  488.                 }
  489.                 it->m_selected = select;
  490.                 select = nextSelect;
  491.             }
  492.         }
  493.         else if( rEvent.getAsString().find( "mouse:left:down" ) !=
  494.                  string::npos )
  495.         {
  496.             it = findItemAtPos(yPos);
  497.             if( it != m_rTree.end() )
  498.             {
  499.                 if( ( it->size() && xPos > (it->depth() - 1) * itemImageWidth()
  500.                       && xPos < it->depth() * itemImageWidth() )
  501.                  && !m_flat )
  502.                 {
  503.                     // Fold/unfold the item
  504.                     it->m_expanded = !it->m_expanded;
  505.                     bChangedPosition = true;
  506.                 }
  507.                 else
  508.                 {
  509.                     // Unselect any previously selected item
  510.                     VarTree::Iterator it2;
  511.                     for( it2 = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  512.                          it2 != m_rTree.end();
  513.                          it2 = m_flat ? m_rTree.getNextLeaf( it2 )
  514.                                       : m_rTree.getNextVisibleItem( it2 ) )
  515.                     {
  516.                         it2->m_selected = false;
  517.                     }
  518.                     // Select the new item
  519.                     if( it != m_rTree.end() )
  520.                     {
  521.                         it->m_selected = true;
  522.                         m_pLastSelected = &*it;
  523.                     }
  524.                 }
  525.             }
  526.         }
  527.         else if( rEvent.getAsString().find( "mouse:left:dblclick" ) !=
  528.                  string::npos )
  529.         {
  530.             it = findItemAtPos(yPos);
  531.             if( it != m_rTree.end() )
  532.             {
  533.                // Execute the action associated to this item
  534.                m_rTree.action( &*it );
  535.             }
  536.         }
  537.         // Redraw the control
  538.         makeImage();
  539.         notifyLayout();
  540.     }
  541.     else if( rEvent.getAsString().find( "scroll" ) != string::npos )
  542.     {
  543.         int direction = ((EvtScroll&)rEvent).getDirection();
  544.         double percentage = m_rTree.getPositionVar().get();
  545.         double step = 2.0 / (double)( m_flat ? m_rTree.countLeafs()
  546.                                              : m_rTree.visibleItems() );
  547.         if( direction == EvtScroll::kUp )
  548.         {
  549.             percentage += step;
  550.         }
  551.         else
  552.         {
  553.             percentage -= step;
  554.         }
  555.         m_rTree.getPositionVar().set( percentage );
  556.     }
  557.     /* We changed the nodes, let's fix teh position var */
  558.     if( bChangedPosition )
  559.     {
  560.         VarTree::Iterator it;
  561.         int i = 0;
  562.         int iFirst = 0;
  563.         for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  564.              it != m_rTree.end();
  565.              it = m_flat ? m_rTree.getNextLeaf( it )
  566.                          : m_rTree.getNextVisibleItem( it ) )
  567.         {
  568.             i++;
  569.             if( it == m_firstPos )
  570.             {
  571.                 iFirst = i;
  572.                 break;
  573.             }
  574.         }
  575.         iFirst += maxItems();
  576.         if( iFirst >= m_flat ? m_rTree.countLeafs() : m_rTree.visibleItems() )
  577.             iFirst = m_flat ? m_rTree.countLeafs() : m_rTree.visibleItems();
  578.         float f_new = (float)iFirst / (float)( m_flat ? m_rTree.countLeafs()
  579.                                                       :m_rTree.visibleItems() );
  580.         m_dontMove = true;
  581.         m_rTree.getPositionVar().set( 1.0 - f_new );
  582.         m_dontMove = false;
  583.     }
  584. }
  585. bool CtrlTree::mouseOver( int x, int y ) const
  586. {
  587.     const Position *pPos = getPosition();
  588.     return ( pPos
  589.        ? x >= 0 && x <= pPos->getWidth() && y >= 0 && y <= pPos->getHeight()
  590.        : false);
  591. }
  592. void CtrlTree::draw( OSGraphics &rImage, int xDest, int yDest )
  593. {
  594.     if( m_pImage )
  595.     {
  596.         rImage.drawGraphics( *m_pImage, 0, 0, xDest, yDest );
  597.     }
  598. }
  599. bool CtrlTree::ensureVisible( VarTree::Iterator item )
  600. {
  601.     // Find the item to focus
  602.     int focusItemIndex = 0;
  603.     VarTree::Iterator it;
  604.     m_rTree.ensureExpanded( item );
  605.     for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  606.          it != m_rTree.end();
  607.          it = m_flat ? m_rTree.getNextLeaf( it )
  608.                      : m_rTree.getNextVisibleItem( it ) )
  609.     {
  610.         if( it->m_id == item->m_id ) break;
  611.         focusItemIndex++;
  612.     }
  613.    return ensureVisible( focusItemIndex );
  614. }
  615. bool CtrlTree::ensureVisible( int focusItemIndex )
  616. {
  617.     // Find  m_firstPos
  618.     VarTree::Iterator it;
  619.     int firstPosIndex = 0;
  620.     for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  621.          it != m_rTree.end();
  622.          it = m_flat ? m_rTree.getNextLeaf( it )
  623.                      : m_rTree.getNextVisibleItem( it ) )
  624.     {
  625.         if( it == m_firstPos ) break;
  626.         firstPosIndex++;
  627.     }
  628.     if( it == m_rTree.end() ) return false;
  629.     if( it != m_rTree.end()
  630.         && ( focusItemIndex < firstPosIndex
  631.            || focusItemIndex > firstPosIndex + maxItems() ) )
  632.     {
  633.         // Scroll to have the wanted stream visible
  634.         VarPercent &rVarPos = m_rTree.getPositionVar();
  635.         rVarPos.set( 1.0 - (double)focusItemIndex /
  636.                            (double)( m_flat ? m_rTree.countLeafs()
  637.                                             : m_rTree.visibleItems() ) );
  638.         return true;
  639.     }
  640.     return false;
  641. }
  642. void CtrlTree::autoScroll()
  643. {
  644.     // Find the current playing stream
  645.     int playIndex = 0;
  646.     VarTree::Iterator it;
  647.     for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  648.          it != m_rTree.end();
  649.          it = m_flat ? m_rTree.getNextLeaf( it )
  650.                      : m_rTree.getNextItem( it ) )
  651.     {
  652.         if( it->m_playing )
  653.         {
  654.            m_rTree.ensureExpanded( it );
  655.            break;
  656.         }
  657.     }
  658.     for( it = m_flat ? m_rTree.firstLeaf() : m_rTree.begin();
  659.          it != m_rTree.end();
  660.          it = m_flat ? m_rTree.getNextLeaf( it )
  661.                      : m_rTree.getNextVisibleItem( it ) )
  662.     {
  663.         if( it->m_playing )
  664.            break;
  665.         playIndex++;
  666.     }
  667.     if( it == m_rTree.end() ) return;
  668.     ensureVisible( playIndex );
  669. }
  670. void CtrlTree::makeImage()
  671. {
  672.     stats_TimerStart( getIntf(), "[Skins] Playlist image",
  673.                       STATS_TIMER_SKINS_PLAYTREE_IMAGE );
  674.     delete m_pImage;
  675.     // Get the size of the control
  676.     const Position *pPos = getPosition();
  677.     if( !pPos )
  678.     {
  679.         stats_TimerStop( getIntf(), STATS_TIMER_SKINS_PLAYTREE_IMAGE );
  680.         return;
  681.     }
  682.     int width = pPos->getWidth();
  683.     int height = pPos->getHeight();
  684.     int i_itemHeight = itemHeight();
  685.     // Create an image
  686.     OSFactory *pOsFactory = OSFactory::instance( getIntf() );
  687.     m_pImage = pOsFactory->createOSGraphics( width, height );
  688.     VarTree::Iterator it = m_firstPos;
  689.     if( m_pBgBitmap )
  690.     {
  691.         // Draw the background bitmap
  692.         ScaledBitmap bmp( getIntf(), *m_pBgBitmap, width, height );
  693.         m_pImage->drawBitmap( bmp, 0, 0 );
  694.         for( int yPos = 0; yPos < height; yPos += i_itemHeight )
  695.         {
  696.             if( it != m_rTree.end() )
  697.             {
  698.                 if( (*it).m_selected )
  699.                 {
  700.                     int rectHeight = __MIN( i_itemHeight, height - yPos );
  701.                     m_pImage->fillRect( 0, yPos, width, rectHeight,
  702.                                         m_selColor );
  703.                 }
  704.                 do
  705.                 {
  706.                     it = m_flat ? m_rTree.getNextLeaf( it )
  707.                                 : m_rTree.getNextVisibleItem( it );
  708.                 } while( it != m_rTree.end() && it->m_deleted );
  709.             }
  710.         }
  711.     }
  712.     else
  713.     {
  714.         // FIXME (TRYME)
  715.         // Fill background with background color
  716.         uint32_t bgColor = m_bgColor1;
  717.         m_pImage->fillRect( 0, 0, width, height, bgColor );
  718.         for( int yPos = 0; yPos < height; yPos += i_itemHeight )
  719.         {
  720.             int rectHeight = __MIN( i_itemHeight, height - yPos );
  721.             if( it != m_rTree.end() )
  722.             {
  723.                 uint32_t color = ( it->m_selected ? m_selColor : bgColor );
  724.                 m_pImage->fillRect( 0, yPos, width, rectHeight, color );
  725.                 do
  726.                 {
  727.                     it = m_flat ? m_rTree.getNextLeaf( it )
  728.                                 : m_rTree.getNextVisibleItem( it );
  729.                 } while( it != m_rTree.end() && it->m_deleted );
  730.             }
  731.             else
  732.             {
  733.                 m_pImage->fillRect( 0, yPos, width, rectHeight, bgColor );
  734.             }
  735.             bgColor = ( bgColor == m_bgColor1 ? m_bgColor2 : m_bgColor1 );
  736.         }
  737.     }
  738.     int bitmapWidth = itemImageWidth();
  739.     int yPos = 0;
  740.     it = m_firstPos;
  741.     while( it != m_rTree.end() && yPos < height )
  742.     {
  743.         const GenericBitmap *m_pCurBitmap;
  744.         UString *pStr = (UString*)(it->m_cString.get());
  745.         uint32_t color = ( it->m_playing ? m_playColor : m_fgColor );
  746.         // Draw the text
  747.         if( pStr != NULL )
  748.         {
  749.             int depth = m_flat ? 1 : it->depth();
  750.             GenericBitmap *pText = m_rFont.drawString( *pStr, color, width - bitmapWidth * depth );
  751.             if( !pText )
  752.             {
  753.                 stats_TimerStop( getIntf(), STATS_TIMER_SKINS_PLAYTREE_IMAGE );
  754.                 return;
  755.             }
  756.             if( it->size() )
  757.                 m_pCurBitmap = it->m_expanded ? m_pOpenBitmap : m_pClosedBitmap;
  758.             else
  759.                 m_pCurBitmap = m_pItemBitmap;
  760.             if( m_pCurBitmap )
  761.             {
  762.                 // Make sure we are centered on the line
  763.                 int yPos2 = yPos+(i_itemHeight-m_pCurBitmap->getHeight()+1)/2;
  764.                 if( yPos2 >= height )
  765.                 {
  766.                     delete pText;
  767.                     break;
  768.                 }
  769.                 m_pImage->drawBitmap( *m_pCurBitmap, 0, 0,
  770.                                       bitmapWidth * (depth - 1 ), yPos2,
  771.                                       m_pCurBitmap->getWidth(),
  772.                                       __MIN( m_pCurBitmap->getHeight(),
  773.                                              height -  yPos2), true );
  774.             }
  775.             yPos += i_itemHeight - pText->getHeight();
  776.             int ySrc = 0;
  777.             if( yPos < 0 )
  778.             {
  779.                 ySrc = - yPos;
  780.                 yPos = 0;
  781.             }
  782.             int lineHeight = __MIN( pText->getHeight() - ySrc, height - yPos );
  783.             m_pImage->drawBitmap( *pText, 0, ySrc, bitmapWidth * depth, yPos,
  784.                                   pText->getWidth(),
  785.                                   lineHeight, true );
  786.             yPos += (pText->getHeight() - ySrc );
  787.             delete pText;
  788.         }
  789.         do
  790.         {
  791.             it = m_flat ? m_rTree.getNextLeaf( it )
  792.                 : m_rTree.getNextVisibleItem( it );
  793.         } while( it != m_rTree.end() && it->m_deleted );
  794.     }
  795.     stats_TimerStop( getIntf(), STATS_TIMER_SKINS_PLAYTREE_IMAGE );
  796. }
  797. VarTree::Iterator CtrlTree::findItemAtPos( int pos )
  798. {
  799.     // The first item is m_firstPos.
  800.     // We decrement pos as we try the other items, until pos == 0.
  801.     VarTree::Iterator it;
  802.     for( it = m_firstPos; it != m_rTree.end() && pos != 0;
  803.          it = m_flat ? m_rTree.getNextLeaf( it )
  804.                      : m_rTree.getNextVisibleItem( it ) )
  805.     {
  806.         pos--;
  807.     }
  808.     return it;
  809. }