]> git.sesse.net Git - vlc/blob - modules/gui/skins/controls/playlist.cpp
* now selection method in the playlist depends on the state of the
[vlc] / modules / gui / skins / controls / playlist.cpp
1 /*****************************************************************************
2  * playlist.cpp: Playlist control
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: playlist.cpp,v 1.14 2003/06/09 14:04:20 asmax Exp $
6  *
7  * Authors: Olivier Teulière <ipkiss@via.ecp.fr>
8  *          Emmanuel Puig    <karibu@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,
23  * USA.
24  *****************************************************************************/
25
26
27 //--- GENERAL ---------------------------------------------------------------
28 #include <math.h>
29
30 //--- VLC -------------------------------------------------------------------
31 #include <vlc/intf.h>
32
33 //--- SKIN ------------------------------------------------------------------
34 #include "../os_api.h"
35 #include "../src/bitmap.h"
36 #include "../src/banks.h"
37 #include "../src/bezier.h"
38 #include "../src/graphics.h"
39 #include "../os_graphics.h"
40 #include "../src/font.h"
41 #include "../os_font.h"
42 #include "generic.h"
43 #include "slider.h"
44 #include "playlist.h"
45 #include "../src/event.h"
46 #include "../src/theme.h"
47 #include "../src/window.h"
48 #include "../src/skin_common.h"
49
50
51
52 //---------------------------------------------------------------------------
53 // Control Playlist
54 //---------------------------------------------------------------------------
55 ControlPlayList::ControlPlayList( string id, bool visible, int width,
56     int infowidth, string font, string playfont, int selcolor, double *ptx,
57     double *pty, int nb, bool longfilename, string help, SkinWindow *Parent )
58     : GenericControl( id, visible, help, Parent )
59 {
60     Left          = 0;
61     Top           = 0;
62     Column        = 1;
63     Line          = 1;
64     Margin        = 1;
65     Enabled       = true;
66     FontName      = font;
67     PlayFontName  = playfont;
68
69     // Text zone
70     CaseWidth    = width;
71     InfoWidth    = infowidth;
72     NumWidth     = 0;
73     FileWidth    = 0;
74     CaseHeight   = 1;
75     NumOfItems   = 0;
76     SelectColor  = selcolor;
77     TextCurve    = new Bezier( ptx, pty, nb, BEZIER_PTS_Y );
78     LongFileName = longfilename;
79
80     // Scroll
81     StartIndex  = 0;
82 }
83 //---------------------------------------------------------------------------
84 ControlPlayList::~ControlPlayList()
85 {
86     if( CaseLeft )
87     {
88         delete[] CaseLeft;
89     }
90     if( CaseRight )
91     {
92         delete[] CaseRight;
93     }
94     if( CaseTextLeft )
95     {
96         delete[] CaseTextLeft;
97     }
98     if( Slider )
99     {
100         delete Slider;
101     }
102     if( TextClipRgn )
103     {
104         delete TextClipRgn;
105     }
106     if( PlayList != NULL )
107     {
108         vlc_object_release( PlayList );
109     }
110 }
111 //---------------------------------------------------------------------------
112 void ControlPlayList::Init()
113 {
114     int i, j, h;
115     int *x, *y;
116
117     // Font & events
118     UpdateEvent = p_intf->p_sys->p_theme->EvtBank->Get( "playlist_refresh" );
119     TextFont    = p_intf->p_sys->p_theme->FntBank->Get( FontName );
120     if( PlayFontName == "none" )
121         PlayFont = p_intf->p_sys->p_theme->FntBank->Get( FontName );
122     else
123         PlayFont = p_intf->p_sys->p_theme->FntBank->Get( PlayFontName );
124
125     TextFont->GetSize( "lp", h, CaseHeight );
126
127     // Get bitmap from list
128     Img = NULL;
129
130     // Get points for Text curve
131     h  = TextCurve->GetNumOfDifferentPoints();
132     x  = new int[h + 1];
133     y  = new int[h + 1];
134     TextCurve->GetDifferentPoints( x, y, 0, 0 );
135
136     // Get top of first point
137     TextCurve->GetPoint( 0, i, TextTop );
138
139     // Set number of lines
140     Line = 0;
141     for( i = 0; i < h; i++ )
142     {
143         if( ( Line + 1 ) * CaseHeight < y[i] - TextTop )
144             Line++;
145     }
146     CaseLeft     = new int[Line];
147     CaseRight    = new int[Line];
148     CaseTextLeft = new int[Line];
149     for( i = 0; i < Line; i++ )
150     {
151         CaseLeft[i]     = x[i * CaseHeight];
152         CaseTextLeft[i] = x[i * CaseHeight];
153         for( j = 1; j < CaseHeight; j++ )
154         {
155             if( x[i * CaseHeight + j] < CaseLeft[i] )
156                 CaseLeft[i] = x[i * CaseHeight + j];
157             if( x[i * CaseHeight + j] > CaseTextLeft[i] )
158                 CaseTextLeft[i] = x[i * CaseHeight + j];
159         }
160         CaseRight[i] = CaseTextLeft[i] + CaseWidth;
161     }
162
163     // Get size of text zone
164     TextHeight = Line * CaseHeight;
165     TextLeft   = CaseLeft[0];
166     TextWidth  = CaseRight[0];
167     for( i = 1; i < Line; i++ )
168     {
169         if( CaseLeft[i] < TextLeft )
170             TextLeft = CaseLeft[i];
171         if( CaseRight[i] > TextWidth )
172             TextWidth = CaseRight[i];
173     }
174     TextWidth -= TextLeft;
175
176     // Set Text Clipping Region
177     TextClipRgn = (SkinRegion *)new OSRegion;
178     for( i = 0; i < Line; i++ )
179     {
180         for( j = 0; j < CaseHeight; j++ )
181         {
182             h = i * CaseHeight + j;
183             TextClipRgn->AddRectangle( x[h] - TextLeft, h, CaseWidth, 1 );
184         }
185     }
186
187     // Curve is no more needed so delete it
188     delete TextCurve;
189     delete[] x;
190     delete[] y;
191
192     // Get size of control
193     Left   = Slider->GetLeft();
194     Top    = Slider->GetTop();
195     Width  = Slider->GetLeft() + Slider->GetWidth();
196     Height = Slider->GetTop()  + Slider->GetHeight();
197     if( TextLeft < Left )
198         Left = TextLeft;
199     if( TextTop  < Top  )
200         Top  = TextTop;
201     if( TextLeft + TextWidth  > Width )
202         Width  = TextLeft + TextWidth;
203     if( TextTop + TextHeight > Height )
204         Height  = TextTop  + TextHeight;
205     Width  -= Left;
206     Height -= Top;
207
208     // Getting playlist
209     PlayList = (playlist_t *)
210         vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
211     if( PlayList == NULL )
212         msg_Err( p_intf, "cannot find a playlist object" );
213
214     Slider->Init();
215     Slider->Enable( p_intf->p_sys->p_theme->EvtBank->Get( "none" ), true );
216     RefreshList();
217 }
218 //---------------------------------------------------------------------------
219 bool ControlPlayList::ProcessEvent( Event *evt )
220 {
221     switch( evt->GetMessage() )
222     {
223         case CTRL_ENABLED:
224             Enable( (Event*)evt->GetParam1(), (bool)evt->GetParam2() );
225             break;
226
227         case CTRL_SYNCHRO:
228             if( UpdateEvent->IsEqual( (Event*)evt->GetParam1() ) )
229             {
230                 RefreshList();
231                 RefreshAll();
232             }
233             break;
234
235         case PLAYLIST_ID_DEL:
236             if( (GenericControl *)evt->GetParam1() == this )
237             {
238                 for( int i = PlayList->i_size - 1; i >= 0; i-- )
239                 {
240                     if( Select[i] && i != PlayList->i_index )
241                         playlist_Delete( PlayList, i );
242                 }
243                 RefreshList();
244                 RefreshAll();
245             }
246             break;
247     }
248     return false;
249 }
250 //---------------------------------------------------------------------------
251 void ControlPlayList::RefreshList()
252 {
253     vlc_mutex_lock( &PlayList->object_lock );
254     
255     if( NumOfItems != PlayList->i_size )
256     {
257         if( NumOfItems > 0 )
258             delete[] Select;
259         NumOfItems = PlayList->i_size;
260         if( PlayList->i_size > 0 )
261         {
262             Select = new bool[NumOfItems];
263             for( int i = 0; i < NumOfItems; i++ )
264                 Select[i] = false;
265             int h;
266             sprintf( Num, " %i", NumOfItems + 1 );
267             TextFont->GetSize( Num, NumWidth, h);
268             FileWidth = CaseWidth - NumWidth - InfoWidth;
269         }
270
271         int Range = PlayList->i_size - Line * Column;
272         if( Range < 0 )
273             Range = 0;
274
275         Slider->ChangeSliderRange( Range );
276         StartIndex = Slider->GetCursorPosition();
277     }
278
279     vlc_mutex_unlock( &PlayList->object_lock );
280 }
281 //---------------------------------------------------------------------------
282 void ControlPlayList::RefreshAll()
283 {
284     ParentWindow->Refresh( TextLeft, TextTop, TextWidth, TextHeight );
285 }
286 //---------------------------------------------------------------------------
287 void ControlPlayList::Draw( int x, int y, int w, int h, Graphics *dest )
288 {
289     if( !Visible )
290         return;
291
292     int xI, yI, wI, hI;
293     // Slider Image
294     Slider->Draw( x, y, w, h, dest );
295
296     // TextZone
297     if( GetIntersectRgn( x, y, w, h, TextLeft, TextTop, TextWidth, TextHeight,
298                          xI, yI, wI, hI) )
299     {
300         // Change clipping region
301         SkinRegion *destClipRgn = (SkinRegion *)new OSRegion( 0, 0, w, h );
302         TextClipRgn->Move( TextLeft - x, TextTop - y );
303         dest->SetClipRegion( TextClipRgn );
304
305         // Draw each line
306         DrawAllCase( dest, x, y, wI, hI );
307
308         // Reset clipping region to old region
309         dest->SetClipRegion( destClipRgn );
310         delete destClipRgn;
311         TextClipRgn->Move( x - TextLeft, y - TextTop );
312     }
313 }
314 //---------------------------------------------------------------------------
315 void ControlPlayList::DrawAllCase( Graphics *dest, int x, int y, int w, int h )
316 {
317     int i;
318     for( i = 0; i < NumOfItems - StartIndex && i < Line * Column; i++ )
319     {
320         DrawCase( dest, i + StartIndex, x, y, w, h );
321     }
322 }
323 //---------------------------------------------------------------------------
324 void ControlPlayList::DrawCase( Graphics *dest, int i, int x, int y, int w,
325                                 int h )
326 {
327     // Test if case is in range
328     int j = i - StartIndex;
329     if( j < 0 || j >= Line * Column )
330         return;
331
332     // Draw background if selected
333     if( Select[i] )
334     {
335         dest->DrawRect(
336             CaseLeft[j] - x,
337             TextTop + j * CaseHeight - y,
338             CaseRight[j] - CaseLeft[j],
339             CaseHeight,
340             SelectColor
341         );
342     }
343
344     // Choose font
345     SkinFont *F;
346     if( PlayList->i_index == i )
347         F = PlayFont;
348     else
349         F = TextFont;
350
351     // Print number
352     sprintf( Num, "%i", i + 1 );
353     F->Print( dest,
354         Num,
355         CaseTextLeft[j] - x, TextTop + j * CaseHeight - y,
356         NumWidth - Margin, CaseHeight, VLC_FONT_ALIGN_RIGHT );
357
358     // Print name
359     F->Print( dest,
360         GetFileName( i ),
361         NumWidth + Margin + CaseTextLeft[j] - x,
362         TextTop + j * CaseHeight - y,
363         FileWidth - 2 * Margin, CaseHeight, VLC_FONT_ALIGN_LEFT );
364
365     // Print info
366     F->Print( dest,
367         "no info",
368         NumWidth + FileWidth + Margin + CaseTextLeft[j] - x,
369         TextTop + j * CaseHeight - y,
370         InfoWidth - Margin, CaseHeight, VLC_FONT_ALIGN_CENTER );
371 }
372 //---------------------------------------------------------------------------
373 char * ControlPlayList::GetFileName( int i )
374 {
375     if( LongFileName )
376     {
377         return PlayList->pp_items[i]->psz_name;
378     }
379     else
380     {
381         string f = PlayList->pp_items[i]->psz_name;
382         int pos  = f.rfind( DIRECTORY_SEPARATOR, f.size() );
383         return PlayList->pp_items[i]->psz_name + pos + 1;
384     }
385 }
386 //---------------------------------------------------------------------------
387 void ControlPlayList::MoveRelative( int xOff, int yOff )
388 {
389     Slider->MoveRelative( xOff, yOff );
390     Left     += xOff;
391     Top      += yOff;
392     TextLeft += xOff;
393     TextTop  += yOff;
394     for( int i = 1; i < Line; i++ )
395     {
396         CaseLeft[i]     += xOff;
397         CaseTextLeft[i] += xOff;
398         CaseRight[i]    += xOff;
399     }
400 }
401 //---------------------------------------------------------------------------
402 double ControlPlayList::Dist( int x1, int y1, int x2, int y2 )
403 {
404     return sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );
405 }
406 //---------------------------------------------------------------------------
407 bool ControlPlayList::MouseDown( int x, int y, int button )
408 {
409     if( !Enabled )
410         return false;
411
412     // If hit into slider
413     if( Slider->MouseDown( x, y, button ) )
414     {
415         int New = Slider->GetCursorPosition();
416         if( New != StartIndex )
417         {
418             StartIndex = New;
419             ParentWindow->Refresh( TextLeft,TextTop,TextWidth,TextHeight );
420         }
421         return true;
422     }
423
424     if( !TextClipRgn->Hit( x - TextLeft, y - TextTop ) )
425         return false;
426
427     // If hit in a case
428     int i, j;
429     for( i = 0; i < PlayList->i_size - StartIndex && i < Line * Column; i++)
430     {
431         if( x >= CaseLeft[i] && x <= CaseRight[i] && y >= TextTop +
432             i * CaseHeight  && y < TextTop + (i + 1) * CaseHeight )
433         {
434             for( j = 0; j < NumOfItems; j++ )
435             {
436                 if( button & KEY_CTRL )
437                 {
438                     // CTRL is pressed
439                     if( j == i + StartIndex )
440                     {
441                         Select[j] = !Select[j];
442                     }
443                 }
444                 else
445                 { 
446                     // CTRL is not pressed
447                     Select[j] = ( j == i + StartIndex );
448                 }
449             }
450             RefreshAll();
451             return true;
452         }
453     }
454
455     return false;
456 }
457 //---------------------------------------------------------------------------
458 bool ControlPlayList::MouseUp( int x, int y, int button )
459 {
460     if( !Enabled )
461         return false;
462
463     // If hit into slider
464     if( Slider->MouseUp( x, y, button ) )
465         return true;
466
467     return false;
468 }
469 //---------------------------------------------------------------------------
470 bool ControlPlayList::MouseMove( int x, int y, int button )
471 {
472     if( !Enabled || !button )
473         return false;
474
475     // If hit into slider
476     if( Slider->MouseMove( x, y, button ) )
477     {
478         int New = Slider->GetCursorPosition();
479         if( New != StartIndex )
480         {
481             StartIndex = New;
482             RefreshAll();
483         }
484         return true;
485     }
486
487     return false;
488 }
489 //---------------------------------------------------------------------------
490 bool ControlPlayList::MouseScroll( int x, int y, int direction )
491 {
492     if( !Enabled )
493         return false;
494
495     if( !TextClipRgn->Hit( x - Left, y - Top ) && !Slider->MouseOver( x, y ) )
496         return false;
497
498     long pos = StartIndex;
499     switch( direction )
500     {
501         case MOUSE_SCROLL_UP:
502             if( pos > 0 ) pos--;
503             break;
504         case MOUSE_SCROLL_DOWN:
505             if( pos + Line  < NumOfItems ) pos++;
506             break;
507     }
508     StartIndex = pos;
509     Slider->SetCursorPosition( pos );
510     RefreshAll();
511     return true;
512 }
513 //---------------------------------------------------------------------------
514 bool ControlPlayList::MouseOver( int x, int y )
515 {
516     if( TextClipRgn->Hit( x - Left, y - Top ) || Slider->MouseOver( x, y ) )
517         return true;
518     else
519         return false;
520 }
521 //---------------------------------------------------------------------------
522 bool ControlPlayList::MouseDblClick( int x, int y, int button )
523 {
524     if( !Enabled || button != 1 )
525         return false;
526
527     int i;
528
529     if( !TextClipRgn->Hit( x - TextLeft, y - TextTop ) )
530         return false;
531
532     for( i = 0; i < PlayList->i_size - StartIndex && i < Line * Column; i++ )
533     {
534         if( x >= CaseLeft[i] && x <= CaseRight[i] && y >=
535             TextTop + i * CaseHeight  && y < TextTop + (i + 1) * CaseHeight )
536         {
537             playlist_Goto( PlayList, i + StartIndex );
538             OSAPI_PostMessage( NULL, VLC_INTF_REFRESH, 0, (int)false );
539             return true;
540         }
541     }
542     return false;
543 }
544 //---------------------------------------------------------------------------
545 bool ControlPlayList::ToolTipTest( int x, int y )
546 {
547     if( !Enabled )
548         return false;
549
550     int i, w, h;
551     for( i = 0; i < PlayList->i_size - StartIndex && i < Line * Column; i++ )
552     {
553         if( x >= CaseLeft[i] && x <= CaseRight[i] && y >=
554             TextTop + i * CaseHeight  && y < TextTop + (i + 1) * CaseHeight )
555         {
556             TextFont->GetSize( PlayList->pp_items[i + StartIndex]->psz_name, w,
557                                h );
558             if( w > FileWidth )
559             {
560                 ParentWindow->ChangeToolTipText(
561                     (string)PlayList->pp_items[i + StartIndex]->psz_name );
562                 return true;
563             }
564         }
565     }
566     return false;
567 }
568 //---------------------------------------------------------------------------
569 void ControlPlayList::InitSliderCurve( double *ptx, double *pty, int nb,
570                                        string scroll_up, string scroll_down )
571 {
572     Slider = new ControlSlider( "none", true, "none", scroll_up, scroll_down,
573         ptx, pty, nb, "none", "", ParentWindow );
574 }
575 //---------------------------------------------------------------------------
576