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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * ctrl_list.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2003 the VideoLAN team
  5.  * $Id: c4c4cff50b308bb69b5722e46e05c947ac41650a $
  6.  *
  7.  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
  8.  *          Olivier Teulière <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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, 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 "../src/scaled_bitmap.hpp"
  31. #include "../utils/position.hpp"
  32. #include "../utils/ustring.hpp"
  33. #include "../events/evt_key.hpp"
  34. #include "../events/evt_mouse.hpp"
  35. #include "../events/evt_scroll.hpp"
  36. #include "vlc_keys.h"
  37. #define SCROLL_STEP 0.05f
  38. #define LINE_INTERVAL 1  // Number of pixels inserted between 2 lines
  39. CtrlList::CtrlList( intf_thread_t *pIntf, VarList &rList,
  40.                     const GenericFont &rFont, const GenericBitmap *pBitmap,
  41.                     uint32_t fgColor, uint32_t playColor, uint32_t bgColor1,
  42.                     uint32_t bgColor2, uint32_t selColor,
  43.                     const UString &rHelp, VarBool *pVisible ):
  44.     CtrlGeneric( pIntf, rHelp, pVisible ), m_rList( rList ), m_rFont( rFont ),
  45.     m_pBitmap( pBitmap ), m_fgColor( fgColor ), m_playColor( playColor ),
  46.     m_bgColor1( bgColor1 ), m_bgColor2( bgColor2 ), m_selColor( selColor ),
  47.     m_pLastSelected( NULL ), m_pImage( NULL ), m_lastPos( 0 )
  48. {
  49.     // Observe the list and position variables
  50.     m_rList.addObserver( this );
  51.     m_rList.getPositionVar().addObserver( this );
  52.     makeImage();
  53. }
  54. CtrlList::~CtrlList()
  55. {
  56.     m_rList.getPositionVar().delObserver( this );
  57.     m_rList.delObserver( this );
  58.     if( m_pImage )
  59.     {
  60.         delete m_pImage;
  61.     }
  62. }
  63. void CtrlList::onUpdate( Subject<VarList> &rList, void *arg  )
  64. {
  65.     autoScroll();
  66.     m_pLastSelected = NULL;
  67. }
  68. void CtrlList::onUpdate( Subject<VarPercent> &rPercent, void *arg  )
  69. {
  70.     // Get the size of the control
  71.     const Position *pPos = getPosition();
  72.     if( !pPos )
  73.     {
  74.         return;
  75.     }
  76.     int height = pPos->getHeight();
  77.     // How many lines can be displayed ?
  78.     int itemHeight = m_rFont.getSize() + LINE_INTERVAL;
  79.     int maxItems = height / itemHeight;
  80.     // Determine what is the first item to display
  81.     VarPercent &rVarPos = m_rList.getPositionVar();
  82.     int firstItem = 0;
  83.     int excessItems = m_rList.size() - maxItems;
  84.     if( excessItems > 0 )
  85.     {
  86.         // a simple (int)(...) causes rounding errors !
  87. #ifdef _MSC_VER
  88. #   define lrint (int)
  89. #endif
  90.         firstItem = lrint( (1.0 - rVarPos.get()) * (double)excessItems );
  91.     }
  92.     if( m_lastPos != firstItem )
  93.     {
  94.         // Redraw the control if the position has changed
  95.         m_lastPos = firstItem;
  96.         makeImage();
  97.         notifyLayout();
  98.     }
  99. }
  100. void CtrlList::onResize()
  101. {
  102.     // Get the size of the control
  103.     const Position *pPos = getPosition();
  104.     if( !pPos )
  105.     {
  106.         return;
  107.     }
  108.     int height = pPos->getHeight();
  109.     // How many lines can be displayed ?
  110.     int itemHeight = m_rFont.getSize() + LINE_INTERVAL;
  111.     int maxItems = height / itemHeight;
  112.     // Update the position variable
  113.     VarPercent &rVarPos = m_rList.getPositionVar();
  114.     int excessItems = m_rList.size() - maxItems;
  115.     if( excessItems > 0 )
  116.     {
  117.         double newVal = 1.0 - (double)m_lastPos / excessItems;
  118.         if( newVal >= 0 )
  119.         {
  120.             // Change the position to keep the same first displayed item
  121.             rVarPos.set( 1.0 - (double)m_lastPos / excessItems );
  122.         }
  123.         else
  124.         {
  125.             // We cannot keep the current first item
  126.             m_lastPos = excessItems;
  127.         }
  128.     }
  129.     makeImage();
  130.     notifyLayout();
  131. }
  132. void CtrlList::onPositionChange()
  133. {
  134.     makeImage();
  135.     notifyLayout();
  136. }
  137. void CtrlList::handleEvent( EvtGeneric &rEvent )
  138. {
  139.     if( rEvent.getAsString().find( "key:down" ) != string::npos )
  140.     {
  141.         int key = ((EvtKey&)rEvent).getKey();
  142.         VarList::Iterator it = m_rList.begin();
  143.         bool previousWasSelected = false;
  144.         while( it != m_rList.end() )
  145.         {
  146.             VarList::Iterator next = it;
  147.             ++next;
  148.             if( key == KEY_UP )
  149.             {
  150.                 // Scroll up one item
  151.                 if( it != m_rList.begin() || &*it != m_pLastSelected )
  152.                 {
  153.                     bool nextWasSelected = ( &*next == m_pLastSelected );
  154.                     (*it).m_selected = nextWasSelected;
  155.                     if( nextWasSelected )
  156.                     {
  157.                         m_pLastSelected = &*it;
  158.                     }
  159.                 }
  160.             }
  161.             else if( key == KEY_DOWN )
  162.             {
  163.                 // Scroll down one item
  164.                 if( next != m_rList.end() || &*it != m_pLastSelected )
  165.                 {
  166.                     (*it).m_selected = previousWasSelected;
  167.                 }
  168.                 if( previousWasSelected )
  169.                 {
  170.                     m_pLastSelected = &*it;
  171.                     previousWasSelected = false;
  172.                 }
  173.                 else
  174.                 {
  175.                     previousWasSelected = ( &*it == m_pLastSelected );
  176.                 }
  177.             }
  178.             it = next;
  179.         }
  180.         // Redraw the control
  181.         makeImage();
  182.         notifyLayout();
  183.     }
  184.     else if( rEvent.getAsString().find( "mouse:left" ) != string::npos )
  185.     {
  186.         EvtMouse &rEvtMouse = (EvtMouse&)rEvent;
  187.         const Position *pos = getPosition();
  188.         int yPos = m_lastPos + ( rEvtMouse.getYPos() - pos->getTop() ) /
  189.             (m_rFont.getSize() + LINE_INTERVAL);
  190.         VarList::Iterator it;
  191.         int index = 0;
  192.         if( rEvent.getAsString().find( "mouse:left:down:ctrl,shift" ) !=
  193.                  string::npos )
  194.         {
  195.             // Flag to know if the current item must be selected
  196.             bool select = false;
  197.             for( it = m_rList.begin(); it != m_rList.end(); it++ )
  198.             {
  199.                 bool nextSelect = select;
  200.                 if( index == yPos || &*it == m_pLastSelected )
  201.                 {
  202.                     if( select )
  203.                     {
  204.                         nextSelect = false;
  205.                     }
  206.                     else
  207.                     {
  208.                         select = true;
  209.                         nextSelect = true;
  210.                     }
  211.                 }
  212.                 (*it).m_selected = (*it).m_selected || select;
  213.                 select = nextSelect;
  214.                 index++;
  215.             }
  216.         }
  217.         else if( rEvent.getAsString().find( "mouse:left:down:ctrl" ) !=
  218.                  string::npos )
  219.         {
  220.             for( it = m_rList.begin(); it != m_rList.end(); it++ )
  221.             {
  222.                 if( index == yPos )
  223.                 {
  224.                     (*it).m_selected = ! (*it).m_selected;
  225.                     m_pLastSelected = &*it;
  226.                     break;
  227.                 }
  228.                 index++;
  229.             }
  230.         }
  231.         else if( rEvent.getAsString().find( "mouse:left:down:shift" ) !=
  232.                  string::npos )
  233.         {
  234.             // Flag to know if the current item must be selected
  235.             bool select = false;
  236.             for( it = m_rList.begin(); it != m_rList.end(); it++ )
  237.             {
  238.                 bool nextSelect = select;
  239.                 if( index == yPos ||  &*it == m_pLastSelected )
  240.                 {
  241.                     if( select )
  242.                     {
  243.                         nextSelect = false;
  244.                     }
  245.                     else
  246.                     {
  247.                         select = true;
  248.                         nextSelect = true;
  249.                     }
  250.                 }
  251.                 (*it).m_selected = select;
  252.                 select = nextSelect;
  253.                 index++;
  254.             }
  255.         }
  256.         else if( rEvent.getAsString().find( "mouse:left:down" ) !=
  257.                  string::npos )
  258.         {
  259.             for( it = m_rList.begin(); it != m_rList.end(); it++ )
  260.             {
  261.                 if( index == yPos )
  262.                 {
  263.                     (*it).m_selected = true;
  264.                     m_pLastSelected = &*it;
  265.                 }
  266.                 else
  267.                 {
  268.                     (*it).m_selected = false;
  269.                 }
  270.                 index++;
  271.             }
  272.         }
  273.         else if( rEvent.getAsString().find( "mouse:left:dblclick" ) !=
  274.                  string::npos )
  275.         {
  276.             for( it = m_rList.begin(); it != m_rList.end(); it++ )
  277.             {
  278.                 if( index == yPos )
  279.                 {
  280.                     (*it).m_selected = true;
  281.                     m_pLastSelected = &*it;
  282.                     // Execute the action associated to this item
  283.                     m_rList.action( &*it );
  284.                 }
  285.                 else
  286.                 {
  287.                     (*it).m_selected = false;
  288.                 }
  289.                 index++;
  290.             }
  291.         }
  292.         // Redraw the control
  293.         makeImage();
  294.         notifyLayout();
  295.     }
  296.     else if( rEvent.getAsString().find( "scroll" ) != string::npos )
  297.     {
  298.         int direction = ((EvtScroll&)rEvent).getDirection();
  299.         double percentage = m_rList.getPositionVar().get();
  300.         double step = 2.0 / (double)m_rList.size();
  301.         if( direction == EvtScroll::kUp )
  302.         {
  303.             percentage += step;
  304.         }
  305.         else
  306.         {
  307.             percentage -= 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.     VarList::ConstIterator it = m_rList[m_lastPos];
  386.     // Draw the background
  387.     if( m_pBitmap )
  388.     {
  389.         // A background bitmap is given, so we scale it, ignoring the
  390.         // background colors
  391.         ScaledBitmap bmp( getIntf(), *m_pBitmap, width, height );
  392.         m_pImage->drawBitmap( bmp, 0, 0 );
  393.         // Take care of the selection color
  394.         for( int yPos = 0; yPos < height; yPos += itemHeight )
  395.         {
  396.             int rectHeight = __MIN( itemHeight, height - yPos );
  397.             if( it != m_rList.end() )
  398.             {
  399.                 if( (*it).m_selected )
  400.                 {
  401.                     m_pImage->fillRect( 0, yPos, width, rectHeight,
  402.                                         m_selColor );
  403.                 }
  404.                 it++;
  405.             }
  406.         }
  407.     }
  408.     else
  409.     {
  410.         // No background bitmap, so use the 2 background colors
  411.         // Current background color
  412.         uint32_t bgColor = m_bgColor1;
  413.         for( int yPos = 0; yPos < height; yPos += itemHeight )
  414.         {
  415.             int rectHeight = __MIN( itemHeight, height - yPos );
  416.             if( it != m_rList.end() )
  417.             {
  418.                 uint32_t color = ( (*it).m_selected ? m_selColor : bgColor );
  419.                 m_pImage->fillRect( 0, yPos, width, rectHeight, color );
  420.                 it++;
  421.             }
  422.             else
  423.             {
  424.                 m_pImage->fillRect( 0, yPos, width, rectHeight, bgColor );
  425.             }
  426.             // Flip the background color
  427.             bgColor = ( bgColor == m_bgColor1 ? m_bgColor2 : m_bgColor1 );
  428.         }
  429.     }
  430.     // Draw the items
  431.     int yPos = 0;
  432.     for( it = m_rList[m_lastPos]; it != m_rList.end() && yPos < height; it++ )
  433.     {
  434.         UString *pStr = (UString*)(it->m_cString.get());
  435.         uint32_t color = ( it->m_playing ? m_playColor : m_fgColor );
  436.         // Draw the text
  437.         GenericBitmap *pText = m_rFont.drawString( *pStr, color, width );
  438.         if( !pText )
  439.         {
  440.             return;
  441.         }
  442.         yPos += itemHeight - pText->getHeight();
  443.         int ySrc = 0;
  444.         if( yPos < 0 )
  445.         {
  446.             ySrc = - yPos;
  447.             yPos = 0;
  448.         }
  449.         int lineHeight = __MIN( pText->getHeight() - ySrc, height - yPos );
  450.         m_pImage->drawBitmap( *pText, 0, ySrc, 0, yPos, pText->getWidth(),
  451.                               lineHeight, true );
  452.         yPos += (pText->getHeight() - ySrc );
  453.         delete pText;
  454.     }
  455. }