00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <math.h>
00026 #include "ctrl_list.hpp"
00027 #include "../src/os_factory.hpp"
00028 #include "../src/os_graphics.hpp"
00029 #include "../src/generic_bitmap.hpp"
00030 #include "../src/generic_font.hpp"
00031 #include "../src/scaled_bitmap.hpp"
00032 #include "../utils/position.hpp"
00033 #include "../utils/ustring.hpp"
00034 #include "../events/evt_key.hpp"
00035 #include "../events/evt_mouse.hpp"
00036 #include "../events/evt_scroll.hpp"
00037 #include "vlc_keys.h"
00038 #ifdef sun
00039 # include "solaris_specific.h"
00040 #endif
00041
00042 #define SCROLL_STEP 0.05f
00043 #define LINE_INTERVAL 1 // Number of pixels inserted between 2 lines
00044
00045
00046 CtrlList::CtrlList( intf_thread_t *pIntf, VarList &rList,
00047 const GenericFont &rFont, const GenericBitmap *pBitmap,
00048 uint32_t fgColor, uint32_t playColor, uint32_t bgColor1,
00049 uint32_t bgColor2, uint32_t selColor,
00050 const UString &rHelp, VarBool *pVisible ):
00051 CtrlGeneric( pIntf, rHelp, pVisible ), m_rList( rList ), m_rFont( rFont ),
00052 m_pBitmap( pBitmap ), m_fgColor( fgColor ), m_playColor( playColor ),
00053 m_bgColor1( bgColor1 ), m_bgColor2( bgColor2 ), m_selColor( selColor ),
00054 m_pLastSelected( NULL ), m_pImage( NULL ), m_lastPos( 0 )
00055 {
00056
00057 m_rList.addObserver( this );
00058 m_rList.getPositionVar().addObserver( this );
00059
00060 makeImage();
00061 }
00062
00063
00064 CtrlList::~CtrlList()
00065 {
00066 m_rList.getPositionVar().delObserver( this );
00067 m_rList.delObserver( this );
00068 if( m_pImage )
00069 {
00070 delete m_pImage;
00071 }
00072 }
00073
00074
00075 void CtrlList::onUpdate( Subject<VarList> &rList )
00076 {
00077 autoScroll();
00078 m_pLastSelected = NULL;
00079 }
00080
00081
00082 void CtrlList::onUpdate( Subject<VarPercent> &rPercent )
00083 {
00084
00085 const Position *pPos = getPosition();
00086 if( !pPos )
00087 {
00088 return;
00089 }
00090 int height = pPos->getHeight();
00091
00092
00093 int itemHeight = m_rFont.getSize() + LINE_INTERVAL;
00094 int maxItems = height / itemHeight;
00095
00096
00097 VarPercent &rVarPos = m_rList.getPositionVar();
00098 int firstItem = 0;
00099 int excessItems = m_rList.size() - maxItems;
00100 if( excessItems > 0 )
00101 {
00102
00103 #ifdef _MSC_VER
00104 # define lrint (int)
00105 #endif
00106 firstItem = lrint( (1.0 - rVarPos.get()) * (double)excessItems );
00107 }
00108 if( m_lastPos != firstItem )
00109 {
00110
00111 m_lastPos = firstItem;
00112 makeImage();
00113 notifyLayout();
00114 }
00115 }
00116
00117
00118 void CtrlList::onResize()
00119 {
00120
00121 const Position *pPos = getPosition();
00122 if( !pPos )
00123 {
00124 return;
00125 }
00126 int height = pPos->getHeight();
00127
00128
00129 int itemHeight = m_rFont.getSize() + LINE_INTERVAL;
00130 int maxItems = height / itemHeight;
00131
00132
00133 VarPercent &rVarPos = m_rList.getPositionVar();
00134 int excessItems = m_rList.size() - maxItems;
00135 if( excessItems > 0 )
00136 {
00137 double newVal = 1.0 - (double)m_lastPos / excessItems;
00138 if( newVal >= 0 )
00139 {
00140
00141 rVarPos.set( 1.0 - (double)m_lastPos / excessItems );
00142 }
00143 else
00144 {
00145
00146 m_lastPos = excessItems;
00147 }
00148 }
00149
00150 makeImage();
00151 notifyLayout();
00152 }
00153
00154
00155 void CtrlList::onPositionChange()
00156 {
00157 makeImage();
00158 notifyLayout();
00159 }
00160
00161
00162 void CtrlList::handleEvent( EvtGeneric &rEvent )
00163 {
00164 if( rEvent.getAsString().find( "key:down" ) != string::npos )
00165 {
00166 int key = ((EvtKey&)rEvent).getKey();
00167 VarList::Iterator it = m_rList.begin();
00168 bool previousWasSelected = false;
00169 while( it != m_rList.end() )
00170 {
00171 VarList::Iterator next = it;
00172 ++next;
00173 if( key == KEY_UP )
00174 {
00175
00176 if( it != m_rList.begin() || &*it != m_pLastSelected )
00177 {
00178 bool nextWasSelected = ( &*next == m_pLastSelected );
00179 (*it).m_selected = nextWasSelected;
00180 if( nextWasSelected )
00181 {
00182 m_pLastSelected = &*it;
00183 }
00184 }
00185 }
00186 else if( key == KEY_DOWN )
00187 {
00188
00189 if( next != m_rList.end() || &*it != m_pLastSelected )
00190 {
00191 (*it).m_selected = previousWasSelected;
00192 }
00193 if( previousWasSelected )
00194 {
00195 m_pLastSelected = &*it;
00196 previousWasSelected = false;
00197 }
00198 else
00199 {
00200 previousWasSelected = ( &*it == m_pLastSelected );
00201 }
00202 }
00203 it = next;
00204 }
00205
00206
00207 makeImage();
00208 notifyLayout();
00209 }
00210
00211 else if( rEvent.getAsString().find( "mouse:left" ) != string::npos )
00212 {
00213 EvtMouse &rEvtMouse = (EvtMouse&)rEvent;
00214 const Position *pos = getPosition();
00215 int yPos = m_lastPos + ( rEvtMouse.getYPos() - pos->getTop() ) /
00216 (m_rFont.getSize() + LINE_INTERVAL);
00217 VarList::Iterator it;
00218 int index = 0;
00219
00220 if( rEvent.getAsString().find( "mouse:left:down:ctrl,shift" ) !=
00221 string::npos )
00222 {
00223
00224 bool select = false;
00225 for( it = m_rList.begin(); it != m_rList.end(); it++ )
00226 {
00227 bool nextSelect = select;
00228 if( index == yPos || &*it == m_pLastSelected )
00229 {
00230 if( select )
00231 {
00232 nextSelect = false;
00233 }
00234 else
00235 {
00236 select = true;
00237 nextSelect = true;
00238 }
00239 }
00240 (*it).m_selected = (*it).m_selected || select;
00241 select = nextSelect;
00242 index++;
00243 }
00244 }
00245
00246 else if( rEvent.getAsString().find( "mouse:left:down:ctrl" ) !=
00247 string::npos )
00248 {
00249 for( it = m_rList.begin(); it != m_rList.end(); it++ )
00250 {
00251 if( index == yPos )
00252 {
00253 (*it).m_selected = ! (*it).m_selected;
00254 m_pLastSelected = &*it;
00255 break;
00256 }
00257 index++;
00258 }
00259 }
00260
00261 else if( rEvent.getAsString().find( "mouse:left:down:shift" ) !=
00262 string::npos )
00263 {
00264
00265 bool select = false;
00266 for( it = m_rList.begin(); it != m_rList.end(); it++ )
00267 {
00268 bool nextSelect = select;
00269 if( index == yPos || &*it == m_pLastSelected )
00270 {
00271 if( select )
00272 {
00273 nextSelect = false;
00274 }
00275 else
00276 {
00277 select = true;
00278 nextSelect = true;
00279 }
00280 }
00281 (*it).m_selected = select;
00282 select = nextSelect;
00283 index++;
00284 }
00285 }
00286
00287 else if( rEvent.getAsString().find( "mouse:left:down" ) !=
00288 string::npos )
00289 {
00290 for( it = m_rList.begin(); it != m_rList.end(); it++ )
00291 {
00292 if( index == yPos )
00293 {
00294 (*it).m_selected = true;
00295 m_pLastSelected = &*it;
00296 }
00297 else
00298 {
00299 (*it).m_selected = false;
00300 }
00301 index++;
00302 }
00303 }
00304
00305 else if( rEvent.getAsString().find( "mouse:left:dblclick" ) !=
00306 string::npos )
00307 {
00308 for( it = m_rList.begin(); it != m_rList.end(); it++ )
00309 {
00310 if( index == yPos )
00311 {
00312 (*it).m_selected = true;
00313 m_pLastSelected = &*it;
00314
00315 m_rList.action( &*it );
00316 }
00317 else
00318 {
00319 (*it).m_selected = false;
00320 }
00321 index++;
00322 }
00323 }
00324
00325
00326 makeImage();
00327 notifyLayout();
00328 }
00329
00330 else if( rEvent.getAsString().find( "scroll" ) != string::npos )
00331 {
00332 int direction = ((EvtScroll&)rEvent).getDirection();
00333
00334 double percentage = m_rList.getPositionVar().get();
00335 double step = 2.0 / (double)m_rList.size();
00336 if( direction == EvtScroll::kUp )
00337 {
00338 percentage += step;
00339 }
00340 else
00341 {
00342 percentage -= step;
00343 }
00344 m_rList.getPositionVar().set( percentage );
00345 }
00346 }
00347
00348
00349 bool CtrlList::mouseOver( int x, int y ) const
00350 {
00351 const Position *pPos = getPosition();
00352 if( pPos )
00353 {
00354 int width = pPos->getWidth();
00355 int height = pPos->getHeight();
00356 return ( x >= 0 && x <= width && y >= 0 && y <= height );
00357 }
00358 return false;
00359 }
00360
00361
00362 void CtrlList::draw( OSGraphics &rImage, int xDest, int yDest )
00363 {
00364 if( m_pImage )
00365 {
00366 rImage.drawGraphics( *m_pImage, 0, 0, xDest, yDest );
00367 }
00368 }
00369
00370
00371 void CtrlList::autoScroll()
00372 {
00373
00374 const Position *pPos = getPosition();
00375 if( !pPos )
00376 {
00377 return;
00378 }
00379 int height = pPos->getHeight();
00380
00381
00382 int itemHeight = m_rFont.getSize() + LINE_INTERVAL;
00383 int maxItems = height / itemHeight;
00384
00385
00386 int playIndex = 0;
00387 VarList::ConstIterator it;
00388 for( it = m_rList.begin(); it != m_rList.end(); it++ )
00389 {
00390 if( (*it).m_playing )
00391 {
00392 break;
00393 }
00394 playIndex++;
00395 }
00396 if( it != m_rList.end() &&
00397 ( playIndex < m_lastPos || playIndex >= m_lastPos + maxItems ) )
00398 {
00399
00400 VarPercent &rVarPos = m_rList.getPositionVar();
00401 rVarPos.set( 1.0 - (float)playIndex / (float)m_rList.size() );
00402
00403 }
00404 else
00405 {
00406 makeImage();
00407 notifyLayout();
00408 }
00409 }
00410
00411
00412 void CtrlList::makeImage()
00413 {
00414 if( m_pImage )
00415 {
00416 delete m_pImage;
00417 }
00418
00419
00420 const Position *pPos = getPosition();
00421 if( !pPos )
00422 {
00423 return;
00424 }
00425 int width = pPos->getWidth();
00426 int height = pPos->getHeight();
00427 int itemHeight = m_rFont.getSize() + LINE_INTERVAL;
00428
00429
00430 OSFactory *pOsFactory = OSFactory::instance( getIntf() );
00431 m_pImage = pOsFactory->createOSGraphics( width, height );
00432
00433 VarList::ConstIterator it = m_rList[m_lastPos];
00434
00435
00436 if( m_pBitmap )
00437 {
00438
00439
00440 ScaledBitmap bmp( getIntf(), *m_pBitmap, width, height );
00441 m_pImage->drawBitmap( bmp, 0, 0 );
00442
00443
00444 for( int yPos = 0; yPos < height; yPos += itemHeight )
00445 {
00446 int rectHeight = __MIN( itemHeight, height - yPos );
00447 if( it != m_rList.end() )
00448 {
00449 if( (*it).m_selected )
00450 {
00451 m_pImage->fillRect( 0, yPos, width, rectHeight,
00452 m_selColor );
00453 }
00454 it++;
00455 }
00456 }
00457 }
00458 else
00459 {
00460
00461
00462 uint32_t bgColor = m_bgColor1;
00463 for( int yPos = 0; yPos < height; yPos += itemHeight )
00464 {
00465 int rectHeight = __MIN( itemHeight, height - yPos );
00466 if( it != m_rList.end() )
00467 {
00468 uint32_t color = ( (*it).m_selected ? m_selColor : bgColor );
00469 m_pImage->fillRect( 0, yPos, width, rectHeight, color );
00470 it++;
00471 }
00472 else
00473 {
00474 m_pImage->fillRect( 0, yPos, width, rectHeight, bgColor );
00475 }
00476
00477 bgColor = ( bgColor == m_bgColor1 ? m_bgColor2 : m_bgColor1 );
00478 }
00479 }
00480
00481
00482 int yPos = 0;
00483 for( it = m_rList[m_lastPos]; it != m_rList.end() && yPos < height; it++ )
00484 {
00485 UString *pStr = (UString*)(it->m_cString.get());
00486 uint32_t color = ( it->m_playing ? m_playColor : m_fgColor );
00487
00488
00489 GenericBitmap *pText = m_rFont.drawString( *pStr, color, width );
00490 if( !pText )
00491 {
00492 return;
00493 }
00494 yPos += itemHeight - pText->getHeight();
00495 int ySrc = 0;
00496 if( yPos < 0 )
00497 {
00498 ySrc = - yPos;
00499 yPos = 0;
00500 }
00501 int lineHeight = __MIN( pText->getHeight() - ySrc, height - yPos );
00502 m_pImage->drawBitmap( *pText, 0, ySrc, 0, yPos, pText->getWidth(),
00503 lineHeight, true );
00504 yPos += (pText->getHeight() - ySrc );
00505 delete pText;
00506
00507 }
00508 }
00509