ctrl_list.cpp
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:13k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * ctrl_list.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2003 VideoLAN
  5.  * $Id: ctrl_list.cpp 8493 2004-08-22 10:38:26Z asmax $
  6.  *
  7.  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
  8.  *          Olivier Teuli鑢e <ipkiss@via.ecp.fr>
  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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  23.  *****************************************************************************/
  24. #include <math.h>
  25. #include "ctrl_list.hpp"
  26. #include "../src/os_factory.hpp"
  27. #include "../src/os_graphics.hpp"
  28. #include "../src/generic_bitmap.hpp"
  29. #include "../src/generic_font.hpp"
  30. #include "../utils/position.hpp"
  31. #include "../utils/ustring.hpp"
  32. #include "../events/evt_key.hpp"
  33. #include "../events/evt_mouse.hpp"
  34. #include "../events/evt_scroll.hpp"
  35. #include "vlc_keys.h"
  36. #ifdef sun
  37. #   include "solaris_specific.h" // for lrint
  38. #endif
  39. #define SCROLL_STEP 0.05
  40. #define LINE_INTERVAL 1  // Number of pixels inserted between 2 lines
  41. CtrlList::CtrlList( intf_thread_t *pIntf, VarList &rList, GenericFont &rFont,
  42.                     uint32_t fgColor, uint32_t playColor, uint32_t bgColor1,
  43.                     uint32_t bgColor2, uint32_t selColor,
  44.                     const UString &rHelp, VarBool *pVisible ):
  45.     CtrlGeneric( pIntf, rHelp, pVisible ), m_rList( rList ), m_rFont( rFont ),
  46.     m_fgColor( fgColor ), m_playColor( playColor ), m_bgColor1( bgColor1 ),
  47.     m_bgColor2( bgColor2 ), m_selColor( selColor ), m_pLastSelected( NULL ),
  48.     m_pImage( NULL ), m_lastPos( 0 )
  49. {
  50.     // Observe the list and position variables
  51.     m_rList.addObserver( this );
  52.     m_rList.getPositionVar().addObserver( this );
  53.     makeImage();
  54. }
  55. CtrlList::~CtrlList()
  56. {
  57.     m_rList.getPositionVar().delObserver( this );
  58.     m_rList.delObserver( this );
  59.     if( m_pImage )
  60.     {
  61.         delete m_pImage;
  62.     }
  63. }
  64. void CtrlList::onUpdate( Subject<VarList> &rList )
  65. {
  66.     autoScroll();
  67.     m_pLastSelected = NULL;
  68. }
  69. void CtrlList::onUpdate( Subject<VarPercent> &rPercent )
  70. {
  71.     // Get the size of the control
  72.     const Position *pPos = getPosition();
  73.     if( !pPos )
  74.     {
  75.         return;
  76.     }
  77.     int height = pPos->getHeight();
  78.     // How many lines can be displayed ?
  79.     int itemHeight = m_rFont.getSize() + LINE_INTERVAL;
  80.     int maxItems = height / itemHeight;
  81.     // Determine what is the first item to display
  82.     VarPercent &rVarPos = m_rList.getPositionVar();
  83.     int firstItem = 0;
  84.     int excessItems = m_rList.size() - maxItems;
  85.     if( excessItems > 0 )
  86.     {
  87.         // a simple (int)(...) causes rounding errors !
  88. #ifdef _MSC_VER
  89. #   define lrint (int)
  90. #endif
  91.         firstItem = lrint( (1.0 - rVarPos.get()) * (double)excessItems );
  92.     }
  93.     if( m_lastPos != firstItem )
  94.     {
  95.         // Redraw the control if the position has changed
  96.         m_lastPos = firstItem;
  97.         makeImage();
  98.         notifyLayout();
  99.     }
  100. }
  101. void CtrlList::onResize()
  102. {
  103.     // Get the size of the control
  104.     const Position *pPos = getPosition();
  105.     if( !pPos )
  106.     {
  107.         return;
  108.     }
  109.     int height = pPos->getHeight();
  110.     // How many lines can be displayed ?
  111.     int itemHeight = m_rFont.getSize() + LINE_INTERVAL;
  112.     int maxItems = height / itemHeight;
  113.     // Update the position variable
  114.     VarPercent &rVarPos = m_rList.getPositionVar();
  115.     int excessItems = m_rList.size() - maxItems;
  116.     if( excessItems > 0 )
  117.     {
  118.         double newVal = 1.0 - (double)m_lastPos / excessItems;
  119.         if( newVal >= 0 )
  120.         {
  121.             // Change the position to keep the same first displayed item
  122.             rVarPos.set( 1.0 - (double)m_lastPos / excessItems );
  123.         }
  124.         else
  125.         {
  126.             // We cannot keep the current first item
  127.             m_lastPos = excessItems;
  128.         }
  129.     }
  130.     makeImage();
  131.     notifyLayout();
  132. }
  133. void CtrlList::onPositionChange()
  134. {
  135.     makeImage();
  136.     notifyLayout();
  137. }
  138. void CtrlList::handleEvent( EvtGeneric &rEvent )
  139. {
  140.     if( rEvent.getAsString().find( "key:down" ) != string::npos )
  141.     {
  142.         int key = ((EvtKey&)rEvent).getKey();
  143.         VarList::Iterator it = m_rList.begin();
  144.         bool previousWasSelected = false;
  145.         while( it != m_rList.end() )
  146.         {
  147.             VarList::Iterator next = it;
  148.             ++next;
  149.             if( key == KEY_UP )
  150.             {
  151.                 // Scroll up one item
  152.                 if( it != m_rList.begin() || &*it != m_pLastSelected )
  153.                 {
  154.                     bool nextWasSelected = ( &*next == m_pLastSelected );
  155.                     (*it).m_selected = nextWasSelected;
  156.                     if( nextWasSelected )
  157.                     {
  158.                         m_pLastSelected = &*it;
  159.                     }
  160.                 }
  161.             }
  162.             else if( key == KEY_DOWN )
  163.             {
  164.                 // Scroll down one item
  165.                 if( next != m_rList.end() || &*it != m_pLastSelected )
  166.                 {
  167.                     (*it).m_selected = previousWasSelected;
  168.                 }
  169.                 if( previousWasSelected )
  170.                 {
  171.                     m_pLastSelected = &*it;
  172.                     previousWasSelected = false;
  173.                 }
  174.                 else
  175.                 {
  176.                     previousWasSelected = ( &*it == m_pLastSelected );
  177.                 }
  178.             }
  179.             it = next;
  180.         }
  181.         // Redraw the control
  182.         makeImage();
  183.         notifyLayout();
  184.     }
  185.     else if( rEvent.getAsString().find( "mouse:left" ) != string::npos )
  186.     {
  187.         EvtMouse &rEvtMouse = (EvtMouse&)rEvent;
  188.         const Position *pos = getPosition();
  189.         int yPos = m_lastPos + ( rEvtMouse.getYPos() - pos->getTop() ) /
  190.             (m_rFont.getSize() + LINE_INTERVAL);
  191.         VarList::Iterator it;
  192.         int index = 0;
  193.         if( rEvent.getAsString().find( "mouse:left:down:ctrl,shift" ) !=
  194.                  string::npos )
  195.         {
  196.             // Flag to know if the current item must be selected
  197.             bool select = false;
  198.             for( it = m_rList.begin(); it != m_rList.end(); it++ )
  199.             {
  200.                 bool nextSelect = select;
  201.                 if( index == yPos || &*it == m_pLastSelected )
  202.                 {
  203.                     if( select )
  204.                     {
  205.                         nextSelect = false;
  206.                     }
  207.                     else
  208.                     {
  209.                         select = true;
  210.                         nextSelect = true;
  211.                     }
  212.                 }
  213.                 (*it).m_selected = (*it).m_selected || select;
  214.                 select = nextSelect;
  215.                 index++;
  216.             }
  217.         }
  218.         else if( rEvent.getAsString().find( "mouse:left:down:ctrl" ) !=
  219.                  string::npos )
  220.         {
  221.             for( it = m_rList.begin(); it != m_rList.end(); it++ )
  222.             {
  223.                 if( index == yPos )
  224.                 {
  225.                     (*it).m_selected = ! (*it).m_selected;
  226.                     m_pLastSelected = &*it;
  227.                     break;
  228.                 }
  229.                 index++;
  230.             }
  231.         }
  232.         else if( rEvent.getAsString().find( "mouse:left:down:shift" ) !=
  233.                  string::npos )
  234.         {
  235.             // Flag to know if the current item must be selected
  236.             bool select = false;
  237.             for( it = m_rList.begin(); it != m_rList.end(); it++ )
  238.             {
  239.                 bool nextSelect = select;
  240.                 if( index == yPos ||  &*it == m_pLastSelected )
  241.                 {
  242.                     if( select )
  243.                     {
  244.                         nextSelect = false;
  245.                     }
  246.                     else
  247.                     {
  248.                         select = true;
  249.                         nextSelect = true;
  250.                     }
  251.                 }
  252.                 (*it).m_selected = select;
  253.                 select = nextSelect;
  254.                 index++;
  255.             }
  256.         }
  257.         else if( rEvent.getAsString().find( "mouse:left:down" ) !=
  258.                  string::npos )
  259.         {
  260.             for( it = m_rList.begin(); it != m_rList.end(); it++ )
  261.             {
  262.                 if( index == yPos )
  263.                 {
  264.                     (*it).m_selected = true;
  265.                     m_pLastSelected = &*it;
  266.                 }
  267.                 else
  268.                 {
  269.                     (*it).m_selected = false;
  270.                 }
  271.                 index++;
  272.             }
  273.         }
  274.         else if( rEvent.getAsString().find( "mouse:left:dblclick" ) !=
  275.                  string::npos )
  276.         {
  277.             for( it = m_rList.begin(); it != m_rList.end(); it++ )
  278.             {
  279.                 if( index == yPos )
  280.                 {
  281.                     (*it).m_selected = true;
  282.                     m_pLastSelected = &*it;
  283.                     // Execute the action associated to this item
  284.                     m_rList.action( &*it );
  285.                 }
  286.                 else
  287.                 {
  288.                     (*it).m_selected = false;
  289.                 }
  290.                 index++;
  291.             }
  292.         }
  293.         // Redraw the control
  294.         makeImage();
  295.         notifyLayout();
  296.     }
  297.     else if( rEvent.getAsString().find( "scroll" ) != string::npos )
  298.     {
  299.         int direction = ((EvtScroll&)rEvent).getDirection();
  300.         double percentage = m_rList.getPositionVar().get();
  301.         if( direction == EvtScroll::kUp )
  302.         {
  303.             percentage += SCROLL_STEP;
  304.         }
  305.         else
  306.         {
  307.             percentage -= SCROLL_STEP;
  308.         }
  309.         m_rList.getPositionVar().set( percentage );
  310.     }
  311. }
  312. bool CtrlList::mouseOver( int x, int y ) const
  313. {
  314.     const Position *pPos = getPosition();
  315.     if( pPos )
  316.     {
  317.         int width = pPos->getWidth();
  318.         int height = pPos->getHeight();
  319.         return ( x >= 0 && x <= width && y >= 0 && y <= height );
  320.     }
  321.     return false;
  322. }
  323. void CtrlList::draw( OSGraphics &rImage, int xDest, int yDest )
  324. {
  325.     if( m_pImage )
  326.     {
  327.         rImage.drawGraphics( *m_pImage, 0, 0, xDest, yDest );
  328.     }
  329. }
  330. void CtrlList::autoScroll()
  331. {
  332.     // Get the size of the control
  333.     const Position *pPos = getPosition();
  334.     if( !pPos )
  335.     {
  336.         return;
  337.     }
  338.     int height = pPos->getHeight();
  339.     // How many lines can be displayed ?
  340.     int itemHeight = m_rFont.getSize() + LINE_INTERVAL;
  341.     int maxItems = height / itemHeight;
  342.     // Find the current playing stream
  343.     int playIndex = 0;
  344.     VarList::ConstIterator it;
  345.     for( it = m_rList.begin(); it != m_rList.end(); it++ )
  346.     {
  347.         if( (*it).m_playing )
  348.         {
  349.             break;
  350.         }
  351.         playIndex++;
  352.     }
  353.     if( it != m_rList.end() &&
  354.         ( playIndex < m_lastPos || playIndex >= m_lastPos + maxItems ) )
  355.     {
  356.         // Scroll the list to have the playing stream visible
  357.         VarPercent &rVarPos = m_rList.getPositionVar();
  358.         rVarPos.set( 1.0 - (float)playIndex / (float)m_rList.size() );
  359.         // The image will be changed by onUpdate(VarPercent&)
  360.     }
  361.     else
  362.     {
  363.         makeImage();
  364.         notifyLayout();
  365.     }
  366. }
  367. void CtrlList::makeImage()
  368. {
  369.     if( m_pImage )
  370.     {
  371.         delete m_pImage;
  372.     }
  373.     // Get the size of the control
  374.     const Position *pPos = getPosition();
  375.     if( !pPos )
  376.     {
  377.         return;
  378.     }
  379.     int width = pPos->getWidth();
  380.     int height = pPos->getHeight();
  381.     int itemHeight = m_rFont.getSize() + LINE_INTERVAL;
  382.     // Create an image
  383.     OSFactory *pOsFactory = OSFactory::instance( getIntf() );
  384.     m_pImage = pOsFactory->createOSGraphics( width, height );
  385.     // Current background color
  386.     uint32_t bgColor = m_bgColor1;
  387.     // Draw the background
  388.     VarList::ConstIterator it = m_rList[m_lastPos];
  389.     for( int yPos = 0; yPos < height; yPos += itemHeight )
  390.     {
  391.         int rectHeight = __MIN( itemHeight, height - yPos );
  392.         if( it != m_rList.end() )
  393.         {
  394.             uint32_t color = ( (*it).m_selected ? m_selColor : bgColor );
  395.             m_pImage->fillRect( 0, yPos, width, rectHeight, color );
  396.             it++;
  397.         }
  398.         else
  399.         {
  400.             m_pImage->fillRect( 0, yPos, width, rectHeight, bgColor );
  401.         }
  402.         // Flip the background color
  403.         bgColor = ( bgColor == m_bgColor1 ? m_bgColor2 : m_bgColor1 );
  404.     }
  405.     // Draw the items
  406.     int yPos = 0;
  407.     for( it = m_rList[m_lastPos]; it != m_rList.end() && yPos < height; it++ )
  408.     {
  409.         UString *pStr = (UString*)((*it).m_cString.get());
  410.         uint32_t color = ( (*it).m_playing ? m_playColor : m_fgColor );
  411.         // Draw the text
  412.         GenericBitmap *pText = m_rFont.drawString( *pStr, color, width );
  413.         if( !pText )
  414.         {
  415.             return;
  416.         }
  417.         yPos += itemHeight - pText->getHeight();
  418.         int ySrc = 0;
  419.         if( yPos < 0 )
  420.         {
  421.             ySrc = - yPos;
  422.             yPos = 0;
  423.         }
  424.         int lineHeight = __MIN( pText->getHeight() - ySrc, height - yPos );
  425.         m_pImage->drawBitmap( *pText, 0, ySrc, 0, yPos, pText->getWidth(),
  426.                               lineHeight );
  427.         yPos += (pText->getHeight() - ySrc );
  428.         delete pText;
  429.     }
  430. }