1 /*****************************************************************************
2 * ListViews.h: BeOS interface list view class implementation
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
5 * $Id: ListViews.cpp,v 1.2 2003/01/22 01:13:22 titer Exp $
7 * Authors: Stephan Aßmus <stippi@yellowbites.com>
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.
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.
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 *****************************************************************************/
33 #include "VlcWrapper.h"
34 #include "InterfaceWindow.h"
35 #include "ListViews.h"
38 #define MAX_DRAG_HEIGHT 200.0
40 #define TEXT_OFFSET 20.0
42 /*****************************************************************************
44 *****************************************************************************/
45 PlaylistItem::PlaylistItem( const char *name )
50 PlaylistItem::~PlaylistItem()
54 /*****************************************************************************
55 * PlaylistItem::DrawItem
56 *****************************************************************************/
58 PlaylistItem::Draw( BView *owner, BRect frame, bool tintedLine,
59 bool active, bool playing )
61 rgb_color color = (rgb_color){ 255, 255, 255, 255 };
63 color = tint_color( color, 1.04 );
66 color = tint_color( color, B_DARKEN_2_TINT );
67 owner->SetLowColor( color );
68 owner->FillRect( frame, B_SOLID_LOW );
70 owner->SetHighColor( 0, 0, 0, 255 );
72 owner->GetFontHeight( &fh );
73 BString truncatedString( Text() );
74 owner->TruncateString( &truncatedString, B_TRUNCATE_MIDDLE,
75 frame.Width() - TEXT_OFFSET - 4.0 );
76 owner->DrawString( truncatedString.String(),
77 BPoint( frame.left + TEXT_OFFSET,
78 frame.top + fh.ascent + 1.0 ) );
82 rgb_color black = (rgb_color){ 0, 0, 0, 255 };
83 rgb_color green = (rgb_color){ 0, 255, 0, 255 };
84 BRect r( 0.0, 0.0, 10.0, 10.0 );
85 r.OffsetTo( frame.left + 4.0,
86 ceilf( ( frame.top + frame.bottom ) / 2.0 ) - 5.0 );
88 green = tint_color( color, B_DARKEN_1_TINT );
89 rgb_color lightGreen = tint_color( green, B_LIGHTEN_2_TINT );
90 rgb_color darkGreen = tint_color( green, B_DARKEN_2_TINT );
92 arrow[0] = r.LeftTop();
93 arrow[1] = r.LeftBottom();
95 arrow[2].y = ( r.top + r.bottom ) / 2.0;
96 owner->BeginLineArray( 6 );
98 owner->AddLine( arrow[0], arrow[1], black );
99 owner->AddLine( BPoint( arrow[1].x + 1.0, arrow[1].y - 1.0 ),
101 owner->AddLine( arrow[0], arrow[2], black );
108 // highlights and shadow
109 owner->AddLine( arrow[1], arrow[2], darkGreen );
110 owner->AddLine( arrow[0], arrow[2], lightGreen );
111 owner->AddLine( arrow[0], arrow[1], lightGreen );
112 owner->EndLineArray();
119 owner->SetHighColor( green );
120 owner->FillPolygon( arrow, 3 );
124 /*****************************************************************************
125 * DragSortableListView class
126 *****************************************************************************/
127 DragSortableListView::DragSortableListView( BRect frame, const char* name,
128 list_view_type type, uint32 resizingMode,
130 : BListView( frame, name, type, resizingMode, flags ),
133 SetViewColor( B_TRANSPARENT_32_BIT );
136 DragSortableListView::~DragSortableListView()
140 /*****************************************************************************
141 * DragSortableListView::Draw
142 *****************************************************************************/
144 DragSortableListView::Draw( BRect updateRect )
146 int32 firstIndex = IndexOf( updateRect.LeftTop() );
147 int32 lastIndex = IndexOf( updateRect.RightBottom() );
148 if ( firstIndex >= 0 )
150 if ( lastIndex < firstIndex )
151 lastIndex = CountItems() - 1;
152 // update rect contains items
153 BRect r( updateRect );
154 for ( int32 i = firstIndex; i <= lastIndex; i++)
157 DrawListItem( this, i, r );
159 updateRect.top = r.bottom + 1.0;
160 if ( updateRect.IsValid() )
162 SetLowColor( 255, 255, 255, 255 );
163 FillRect( updateRect, B_SOLID_LOW );
168 SetLowColor( 255, 255, 255, 255 );
169 FillRect( updateRect, B_SOLID_LOW );
173 /*****************************************************************************
174 * DragSortableListView::InitiateDrag
175 *****************************************************************************/
177 DragSortableListView::InitiateDrag( BPoint point, int32 index, bool )
180 bool success = false;
181 BListItem* item = ItemAt( CurrentSelection( 0 ) );
184 // workarround a timing problem
186 item = ItemAt( index );
190 // create drag message
191 BMessage msg( B_SIMPLE_DATA );
192 MakeDragMessage( &msg );
193 // figure out drag rect
194 float width = Bounds().Width();
195 BRect dragRect(0.0, 0.0, width, -1.0);
196 // figure out, how many items fit into our bitmap
199 for (numItems = 0; BListItem* item = ItemAt( CurrentSelection( numItems ) ); numItems++) {
200 dragRect.bottom += item->Height();
201 if ( dragRect.Height() > MAX_DRAG_HEIGHT ) {
203 dragRect.bottom = MAX_DRAG_HEIGHT;
208 BBitmap* dragBitmap = new BBitmap( dragRect, B_RGB32, true );
209 if ( dragBitmap && dragBitmap->IsValid() ) {
210 if ( BView *v = new BView( dragBitmap->Bounds(), "helper", B_FOLLOW_NONE, B_WILL_DRAW ) ) {
211 dragBitmap->AddChild( v );
213 BRect itemBounds( dragRect) ;
214 itemBounds.bottom = 0.0;
215 // let all selected items, that fit into our drag_bitmap, draw
216 for ( int32 i = 0; i < numItems; i++ ) {
217 int32 index = CurrentSelection( i );
218 BListItem* item = ItemAt( index );
219 itemBounds.bottom = itemBounds.top + item->Height() - 1.0;
220 if ( itemBounds.bottom > dragRect.bottom )
221 itemBounds.bottom = dragRect.bottom;
222 DrawListItem( v, index, itemBounds );
223 itemBounds.top = itemBounds.bottom + 1.0;
225 // make a black frame arround the edge
226 v->SetHighColor( 0, 0, 0, 255 );
227 v->StrokeRect( v->Bounds() );
230 uint8 *bits = (uint8 *)dragBitmap->Bits();
231 int32 height = (int32)dragBitmap->Bounds().Height() + 1;
232 int32 width = (int32)dragBitmap->Bounds().Width() + 1;
233 int32 bpr = dragBitmap->BytesPerRow();
236 for ( int32 y = 0; y < height - ALPHA / 2; y++, bits += bpr ) {
237 uint8 *line = bits + 3;
238 for (uint8 *end = line + 4 * width; line < end; line += 4)
241 for ( int32 y = height - ALPHA / 2; y < height; y++, bits += bpr ) {
242 uint8 *line = bits + 3;
243 for (uint8 *end = line + 4 * width; line < end; line += 4)
244 *line = (height - y) << 1;
247 for ( int32 y = 0; y < height; y++, bits += bpr ) {
248 uint8 *line = bits + 3;
249 for (uint8 *end = line + 4 * width; line < end; line += 4)
253 dragBitmap->Unlock();
258 DragMessage( &msg, dragBitmap, B_OP_ALPHA, BPoint( 0.0, 0.0 ) );
261 DragMessage( &msg, dragRect.OffsetToCopy( point ), this );
267 /*****************************************************************************
268 * DragSortableListView::WindowActivated
269 *****************************************************************************/
271 DragSortableListView::WindowActivated( bool active )
273 // workarround for buggy focus indication of BScrollView
274 if ( BView* view = Parent() )
278 /*****************************************************************************
279 * DragSortableListView::MessageReceived
280 *****************************************************************************/
282 DragSortableListView::MessageReceived(BMessage* message)
284 BListItem *item = NULL;
285 DragSortableListView *list = NULL;
286 if ( message->FindPointer( "list", (void **)&list ) == B_OK
289 int32 count = CountItems();
290 if ( fDropIndex < 0 || fDropIndex > count )
292 bool copy = ( modifiers() & B_SHIFT_KEY );
293 for ( int32 i = 0; message->FindPointer( "item", i, (void **)&item ) == B_OK; i++ )
296 if ( HasItem( item ) )
298 BListItem* itemToAdd = NULL;
299 int32 index = IndexOf( item );
303 itemToAdd = CloneItem( index );
304 Deselect( IndexOf( item ) );
309 if ( index < fDropIndex )
311 if ( RemoveItem( item ) )
316 if ( AddItem( itemToAdd, fDropIndex ) )
317 Select( IndexOf( itemToAdd ), true );
326 BListView::MessageReceived( message );
329 /*****************************************************************************
330 * DragSortableListView::MouseMoved
331 *****************************************************************************/
333 DragSortableListView::MouseMoved(BPoint where, uint32 transit, const BMessage *msg)
335 if ( msg && msg->what == B_SIMPLE_DATA )
342 BRect r(ItemFrame(0L));
343 where.y += r.Height() / 2.0;
344 int32 count = CountItems();
346 for (int32 index = 0; index <= count; index++)
348 r = ItemFrame(index);
349 if (r.Contains(where))
351 SetHighColor(255, 0, 0, 255);
352 StrokeLine(r.LeftTop(), r.RightTop(), B_SOLID_HIGH);
354 StrokeLine(r.LeftTop(), r.RightTop(), B_SOLID_HIGH);
362 // mouse is after last item
366 r.top = ItemFrame(count - 1).bottom + 1.0;
367 SetHighColor(255, 0, 0, 255);
368 StrokeLine(r.LeftTop(), r.RightTop(), B_SOLID_HIGH);
370 StrokeLine(r.LeftTop(), r.RightTop(), B_SOLID_HIGH);
375 // draw drop mark and invalidate previous drop mark
376 BRect r(ItemFrame(0L));
377 where.y += r.Height() / 2.0;
378 int32 count = CountItems();
379 // mouse still after last item?
380 if (fDropIndex == count)
384 r.top = ItemFrame(count - 1).bottom + 1.0;
385 if (r.Contains(where))
389 r.bottom = r.top + 2.0;
393 // mouse still over same item?
394 if (ItemFrame(fDropIndex).Contains(where))
397 InvalidateItem(fDropIndex);
399 // mouse over new item
401 for (int32 index = 0; index <= count; index++)
403 r = ItemFrame(index);
404 if (r.Contains(where))
406 SetHighColor(255, 0, 0, 255);
407 StrokeLine(r.LeftTop(), r.RightTop(), B_SOLID_HIGH);
409 StrokeLine(r.LeftTop(), r.RightTop(), B_SOLID_HIGH);
417 // mouse is after last item
421 r.top = ItemFrame(count - 1).bottom + 1.0;
422 SetHighColor(255, 0, 0, 255);
423 StrokeLine(r.LeftTop(), r.RightTop(), B_SOLID_HIGH);
425 StrokeLine(r.LeftTop(), r.RightTop(), B_SOLID_HIGH);
430 int32 count = CountItems();
433 if (fDropIndex == count)
436 r.top = ItemFrame(count - 1).bottom + 1.0;
437 r.bottom = r.top + 2.0;
441 InvalidateItem(fDropIndex);
450 BListView::MouseMoved(where, transit, msg);
453 /*****************************************************************************
454 * DragSortableListView::MouseUp
455 *****************************************************************************/
457 DragSortableListView::MouseUp( BPoint where )
460 if ( fDropIndex >= 0 && fDropIndex < CountItems() )
461 InvalidateItem( fDropIndex );
462 BListView::MouseUp( where );
465 /*****************************************************************************
466 * DragSortableListView::DrawItem
467 *****************************************************************************/
469 DragSortableListView::DrawItem( BListItem *item, BRect itemFrame, bool complete )
471 DrawListItem( this, IndexOf( item ), itemFrame );
475 /*****************************************************************************
477 *****************************************************************************/
478 PlaylistView::PlaylistView( BRect frame, InterfaceWindow* mainWindow,
479 VlcWrapper * p_wrapper )
480 : DragSortableListView( frame, "playlist listview",
481 B_MULTIPLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES,
482 B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED
483 | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE ),
486 fMainWindow( mainWindow )
488 this->p_wrapper = p_wrapper;
491 PlaylistView::~PlaylistView()
495 /*****************************************************************************
496 * PlaylistView::AttachedToWindow
497 *****************************************************************************/
499 PlaylistView::AttachedToWindow()
501 // get pulse message every two frames
502 Window()->SetPulseRate(80000);
505 /*****************************************************************************
506 * PlaylistView::MouseDown
507 *****************************************************************************/
509 PlaylistView::MouseDown( BPoint where )
512 Window()->CurrentMessage()->FindInt32( "clicks", &clicks );
513 bool handled = false;
514 for ( int32 i = 0; PlaylistItem* item = (PlaylistItem*)ItemAt( i ); i++ )
516 BRect r = ItemFrame( i );
517 if ( r.Contains( where ) )
521 p_wrapper->PlaylistJumpTo( i );
524 else if ( i == fCurrentIndex )
526 r.right = r.left + TEXT_OFFSET;
527 if ( r.Contains ( where ) )
529 fMainWindow->PostMessage( PAUSE_PLAYBACK );
538 DragSortableListView::MouseDown(where);
541 /*****************************************************************************
542 * PlaylistView::KeyDown
543 *****************************************************************************/
545 PlaylistView::KeyDown( const char* bytes, int32 numBytes )
550 if ( ( bytes[0] == B_BACKSPACE ) || ( bytes[0] == B_DELETE ) )
552 int32 i = CurrentSelection();
553 if ( BListItem *item = ItemAt( i ) )
555 /* if ( RemoveItem( item ) )
562 DragSortableListView::KeyDown( bytes, numBytes );
565 /*****************************************************************************
566 * PlaylistView::Pulse
567 *****************************************************************************/
569 PlaylistView::Pulse()
571 if (fMainWindow->IsStopped())
575 /*****************************************************************************
576 * PlaylistView::CloneItem
577 *****************************************************************************/
579 PlaylistView::CloneItem( int32 atIndex ) const
581 BListItem* clone = NULL;
582 if ( PlaylistItem* item = dynamic_cast<PlaylistItem*>( ItemAt( atIndex ) ) )
583 clone = new PlaylistItem( item->Text() );
587 /*****************************************************************************
588 * PlaylistView::DrawListItem
589 *****************************************************************************/
591 PlaylistView::DrawListItem( BView* owner, int32 index, BRect frame ) const
593 if ( PlaylistItem* item = dynamic_cast<PlaylistItem*>( ItemAt( index ) ) )
594 item->Draw( owner, frame, index % 2, index == fCurrentIndex, fPlaying );
597 /*****************************************************************************
598 * PlaylistView::MakeDragMessage
599 *****************************************************************************/
601 PlaylistView::MakeDragMessage( BMessage* message ) const
605 message->AddPointer( "list", (void*)this );
606 for ( int32 i = 0; BListItem* item = ItemAt( CurrentSelection( i ) ); i++ )
607 message->AddPointer( "item", (void*)item );
611 /*****************************************************************************
612 * PlaylistView::SetCurrent
613 *****************************************************************************/
615 PlaylistView::SetCurrent( int32 index )
617 if ( fCurrentIndex != index )
619 InvalidateItem( fCurrentIndex );
620 fCurrentIndex = index;
621 InvalidateItem( fCurrentIndex );
625 /*****************************************************************************
626 * PlaylistView::SetPlaying
627 *****************************************************************************/
629 PlaylistView::SetPlaying( bool playing )
631 if ( fPlaying != playing )
634 InvalidateItem( fCurrentIndex );