]> git.sesse.net Git - vlc/blob - modules/gui/beos/ListViews.cpp
A bit of headers cleanup
[vlc] / modules / gui / beos / ListViews.cpp
1 /*****************************************************************************
2  * ListViews.h: BeOS interface list view class implementation
3  *****************************************************************************
4  * Copyright (C) 1999, 2000, 2001 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Stephan Aßmus <stippi@yellowbites.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #if 0
25
26 #include <stdio.h>
27 #include <malloc.h>
28
29 #include <Bitmap.h>
30 #include <Entry.h>
31 #include <String.h>
32
33 /* VLC headers */
34 #include <vlc/vlc.h>
35 #include <vlc_interface.h>
36
37 #include "InterfaceWindow.h"
38 #include "ListViews.h"
39 #include "MsgVals.h"
40
41 #define MAX_DRAG_HEIGHT        200.0
42 #define ALPHA                170
43 #define TEXT_OFFSET            20.0
44
45 /*****************************************************************************
46  * PlaylistItem class
47  *****************************************************************************/
48 PlaylistItem::PlaylistItem( const char *name )
49     : BStringItem( name ),
50       fName( "" )
51 {
52     entry_ref ref;
53     if ( get_ref_for_path( name, &ref) == B_OK )
54         fName.SetTo( ref.name );
55 }
56
57 PlaylistItem::~PlaylistItem()
58 {
59 }
60
61 /*****************************************************************************
62  * PlaylistItem::DrawItem
63  *****************************************************************************/
64 void
65 PlaylistItem::Draw( BView *owner, BRect frame, bool tintedLine,
66                     uint32 mode, bool active, bool playing )
67 {
68     rgb_color color = (rgb_color){ 255, 255, 255, 255 };
69     if ( tintedLine )
70         color = tint_color( color, 1.04 );
71     // background
72     if ( IsSelected() )
73         color = tint_color( color, B_DARKEN_2_TINT );
74     owner->SetLowColor( color );
75     owner->FillRect( frame, B_SOLID_LOW );
76     // label
77     owner->SetHighColor( 0, 0, 0, 255 );
78     font_height fh;
79     owner->GetFontHeight( &fh );
80     const char* text = Text();
81     switch ( mode )
82     {
83         case DISPLAY_NAME:
84             if ( fName.CountChars() > 0 )
85                 text = fName.String();
86             break;
87         case DISPLAY_PATH:
88         default:
89             break;
90     }
91     BString truncatedString( text );
92     owner->TruncateString( &truncatedString, B_TRUNCATE_MIDDLE,
93                            frame.Width() - TEXT_OFFSET - 4.0 );
94     owner->DrawString( truncatedString.String(),
95                        BPoint( frame.left + TEXT_OFFSET,
96                                frame.top + fh.ascent + 1.0 ) );
97     // playmark
98     if ( active )
99     {
100         rgb_color black = (rgb_color){ 0, 0, 0, 255 };
101         rgb_color green = (rgb_color){ 0, 255, 0, 255 };
102         BRect r( 0.0, 0.0, 10.0, 10.0 );
103         r.OffsetTo( frame.left + 4.0,
104                     ceilf( ( frame.top + frame.bottom ) / 2.0 ) - 5.0 );
105         if ( !playing )
106             green = tint_color( color, B_DARKEN_1_TINT );
107         rgb_color lightGreen = tint_color( green, B_LIGHTEN_2_TINT );
108         rgb_color darkGreen = tint_color( green, B_DARKEN_2_TINT );
109         BPoint arrow[3];
110         arrow[0] = r.LeftTop();
111         arrow[1] = r.LeftBottom();
112         arrow[2].x = r.right;
113         arrow[2].y = ( r.top + r.bottom ) / 2.0;
114         owner->BeginLineArray( 6 );
115             // black outline
116             owner->AddLine( arrow[0], arrow[1], black );
117             owner->AddLine( BPoint( arrow[1].x + 1.0, arrow[1].y - 1.0 ),
118                             arrow[2], black );
119             owner->AddLine( arrow[0], arrow[2], black );
120             // inset arrow
121             arrow[0].x += 1.0;
122             arrow[0].y += 2.0;
123             arrow[1].x += 1.0;
124             arrow[1].y -= 2.0;
125             arrow[2].x -= 2.0;
126             // highlights and shadow
127             owner->AddLine( arrow[1], arrow[2], darkGreen );
128             owner->AddLine( arrow[0], arrow[2], lightGreen );
129             owner->AddLine( arrow[0], arrow[1], lightGreen );
130         owner->EndLineArray();
131         // fill green
132         arrow[0].x += 1.0;
133         arrow[0].y += 1.0;
134         arrow[1].x += 1.0;
135         arrow[1].y -= 1.0;
136         arrow[2].x -= 2.0;
137         owner->SetHighColor( green );
138         owner->FillPolygon( arrow, 3 );
139     }
140 }
141
142 /*****************************************************************************
143  * DragSortableListView class
144  *****************************************************************************/
145 DragSortableListView::DragSortableListView( BRect frame, const char* name,
146                                             list_view_type type, uint32 resizingMode,
147                                             uint32 flags )
148     : BListView( frame, name, type, resizingMode, flags ),
149       fDropRect( 0.0, 0.0, -1.0, -1.0 ),
150       fDropIndex( -1 )
151 {
152     SetViewColor( B_TRANSPARENT_32_BIT );
153 }
154
155 DragSortableListView::~DragSortableListView()
156 {
157 }
158
159 /*****************************************************************************
160  * DragSortableListView::Draw
161  *****************************************************************************/
162 void
163 DragSortableListView::Draw( BRect updateRect )
164 {
165     int32 firstIndex = IndexOf( updateRect.LeftTop() );
166     int32 lastIndex = IndexOf( updateRect.RightBottom() );
167     if ( firstIndex >= 0 )
168     {
169         if ( lastIndex < firstIndex )
170             lastIndex = CountItems() - 1;
171         // update rect contains items
172         BRect r( updateRect );
173         for ( int32 i = firstIndex; i <= lastIndex; i++)
174         {
175             r = ItemFrame( i );
176             DrawListItem( this, i, r );
177         }
178         updateRect.top = r.bottom + 1.0;
179         if ( updateRect.IsValid() )
180         {
181             SetLowColor( 255, 255, 255, 255 );
182             FillRect( updateRect, B_SOLID_LOW );
183         }
184     }
185     else
186     {
187         SetLowColor( 255, 255, 255, 255 );
188         FillRect( updateRect, B_SOLID_LOW );
189     }
190     // drop anticipation indication
191     if ( fDropRect.IsValid() )
192     {
193         SetHighColor( 255, 0, 0, 255 );
194         StrokeRect( fDropRect );
195     }
196 }
197
198 /*****************************************************************************
199  * DragSortableListView::InitiateDrag
200  *****************************************************************************/
201 bool
202 DragSortableListView::InitiateDrag( BPoint point, int32 index, bool )
203 {
204     bool success = false;
205     BListItem* item = ItemAt( CurrentSelection( 0 ) );
206     if ( !item )
207     {
208         // workarround a timing problem
209         Select( index );
210         item = ItemAt( index );
211     }
212     if ( item )
213     {
214         // create drag message
215         BMessage msg( B_SIMPLE_DATA );
216         MakeDragMessage( &msg );
217         // figure out drag rect
218         float width = Bounds().Width();
219         BRect dragRect(0.0, 0.0, width, -1.0);
220         // figure out, how many items fit into our bitmap
221         int32 numItems;
222         bool fade = false;
223         for (numItems = 0; BListItem* item = ItemAt( CurrentSelection( numItems ) ); numItems++) {
224             dragRect.bottom += ceilf( item->Height() ) + 1.0;
225             if ( dragRect.Height() > MAX_DRAG_HEIGHT ) {
226                 fade = true;
227                 dragRect.bottom = MAX_DRAG_HEIGHT;
228                 numItems++;
229                 break;
230             }
231         }
232         BBitmap* dragBitmap = new BBitmap( dragRect, B_RGB32, true );
233         if ( dragBitmap && dragBitmap->IsValid() ) {
234             if ( BView *v = new BView( dragBitmap->Bounds(), "helper", B_FOLLOW_NONE, B_WILL_DRAW ) ) {
235                 dragBitmap->AddChild( v );
236                 dragBitmap->Lock();
237                 BRect itemBounds( dragRect) ;
238                 itemBounds.bottom = 0.0;
239                 // let all selected items, that fit into our drag_bitmap, draw
240                 for ( int32 i = 0; i < numItems; i++ ) {
241                     int32 index = CurrentSelection( i );
242                     BListItem* item = ItemAt( index );
243                     itemBounds.bottom = itemBounds.top + ceilf( item->Height() );
244                     if ( itemBounds.bottom > dragRect.bottom )
245                         itemBounds.bottom = dragRect.bottom;
246                     DrawListItem( v, index, itemBounds );
247                     itemBounds.top = itemBounds.bottom + 1.0;
248                 }
249                 // make a black frame arround the edge
250                 v->SetHighColor( 0, 0, 0, 255 );
251                 v->StrokeRect( v->Bounds() );
252                 v->Sync();
253     
254                 uint8 *bits = (uint8 *)dragBitmap->Bits();
255                 int32 height = (int32)dragBitmap->Bounds().Height() + 1;
256                 int32 width = (int32)dragBitmap->Bounds().Width() + 1;
257                 int32 bpr = dragBitmap->BytesPerRow();
258     
259                 if (fade) {
260                     for ( int32 y = 0; y < height - ALPHA / 2; y++, bits += bpr ) {
261                         uint8 *line = bits + 3;
262                         for (uint8 *end = line + 4 * width; line < end; line += 4)
263                             *line = ALPHA;
264                     }
265                     for ( int32 y = height - ALPHA / 2; y < height; y++, bits += bpr ) {
266                         uint8 *line = bits + 3;
267                         for (uint8 *end = line + 4 * width; line < end; line += 4)
268                             *line = (height - y) << 1;
269                     }
270                 } else {
271                     for ( int32 y = 0; y < height; y++, bits += bpr ) {
272                         uint8 *line = bits + 3;
273                         for (uint8 *end = line + 4 * width; line < end; line += 4)
274                             *line = ALPHA;
275                     }
276                 }
277                 dragBitmap->Unlock();
278                 success = true;
279             }
280         }
281         if (success)
282             DragMessage( &msg, dragBitmap, B_OP_ALPHA, BPoint( 0.0, 0.0 ) );
283         else {
284             delete dragBitmap;
285             DragMessage( &msg, dragRect.OffsetToCopy( point ), this );
286         }
287     }
288     return success;
289 }
290
291 /*****************************************************************************
292  * DragSortableListView::WindowActivated
293  *****************************************************************************/
294 void
295 DragSortableListView::WindowActivated( bool active )
296 {
297     // workarround for buggy focus indication of BScrollView
298     if ( BView* view = Parent() )
299         view->Invalidate();
300 }
301
302 /*****************************************************************************
303  * DragSortableListView::MessageReceived
304  *****************************************************************************/
305 void
306 DragSortableListView::MessageReceived(BMessage* message)
307 {
308     switch ( message->what )
309     {
310         case B_MODIFIERS_CHANGED:
311             ModifiersChanged();
312             break;
313         case B_SIMPLE_DATA:
314         {
315             DragSortableListView *list = NULL;
316             if ( message->FindPointer( "list", (void **)&list ) == B_OK
317                  && list == this )
318             {
319                 int32 count = CountItems();
320                 if ( fDropIndex < 0 || fDropIndex > count )
321                     fDropIndex = count;
322                 BList items;
323                 int32 index;
324                 for ( int32 i = 0; message->FindInt32( "index", i, &index ) == B_OK; i++ )
325                     if ( BListItem* item = ItemAt(index) )
326                         items.AddItem( (void*)item );
327                 if ( items.CountItems() > 0 )
328                 {
329                     if ( modifiers() & B_SHIFT_KEY )
330                         CopyItems( items, fDropIndex );
331                     else
332                         MoveItems( items, fDropIndex );
333                 }
334                 fDropIndex = -1;
335             }
336             break;
337         }
338         default:
339             BListView::MessageReceived( message );
340             break;
341     }
342 }
343
344 /*****************************************************************************
345  * DragSortableListView::MouseMoved
346  *****************************************************************************/
347 void
348 DragSortableListView::MouseMoved(BPoint where, uint32 transit, const BMessage *msg)
349 {
350     if ( msg && ( msg->what == B_SIMPLE_DATA || msg->what == MSG_SOUNDPLAY ) )
351     {
352         bool replaceAll = !msg->HasPointer("list") && !(modifiers() & B_SHIFT_KEY);
353         switch ( transit )
354         {
355             case B_ENTERED_VIEW:
356                 // remember drag message
357                 // this is needed to react on modifier changes
358                 fDragMessageCopy = *msg;
359             case B_INSIDE_VIEW:
360             {
361                 if ( replaceAll )
362                 {
363                     BRect r( Bounds() );
364                     r.bottom--;    // compensate for scrollbar offset
365                     _SetDropAnticipationRect( r );
366                     fDropIndex = -1;
367                 }
368                 else
369                 {
370                     // offset where by half of item height
371                     BRect r( ItemFrame( 0 ) );
372                     where.y += r.Height() / 2.0;
373     
374                     int32 index = IndexOf( where );
375                     if ( index < 0 )
376                         index = CountItems();
377                     _SetDropIndex( index );
378                 }
379                 break;
380             }
381             case B_EXITED_VIEW:
382                 // forget drag message
383                 fDragMessageCopy.what = 0;
384             case B_OUTSIDE_VIEW:
385                 _RemoveDropAnticipationRect();
386                 break;
387         }
388     }
389     else
390     {
391         _RemoveDropAnticipationRect();
392         BListView::MouseMoved(where, transit, msg);
393         fDragMessageCopy.what = 0;
394     }
395 }
396
397 /*****************************************************************************
398  * DragSortableListView::MouseUp
399  *****************************************************************************/
400 void
401 DragSortableListView::MouseUp( BPoint where )
402 {
403     // remove drop mark
404     _SetDropAnticipationRect( BRect( 0.0, 0.0, -1.0, -1.0 ) );
405     // be sure to forget drag message
406     fDragMessageCopy.what = 0;
407     BListView::MouseUp( where );
408 }
409
410 /*****************************************************************************
411  * DragSortableListView::DrawItem
412  *****************************************************************************/
413 void
414 DragSortableListView::DrawItem( BListItem *item, BRect itemFrame, bool complete )
415 {
416     DrawListItem( this, IndexOf( item ), itemFrame );
417 }
418
419 /*****************************************************************************
420  * DragSortableListView::ModifiersChaned
421  *****************************************************************************/
422 void
423 DragSortableListView::ModifiersChanged()
424 {
425     BPoint where;
426     uint32 buttons;
427     GetMouse( &where, &buttons, false );
428     uint32 transit = Bounds().Contains( where ) ? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
429     MouseMoved( where, transit, &fDragMessageCopy );
430 }
431
432 /*****************************************************************************
433  * DragSortableListView::MoveItems
434  *****************************************************************************/
435 void
436 DragSortableListView::MoveItems( BList& items, int32 index )
437 {
438     DeselectAll();
439     // we remove the items while we look at them, the insertion index is decreased
440     // when the items index is lower, so that we insert at the right spot after
441     // removal
442     BList removedItems;
443     int32 count = items.CountItems();
444     for ( int32 i = 0; i < count; i++ )
445     {
446         BListItem* item = (BListItem*)items.ItemAt( i );
447         int32 removeIndex = IndexOf( item );
448         if ( RemoveItem( item ) && removedItems.AddItem( (void*)item ) )
449         {
450             if ( removeIndex < index )
451                 index--;
452         }
453         // else ??? -> blow up
454     }
455     for ( int32 i = 0; BListItem* item = (BListItem*)removedItems.ItemAt( i ); i++ )
456     {
457         if ( AddItem( item, index ) )
458         {
459             // after we're done, the newly inserted items will be selected
460             Select( index, true );
461             // next items will be inserted after this one
462             index++;
463         }
464         else
465             delete item;
466     }
467 }
468
469 /*****************************************************************************
470  * DragSortableListView::CopyItems
471  *****************************************************************************/
472 void
473 DragSortableListView::CopyItems( BList& items, int32 index )
474 {
475     DeselectAll();
476     // by inserting the items after we copied all items first, we avoid
477     // cloning an item we already inserted and messing everything up
478     // in other words, don't touch the list before we know which items
479     // need to be cloned
480     BList clonedItems;
481     int32 count = items.CountItems();
482     for ( int32 i = 0; i < count; i++ )
483     {
484         BListItem* item = CloneItem( IndexOf( (BListItem*)items.ItemAt( i ) ) );
485         if ( item && !clonedItems.AddItem( (void*)item ) )
486             delete item;
487     }
488     for ( int32 i = 0; BListItem* item = (BListItem*)clonedItems.ItemAt( i ); i++ )
489     {
490         if ( AddItem( item, index ) )
491         {
492             // after we're done, the newly inserted items will be selected
493             Select( index, true );
494             // next items will be inserted after this one
495             index++;
496         }
497         else
498             delete item;
499     }
500 }
501
502 /*****************************************************************************
503  * DragSortableListView::RemoveItemList
504  *****************************************************************************/
505 void
506 DragSortableListView::RemoveItemList( BList& items )
507 {
508     int32 count = items.CountItems();
509     for ( int32 i = 0; i < count; i++ )
510     {
511         BListItem* item = (BListItem*)items.ItemAt( i );
512         if ( RemoveItem( item ) )
513             delete item;
514     }
515 }
516
517 /*****************************************************************************
518  * DragSortableListView::RemoveSelected
519  *****************************************************************************/
520 void
521 DragSortableListView::RemoveSelected()
522 {
523     BList items;
524     for ( int32 i = 0; BListItem* item = ItemAt( CurrentSelection( i ) ); i++ )
525         items.AddItem( (void*)item );
526     RemoveItemList( items );
527 }
528
529 /*****************************************************************************
530  * DragSortableListView::CountSelectedItems
531  *****************************************************************************/
532 int32
533 DragSortableListView::CountSelectedItems() const
534 {
535     int32 count = 0;
536     while ( CurrentSelection( count ) >= 0 )
537         count++;
538     return count;
539 }
540
541 /*****************************************************************************
542  * DragSortableListView::_SetDropAnticipationRect
543  *****************************************************************************/
544 void
545 DragSortableListView::_SetDropAnticipationRect( BRect r )
546 {
547     if ( fDropRect != r )
548     {
549         if ( fDropRect.IsValid() )
550             Invalidate( fDropRect );
551         fDropRect = r;
552         if ( fDropRect.IsValid() )
553             Invalidate( fDropRect );
554     }
555 }
556
557 /*****************************************************************************
558  * DragSortableListView::_SetDropAnticipationRect
559  *****************************************************************************/
560 void
561 DragSortableListView::_SetDropIndex( int32 index )
562 {
563     if ( fDropIndex != index )
564     {
565         fDropIndex = index;
566         if ( fDropIndex == -1 )
567             _SetDropAnticipationRect( BRect( 0.0, 0.0, -1.0, -1.0 ) );
568         else
569         {
570             int32 count = CountItems();
571             if ( fDropIndex == count )
572             {
573                 BRect r;
574                 if ( BListItem* item = ItemAt( count - 1 ) )
575                 {
576                     r = ItemFrame( count - 1 );
577                     r.top = r.bottom + 1.0;
578                     r.bottom = r.top + 1.0;
579                 }
580                 else
581                 {
582                     r = Bounds();
583                     r.bottom--;    // compensate for scrollbars moved slightly out of window
584                 }
585                 _SetDropAnticipationRect( r );
586             }
587             else
588             {
589                 BRect r = ItemFrame( fDropIndex );
590                 r.bottom = r.top + 1.0;
591                 _SetDropAnticipationRect( r );
592             }
593         }
594     }
595 }
596
597 /*****************************************************************************
598  * DragSortableListView::_RemoveDropAnticipationRect
599  *****************************************************************************/
600 void
601 DragSortableListView::_RemoveDropAnticipationRect()
602 {
603     _SetDropAnticipationRect( BRect( 0.0, 0.0, -1.0, -1.0 ) );
604     _SetDropIndex( -1 );
605 }
606
607
608 /*****************************************************************************
609  * PlaylistView class
610  *****************************************************************************/
611 PlaylistView::PlaylistView( intf_thread_t * _p_intf,
612                             BRect frame, InterfaceWindow* mainWindow,
613                             BMessage* selectionChangeMessage )
614     : DragSortableListView( frame, "playlist listview",
615                             B_MULTIPLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES,
616                             B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED
617                             | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE ),
618       p_intf( _p_intf ),
619       fCurrentIndex( -1 ),
620       fPlaying( false ),
621       fDisplayMode( DISPLAY_PATH ),
622       fMainWindow( mainWindow ),
623       fSelectionChangeMessage( selectionChangeMessage ),
624       fLastClickedItem( NULL )
625 {
626 }
627
628 PlaylistView::~PlaylistView()
629 {
630     delete fSelectionChangeMessage;
631 }
632
633 /*****************************************************************************
634  * PlaylistView::AttachedToWindow
635  *****************************************************************************/
636 void
637 PlaylistView::AttachedToWindow()
638 {
639     // get pulse message every two frames
640     Window()->SetPulseRate( 80000 );
641 }
642
643 /*****************************************************************************
644  * PlaylistView::MessageReceived
645  *****************************************************************************/
646 void
647 PlaylistView::MessageReceived( BMessage* message)
648 {
649     switch ( message->what )
650     {
651         case MSG_SOUNDPLAY:
652         case B_SIMPLE_DATA:
653             if ( message->HasPointer( "list" ) )
654             {
655                 // message comes from ourself
656                 DragSortableListView::MessageReceived( message );
657             }
658             else
659             {
660                 // message comes from another app (for example Tracker)
661                 message->AddInt32( "drop index", fDropIndex );
662                 fMainWindow->PostMessage( message, fMainWindow );
663             }
664             break;
665         default:
666             DragSortableListView::MessageReceived( message );
667             break;
668     }
669 }
670
671 /*****************************************************************************
672  * PlaylistView::MouseDown
673  *****************************************************************************/
674 void
675 PlaylistView::MouseDown( BPoint where )
676 {
677     int32 clicks = 1;
678     Window()->CurrentMessage()->FindInt32( "clicks", &clicks );
679     bool handled = false;
680     for ( int32 i = 0; PlaylistItem* item = (PlaylistItem*)ItemAt( i ); i++ )
681     {
682         BRect r = ItemFrame( i );
683         if ( r.Contains( where ) )
684         {
685             if ( clicks == 2 )
686             {
687                 // only do something if user clicked the same item twice
688                 if ( fLastClickedItem == item )
689                 {
690                     playlist_t * p_playlist;
691                     p_playlist = (playlist_t *) vlc_object_find( p_intf,
692                         VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
693                     if( p_playlist )
694                     {
695                         playlist_Goto( p_playlist, i );
696                         vlc_object_release( p_playlist );
697                     }
698                     handled = true;
699                 }
700             }
701             else
702             {
703                 // remember last clicked item
704                 fLastClickedItem = item;
705                 if ( i == fCurrentIndex )
706                 {
707                     r.right = r.left + TEXT_OFFSET;
708                     if ( r.Contains ( where ) )
709                     {
710                         fMainWindow->PostMessage( PAUSE_PLAYBACK );
711                         InvalidateItem( i );
712                         handled = true;
713                     }
714                 }
715             }
716             break;
717         }
718     }
719     if ( !handled )
720         DragSortableListView::MouseDown(where);
721 }
722
723 /*****************************************************************************
724  * PlaylistView::KeyDown
725  *****************************************************************************/
726 void
727 PlaylistView::KeyDown( const char* bytes, int32 numBytes )
728 {
729     if ( numBytes < 1 )
730         return;
731         
732     if ( ( bytes[0] == B_BACKSPACE ) || ( bytes[0] == B_DELETE ) )
733     {
734         RemoveSelected();
735     }
736     DragSortableListView::KeyDown( bytes, numBytes );
737 }
738
739 /*****************************************************************************
740  * PlaylistView::Pulse
741  *****************************************************************************/
742 void
743 PlaylistView::Pulse()
744 {
745     if ( fMainWindow->IsStopped() )
746         SetPlaying( false );
747 }
748
749 /*****************************************************************************
750  * PlaylistView::SelectionChanged
751  *****************************************************************************/
752 void
753 PlaylistView::SelectionChanged()
754 {
755     BLooper* looper = Looper();
756     if ( fSelectionChangeMessage && looper )
757     {
758         BMessage message( *fSelectionChangeMessage );
759         looper->PostMessage( &message );
760     }
761 }
762
763
764 /*****************************************************************************
765  * PlaylistView::MoveItems
766  *****************************************************************************/
767 void
768 PlaylistView::MoveItems( BList& items, int32 index )
769 {
770 #if 0
771     DeselectAll();
772     // we remove the items while we look at them, the insertion index is decreased
773     // when the items index is lower, so that we insert at the right spot after
774     // removal
775     if ( fVlcWrapper->PlaylistLock() )
776     {
777         BList removedItems;
778         BList removeItems;
779         int32 count = items.CountItems();
780         int32 indexOriginal = index;
781         // remember currently playing item
782         BListItem* playingItem = _PlayingItem();
783         // collect item pointers for removal by index
784         for ( int32 i = 0; i < count; i++ )
785         {
786             int32 removeIndex = IndexOf( (BListItem*)items.ItemAt( i ) );
787             void* item = fVlcWrapper->PlaylistItemAt( removeIndex );
788             if ( item && removeItems.AddItem( item ) )
789             {
790                 if ( removeIndex < index )
791                     index--;
792             }
793             // else ??? -> blow up
794         }
795         // actually remove items using pointers
796         for ( int32 i = 0; i < count; i++ )
797         {
798             void* item = fVlcWrapper->PlaylistRemoveItem( removeItems.ItemAt( i ) );
799             if ( item && !removedItems.AddItem( item ) )
800                 free( item );
801         }
802         // add items at index
803         for ( int32 i = 0; void* item = removedItems.ItemAt( i ); i++ )
804         {
805             if ( fVlcWrapper->PlaylistAddItem( item, index ) )
806                 // next items will be inserted after this one
807                 index++;
808             else
809                 free( item );
810         }
811         // update GUI
812         DragSortableListView::MoveItems( items, indexOriginal );
813         // restore currently playing item
814         _SetPlayingIndex( playingItem );
815         // update interface (in case it isn't playing,
816         // there is a chance that it needs to update)
817         fMainWindow->PostMessage( MSG_UPDATE );
818         fVlcWrapper->PlaylistUnlock();
819     }
820 #endif
821 }
822
823 /*****************************************************************************
824  * PlaylistView::CopyItems
825  *****************************************************************************/
826 void
827 PlaylistView::CopyItems( BList& items, int32 toIndex )
828 {
829 #if 0
830     DeselectAll();
831     // we remove the items while we look at them, the insertion index is decreased
832     // when the items index is lower, so that we insert at the right spot after
833     // removal
834     if ( fVlcWrapper->PlaylistLock() )
835     {
836         BList clonedItems;
837         int32 count = items.CountItems();
838         // remember currently playing item
839         BListItem* playingItem = _PlayingItem();
840         // collect cloned item pointers
841         for ( int32 i = 0; i < count; i++ )
842         {
843             int32 index = IndexOf( (BListItem*)items.ItemAt( i ) );
844             void* item = fVlcWrapper->PlaylistItemAt( index );
845             void* cloned = fVlcWrapper->PlaylistCloneItem( item );
846             if ( cloned && !clonedItems.AddItem( cloned ) )
847                 free( cloned );
848             
849         }
850         // add cloned items at index
851         int32 index = toIndex;
852         for ( int32 i = 0; void* item = clonedItems.ItemAt( i ); i++ )
853         {
854             if ( fVlcWrapper->PlaylistAddItem( item, index ) )
855                 // next items will be inserted after this one
856                 index++;
857             else
858                 free( item );
859         }
860         // update GUI
861         DragSortableListView::CopyItems( items, toIndex );
862         // restore currently playing item
863         _SetPlayingIndex( playingItem );
864         // update interface (in case it isn't playing,
865         // there is a chance that it needs to update)
866         fMainWindow->PostMessage( MSG_UPDATE );
867         fVlcWrapper->PlaylistUnlock();
868     }
869 #endif
870 }
871
872 /*****************************************************************************
873  * PlaylistView::RemoveItemList
874  *****************************************************************************/
875 void
876 PlaylistView::RemoveItemList( BList& items )
877 {
878 #if 0
879     if ( fVlcWrapper->PlaylistLock() )
880     {
881         // remember currently playing item
882         BListItem* playingItem = _PlayingItem();
883         // collect item pointers for removal
884         BList removeItems;
885         int32 count = items.CountItems();
886         for ( int32 i = 0; i < count; i++ )
887         {
888             int32 index = IndexOf( (BListItem*)items.ItemAt( i ) );
889             void* item = fVlcWrapper->PlaylistItemAt( index );
890             if ( item && !removeItems.AddItem( item ) )
891                 free( item );
892         }
893         // remove items from playlist
894         count = removeItems.CountItems();
895         for ( int32 i = 0; void* item = removeItems.ItemAt( i ); i++ )
896         {
897             fVlcWrapper->PlaylistRemoveItem( item );
898         }
899         // update GUI
900         DragSortableListView::RemoveItemList( items );
901         // restore currently playing item
902         _SetPlayingIndex( playingItem );
903         // update interface (in case it isn't playing,
904         // there is a chance that it needs to update)
905         fMainWindow->PostMessage( MSG_UPDATE );
906         fVlcWrapper->PlaylistUnlock();
907     }
908 #endif
909 }
910
911 /*****************************************************************************
912  * PlaylistView::CloneItem
913  *****************************************************************************/
914 BListItem*
915 PlaylistView::CloneItem( int32 atIndex ) const
916 {
917     BListItem* clone = NULL;
918     if ( PlaylistItem* item = dynamic_cast<PlaylistItem*>( ItemAt( atIndex ) ) )
919         clone = new PlaylistItem( item->Text() );
920     return clone;
921 }
922
923 /*****************************************************************************
924  * PlaylistView::DrawListItem
925  *****************************************************************************/
926 void
927 PlaylistView::DrawListItem( BView* owner, int32 index, BRect frame ) const
928 {
929     if ( PlaylistItem* item = dynamic_cast<PlaylistItem*>( ItemAt( index ) ) )
930         item->Draw( owner,  frame, index % 2,
931                     fDisplayMode, index == fCurrentIndex, fPlaying );
932 }
933
934 /*****************************************************************************
935  * PlaylistView::MakeDragMessage
936  *****************************************************************************/
937 void
938 PlaylistView::MakeDragMessage( BMessage* message ) const
939 {
940     if ( message )
941     {
942         message->AddPointer( "list", (void*)this );
943         int32 index;
944         for ( int32 i = 0; ( index = CurrentSelection( i ) ) >= 0; i++ )
945         {
946             message->AddInt32( "index", index );
947             // add refs to message (inter application communication)
948             if ( BStringItem* item = dynamic_cast<BStringItem*>( ItemAt( index ) ) )
949             {
950                 entry_ref ref;
951                 if ( get_ref_for_path( item->Text(), &ref ) == B_OK )
952                     message->AddRef( "refs", &ref );
953             }
954         }
955     }
956 }
957
958 /*****************************************************************************
959  * PlaylistView::SetCurrent
960  *****************************************************************************/
961 void
962 PlaylistView::SetCurrent( int32 index )
963 {
964     if ( fCurrentIndex != index )
965     {
966         InvalidateItem( fCurrentIndex );
967         fCurrentIndex = index;
968         InvalidateItem( fCurrentIndex );
969     }
970 }
971
972 /*****************************************************************************
973  * PlaylistView::SetPlaying
974  *****************************************************************************/
975 void
976 PlaylistView::SetPlaying( bool playing )
977 {
978     if ( fPlaying != playing )
979     {
980         fPlaying = playing;
981         InvalidateItem( fCurrentIndex );
982     }
983 }
984
985 /*****************************************************************************
986  * PlaylistView::SetPlaying
987  *****************************************************************************/
988 void
989 PlaylistView::RebuildList()
990 {
991     playlist_t * p_playlist = pl_Yield( p_intf );
992
993     // remove all items
994     BListItem * item;
995     int32 count = CountItems();
996     while( ( item = RemoveItem( --count ) ) )
997         delete item;
998
999     // rebuild listview from VLC's playlist
1000     PL_LOCK;
1001     FOREACH_ARRAY( playlist_item_t *p_item, p_playlist->items )
1002         AddItem( new PlaylistItem( p_item->p_input->psz_name ) );
1003     FOREACH_END();
1004     PL_UNLOCK;
1005
1006     vlc_object_release( p_playlist );
1007 }
1008
1009
1010 /*****************************************************************************
1011  * PlaylistView::SortReverse
1012  *****************************************************************************/
1013 void
1014 PlaylistView::SortReverse()
1015 {
1016 #if 0
1017     if ( int32 count = CountSelectedItems() )
1018     {
1019         int32 last  = count - 1;
1020         // remember currently playing item
1021         BListItem* playingItem = _PlayingItem();
1022         for ( int32 first = 0; first < count / 2; first++, last-- )
1023         {
1024             int32 index1 = CurrentSelection( first);
1025             int32 index2 = CurrentSelection( last);
1026             if ( SwapItems( index1, index2 ) )
1027             {
1028                 // index2 > index1, so the list won't get messed up
1029                 // if we remove the items in that order
1030                 // TODO: Error checking + handling!
1031                 void* item2 = fVlcWrapper->PlaylistRemoveItem( index2 );
1032                 void* item1 = fVlcWrapper->PlaylistRemoveItem( index1 );
1033                 fVlcWrapper->PlaylistAddItem( item2, index1 );
1034                 fVlcWrapper->PlaylistAddItem( item1, index2 );
1035             }
1036         }
1037         // restore currently playing item
1038         _SetPlayingIndex( playingItem );
1039     }
1040 #endif
1041 }
1042
1043 /*****************************************************************************
1044  * PlaylistView::SortByPath
1045  *****************************************************************************/
1046 void
1047 PlaylistView::SortByPath()
1048 {
1049     
1050 }
1051
1052 /*****************************************************************************
1053  * PlaylistView::SortByName
1054  *****************************************************************************/
1055 void
1056 PlaylistView::SortByName()
1057 {
1058 }
1059
1060 /*****************************************************************************
1061  * PlaylistView::SetDisplayMode
1062  *****************************************************************************/
1063 void
1064 PlaylistView::SetDisplayMode( uint32 mode )
1065 {
1066     if ( mode != fDisplayMode )
1067     {
1068         fDisplayMode = mode;
1069         Invalidate();
1070     }
1071 }
1072
1073 /*****************************************************************************
1074  * PlaylistView::_PlayingItem
1075  *****************************************************************************/
1076 BListItem*
1077 PlaylistView::_PlayingItem() const
1078 {
1079     playlist_t * p_playlist;
1080     p_playlist = (playlist_t *) vlc_object_find( p_intf,
1081         VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
1082
1083     if( !p_playlist )
1084     {
1085         return NULL;
1086     }
1087
1088     BListItem * item = ItemAt( p_playlist->i_index );
1089     vlc_object_release( p_playlist );
1090     return item;
1091 }
1092
1093 /*****************************************************************************
1094  * PlaylistView::_SetPlayingIndex
1095  *****************************************************************************/
1096 void
1097 PlaylistView::_SetPlayingIndex( BListItem* playingItem )
1098 {
1099     for ( int32 i = 0; BListItem* item = ItemAt( i ); i++ )
1100     {
1101         if ( item == playingItem )
1102         {
1103             playlist_t * p_playlist;
1104             p_playlist = (playlist_t *) vlc_object_find( p_intf,
1105                 VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
1106         
1107             if( !p_playlist )
1108             {
1109                 return;
1110             }
1111
1112             playlist_Goto( p_playlist, i );
1113             SetCurrent( i );
1114
1115             vlc_object_release( p_playlist );
1116             break;
1117         }
1118     }
1119 }
1120
1121 #endif