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