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