1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
5 * $Id: ctrl_list.cpp,v 1.3 2004/02/29 16:49:55 asmax Exp $
7 * Authors: Cyril Deguet <asmax@via.ecp.fr>
8 * Olivier Teulière <ipkiss@via.ecp.fr>
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.
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.
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 *****************************************************************************/
26 #include "ctrl_list.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 "../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"
38 #define SCROLL_STEP 0.05
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 )
50 // Observe the list and position variables
51 m_rList.addObserver( this );
52 m_rList.getPositionVar().addObserver( this );
60 m_rList.getPositionVar().delObserver( this );
61 m_rList.delObserver( this );
69 void CtrlList::onUpdate( Subject<VarList> &rList )
73 m_pLastSelected = NULL;
77 void CtrlList::onUpdate( Subject<VarPercent> &rPercent )
79 // Get the size of the control
80 const Position *pPos = getPosition();
85 int height = pPos->getHeight();
87 // How many lines can be displayed ?
88 int itemHeight = m_rFont.getSize();
89 int maxItems = height / itemHeight;
91 // Determine what is the first item to display
92 VarPercent &rVarPos = m_rList.getPositionVar();
94 int excessItems = m_rList.size() - maxItems;
97 // a simple (int)(...) causes rounding errors !
101 firstItem = lrint( (1.0 - rVarPos.get()) * (double)excessItems );
103 if( m_lastPos != firstItem )
105 // Redraw the control if the position has changed
106 m_lastPos = firstItem;
113 void CtrlList::onResize()
115 // Get the size of the control
116 const Position *pPos = getPosition();
121 int height = pPos->getHeight();
123 // How many lines can be displayed ?
124 int itemHeight = m_rFont.getSize();
125 int maxItems = height / itemHeight;
127 // Update the position variable
128 VarPercent &rVarPos = m_rList.getPositionVar();
129 int excessItems = m_rList.size() - maxItems;
130 if( excessItems > 0 )
132 double newVal = 1.0 - (double)m_lastPos / excessItems;
135 // Change the position to keep the same first displayed item
136 rVarPos.set( 1.0 - (double)m_lastPos / excessItems );
140 // We cannot keep the current first item
141 m_lastPos = excessItems;
150 void CtrlList::onPositionChange()
157 void CtrlList::handleEvent( EvtGeneric &rEvent )
159 if( rEvent.getAsString().find( "key:down" ) != string::npos )
161 char key = ((EvtKey&)rEvent).getKey();
164 else if( rEvent.getAsString().find( "mouse:left" ) != string::npos )
166 EvtMouse &rEvtMouse = (EvtMouse&)rEvent;
167 const Position *pos = getPosition();
168 int yPos = m_lastPos +
169 ( rEvtMouse.getYPos() - pos->getTop() ) / m_rFont.getSize();
170 VarList::Iterator it;
173 if( rEvent.getAsString().find( "mouse:left:down:ctrl,shift" ) !=
176 // Flag to know if the current item must be selected
178 for( it = m_rList.begin(); it != m_rList.end(); it++ )
180 bool nextSelect = select;
181 if( index == yPos || &*it == m_pLastSelected )
193 (*it).m_selected = (*it).m_selected || select;
199 else if( rEvent.getAsString().find( "mouse:left:down:ctrl" ) !=
202 for( it = m_rList.begin(); it != m_rList.end(); it++ )
206 (*it).m_selected = ! (*it).m_selected;
207 m_pLastSelected = &*it;
214 else if( rEvent.getAsString().find( "mouse:left:down:shift" ) !=
217 // Flag to know if the current item must be selected
219 for( it = m_rList.begin(); it != m_rList.end(); it++ )
221 bool nextSelect = select;
222 if( index == yPos || &*it == m_pLastSelected )
234 (*it).m_selected = select;
240 else if( rEvent.getAsString().find( "mouse:left:down" ) !=
243 for( it = m_rList.begin(); it != m_rList.end(); it++ )
247 (*it).m_selected = true;
248 m_pLastSelected = &*it;
252 (*it).m_selected = false;
258 else if( rEvent.getAsString().find( "mouse:left:dblclick" ) !=
261 for( it = m_rList.begin(); it != m_rList.end(); it++ )
265 (*it).m_selected = true;
266 m_pLastSelected = &*it;
267 // Execute the action associated to this item
268 m_rList.action( &*it );
272 (*it).m_selected = false;
278 // Redraw the control
283 else if( rEvent.getAsString().find( "scroll" ) != string::npos )
285 int direction = ((EvtScroll&)rEvent).getDirection();
287 double percentage = m_rList.getPositionVar().get();
288 if( direction == EvtScroll::kUp )
290 percentage += SCROLL_STEP;
294 percentage -= SCROLL_STEP;
296 m_rList.getPositionVar().set( percentage );
301 bool CtrlList::mouseOver( int x, int y ) const
303 const Position *pPos = getPosition();
306 int width = pPos->getWidth();
307 int height = pPos->getHeight();
308 return ( x >= 0 && x <= width && y >= 0 && y <= height );
314 void CtrlList::draw( OSGraphics &rImage, int xDest, int yDest )
318 rImage.drawGraphics( *m_pImage, 0, 0, xDest, yDest );
323 void CtrlList::makeImage()
330 // Get the size of the control
331 const Position *pPos = getPosition();
336 int width = pPos->getWidth();
337 int height = pPos->getHeight();
338 int itemHeight = m_rFont.getSize();
341 OSFactory *pOsFactory = OSFactory::instance( getIntf() );
342 m_pImage = pOsFactory->createOSGraphics( width, height );
344 // Current background color
345 uint32_t bgColor = m_bgColor1;
347 // Draw the background
348 VarList::ConstIterator it = m_rList[m_lastPos];
349 for( int yPos = 0; yPos < height; yPos += itemHeight )
351 int rectHeight = __MIN( itemHeight, height - yPos );
352 if( it != m_rList.end() )
354 uint32_t color = ( (*it).m_selected ? m_selColor : bgColor );
355 m_pImage->fillRect( 0, yPos, width, rectHeight, color );
360 m_pImage->fillRect( 0, yPos, width, rectHeight, bgColor );
362 // Flip the background color
363 bgColor = ( bgColor == m_bgColor1 ? m_bgColor2 : m_bgColor1 );
368 for( it = m_rList[m_lastPos]; it != m_rList.end() && yPos < height; it++ )
370 UString *pStr = (UString*)((*it).m_cString.get());
371 uint32_t color = ( (*it).m_playing ? m_playColor : m_fgColor );
374 GenericBitmap *pText = m_rFont.drawString( *pStr, color, width );
375 yPos += itemHeight - pText->getHeight();
382 int lineHeight = __MIN( pText->getHeight() - ySrc, height - yPos );
383 m_pImage->drawBitmap( *pText, 0, ySrc, 0, yPos, pText->getWidth(),
385 yPos += (pText->getHeight() - ySrc );