* extraced PlaylistListView into it's own files

* lots of changes, besically these make the Playlist window usable
  - drag sorting works (hold shift to copy instead of move items)
  - removing items with the delete key works
  - dragging files/folders from Tracker works (hold shift to insert
    them in the existing playlist, othewise the new files replace
    the playlist)
* some refactoring and bug fixes in previously unused functionality
* Playlist can now be locked (needed to be), and is in ControllerView,
  MainWin and PlaylistListView


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21305 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2007-06-03 14:35:48 +00:00
parent c1dac92abf
commit 09464bc90b
14 changed files with 841 additions and 340 deletions
+21 -4
View File
@@ -23,11 +23,10 @@
#include <new>
#include <stdio.h>
#include <string.h>
#include <Debug.h>
#include <Entry.h>
#include <Window.h>
#include <Bitmap.h>
#include <Autolock.h>
#include <Bitmap.h>
#include <Debug.h>
#include <MediaFile.h>
#include <MediaTrack.h>
@@ -87,6 +86,7 @@ Controller::Controller()
, fStopped(true)
, fVolume(1.0)
, fRef()
, fMediaFile(0)
// TODO: remove, InfoWin depends on it but should be fixed
,fAudioTrack(0)
@@ -201,6 +201,11 @@ Controller::SetTo(const entry_ref &ref)
BAutolock al(fVideoSupplierLock);
BAutolock vl(fAudioSupplierLock);
if (fRef == ref)
return B_OK;
fRef = ref;
fAudioTrackList->MakeEmpty();
fVideoTrackList->MakeEmpty();
if (fMediaFile)
@@ -466,6 +471,18 @@ Controller::Pause()
}
void
Controller::TogglePlaying()
{
BAutolock _(fDataLock);
if (IsPaused() || IsStopped())
Play();
else
Pause();
}
bool
Controller::IsPaused() const
{
+3
View File
@@ -21,6 +21,7 @@
#ifndef __CONTROLLER_H
#define __CONTROLLER_H
#include <Entry.h>
#include <MediaDefs.h>
#include <MediaNode.h>
#include <List.h>
@@ -76,6 +77,7 @@ public:
void Stop();
void Play();
void Pause();
void TogglePlaying();
bool IsPaused() const;
bool IsStopped() const;
@@ -158,6 +160,7 @@ private:
volatile bool fStopped;
float fVolume;
entry_ref fRef;
BMediaFile * fMediaFile;
BMediaTrack * fAudioTrack;
BMediaTrack * fVideoTrack;
+6 -10
View File
@@ -20,6 +20,7 @@
*/
#include "ControllerView.h"
#include <Autolock.h>
#include <Message.h>
#include <stdio.h>
#include <string.h>
@@ -91,18 +92,13 @@ ControllerView::EnabledButtons()
void
ControllerView::TogglePlaying()
{
printf("ControllerView::TogglePlaying()\n");
if (fController->IsPaused() || fController->IsStopped())
fController->Play();
else
fController->Pause();
fController->TogglePlaying();
}
void
ControllerView::Stop()
{
printf("ControllerView::Stop()\n");
fController->Stop();
}
@@ -126,7 +122,7 @@ ControllerView::Forward()
void
ControllerView::SkipBackward()
{
printf("ControllerView::SkipBackward()\n");
BAutolock _(fPlaylist);
fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() - 1);
}
@@ -134,7 +130,7 @@ ControllerView::SkipBackward()
void
ControllerView::SkipForward()
{
printf("ControllerView::SkipForward()\n");
BAutolock _(fPlaylist);
fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1);
}
@@ -142,7 +138,6 @@ ControllerView::SkipForward()
void
ControllerView::VolumeChanged(float value)
{
printf("ControllerView::VolumeChanged(%.4f)\n", value);
fController->SetVolume(value);
}
@@ -157,7 +152,6 @@ ControllerView::ToggleMute()
void
ControllerView::PositionChanged(float value)
{
printf("ControllerView::PositionChanged(%.2f)\n", value);
// 0.0 ... 1.0
fController->SetPosition(value);
}
@@ -169,6 +163,8 @@ ControllerView::PositionChanged(float value)
void
ControllerView::CheckSkippable()
{
BAutolock _(fPlaylist);
bool canSkipNext, canSkipPrevious;
fPlaylist->GetSkipInfo(&canSkipPrevious, &canSkipNext);
SetSkippable(canSkipPrevious, canSkipNext);
+1
View File
@@ -32,6 +32,7 @@ Application MediaPlayer :
MainApp.cpp
MainWin.cpp
Playlist.cpp
PlaylistListView.cpp
PlaylistObserver.cpp
PlaylistWindow.cpp
SoundOutput.cpp
+57 -58
View File
@@ -320,21 +320,20 @@ DragSortableListView::MessageReceived(BMessage* message)
{
if (AcceptDragMessage(message)) {
DragSortableListView *list = NULL;
if ( message->FindPointer( "list", (void **)&list ) == B_OK
&& list == this ) {
if (message->FindPointer("list", (void **)&list) == B_OK
&& list == this) {
int32 count = CountItems();
if ( fDropIndex < 0 || fDropIndex > count )
if (fDropIndex < 0 || fDropIndex > count)
fDropIndex = count;
BList items;
BList indices;
int32 index;
for ( int32 i = 0; message->FindInt32( "index", i, &index ) == B_OK; i++ )
if ( BListItem* item = ItemAt(index) )
items.AddItem( (void*)item );
if ( items.CountItems() > 0 ) {
if ( modifiers() & B_SHIFT_KEY )
CopyItems( items, fDropIndex );
for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK; i++)
indices.AddItem((void*)index);
if (indices.CountItems() > 0) {
if (modifiers() & B_SHIFT_KEY)
CopyItems(indices, fDropIndex);
else
MoveItems( items, fDropIndex );
MoveItems(indices, fDropIndex);
}
fDropIndex = -1;
}
@@ -371,9 +370,9 @@ DragSortableListView::MessageReceived(BMessage* message)
}
break;
}
// case B_MODIFIERS_CHANGED:
// ModifiersChanged();
// break;
case B_MODIFIERS_CHANGED:
ModifiersChanged();
break;
case B_MOUSE_WHEEL_CHANGED: {
BListView::MessageReceived( message );
BPoint point;
@@ -625,42 +624,39 @@ DragSortableListView::ScrollTo(int32 index)
// MoveItems
void
DragSortableListView::MoveItems( BList& items, int32 index )
DragSortableListView::MoveItems(BList& indices, int32 index)
{
DeselectAll();
// we remove the items while we look at them, the insertion index is decreased
// when the items index is lower, so that we insert at the right spot after
// removal
BList removedItems;
int32 count = items.CountItems();
for ( int32 i = 0; i < count; i++ )
{
BListItem* item = (BListItem*)items.ItemAt( i );
int32 removeIndex = IndexOf( item );
if ( RemoveItem( item ) && removedItems.AddItem( (void*)item ) )
{
if ( removeIndex < index )
int32 count = indices.CountItems();
for (int32 i = 0; i < count; i++) {
int32 removeIndex = (int32)indices.ItemAtFast(i) - i;
BListItem* item = RemoveItem(removeIndex);
if (item && removedItems.AddItem((void*)item)) {
if (removeIndex < index)
index--;
}
// else ??? -> blow up
}
for ( int32 i = 0; BListItem* item = (BListItem*)removedItems.ItemAt( i ); i++ )
{
if ( AddItem( item, index ) )
{
count = removedItems.CountItems();
for (int32 i = 0; i < count; i++) {
BListItem* item = (BListItem*)removedItems.ItemAtFast(i);
if (AddItem(item, index)) {
// after we're done, the newly inserted items will be selected
Select( index, true );
Select(index, true);
// next items will be inserted after this one
index++;
}
else
} else
delete item;
}
}
// CopyItems
void
DragSortableListView::CopyItems( BList& items, int32 index )
DragSortableListView::CopyItems(BList& indices, int32 toIndex)
{
DeselectAll();
// by inserting the items after we copied all items first, we avoid
@@ -668,37 +664,34 @@ DragSortableListView::CopyItems( BList& items, int32 index )
// in other words, don't touch the list before we know which items
// need to be cloned
BList clonedItems;
int32 count = items.CountItems();
for ( int32 i = 0; i < count; i++ )
{
BListItem* item = CloneItem( IndexOf( (BListItem*)items.ItemAt( i ) ) );
if ( item && !clonedItems.AddItem( (void*)item ) )
int32 count = indices.CountItems();
for (int32 i = 0; i < count; i++) {
int32 index = (int32)indices.ItemAtFast(i);
BListItem* item = CloneItem(index);
if (item && !clonedItems.AddItem((void*)item))
delete item;
}
for ( int32 i = 0; BListItem* item = (BListItem*)clonedItems.ItemAt( i ); i++ )
{
if ( AddItem( item, index ) )
{
count = clonedItems.CountItems();
for (int32 i = 0; i < count; i++) {
BListItem* item = (BListItem*)clonedItems.ItemAtFast(i);
if (AddItem(item, toIndex)) {
// after we're done, the newly inserted items will be selected
Select( index, true );
Select(toIndex, true);
// next items will be inserted after this one
index++;
}
else
toIndex++;
} else
delete item;
}
}
// RemoveItemList
void
DragSortableListView::RemoveItemList( BList& items )
DragSortableListView::RemoveItemList(BList& indices)
{
int32 count = items.CountItems();
for ( int32 i = 0; i < count; i++ )
{
BListItem* item = (BListItem*)items.ItemAt( i );
if ( RemoveItem( item ) )
delete item;
int32 count = indices.CountItems();
for (int32 i = 0; i < count; i++) {
int32 index = (int32)indices.ItemAtFast(i) - i;
delete RemoveItem(index);
}
}
@@ -706,13 +699,19 @@ DragSortableListView::RemoveItemList( BList& items )
void
DragSortableListView::RemoveSelected()
{
// if (fFocusedIndex >= 0)
// return;
BList indices;
for (int32 i = 0; true; i++) {
int32 index = CurrentSelection(i);
if (index < 0)
break;
if (!indices.AddItem((void*)index))
break;
}
BList items;
for ( int32 i = 0; BListItem* item = ItemAt( CurrentSelection( i ) ); i++ )
items.AddItem( (void*)item );
RemoveItemList( items );
DeselectAll();
if (indices.CountItems() > 0)
RemoveItemList(indices);
}
// CountSelectedItems
@@ -720,7 +719,7 @@ int32
DragSortableListView::CountSelectedItems() const
{
int32 count = 0;
while ( CurrentSelection( count ) >= 0 )
while (CurrentSelection(count) >= 0)
count++;
return count;
}
+2 -2
View File
@@ -89,8 +89,8 @@ class DragSortableListView : public BListView {
bool MouseWheelChanged(float x, float y);
virtual void MoveItems(BList& items, int32 toIndex);
virtual void CopyItems(BList& items, int32 toIndex);
virtual void MoveItems(BList& indices, int32 toIndex);
virtual void CopyItems(BList& indices, int32 toIndex);
virtual void RemoveItemList(BList& indices);
void RemoveSelected(); // uses RemoveItemList()
int32 CountSelectedItems() const;
+22 -63
View File
@@ -20,25 +20,27 @@
*/
#include "MainWin.h"
#include <View.h>
#include <Screen.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <Alert.h>
#include <Application.h>
#include <Autolock.h>
#include <Debug.h>
#include <Menu.h>
#include <MenuBar.h>
#include <MenuItem.h>
#include <Application.h>
#include <Alert.h>
#include <stdio.h>
#include <string.h>
#include <Messenger.h>
#include <PopUpMenu.h>
#include <Screen.h>
#include <String.h>
#include <Debug.h>
#include <math.h>
#include <View.h>
#include "ControllerObserver.h"
#include "MainApp.h"
#include "PlaylistObserver.h"
#include "PlaylistWindow.h"
#include "MainApp.h"
#define NAME "MediaPlayer"
#define MIN_WIDTH 250
@@ -317,7 +319,6 @@ MainWin::MessageReceived(BMessage *msg)
// PlaylistObserver messages
case MSG_PLAYLIST_REF_ADDED: {
printf("MSG_PLAYLIST_REF_ADDED\n");
entry_ref ref;
int32 index;
if (msg->FindRef("refs", &ref) == B_OK
@@ -327,7 +328,6 @@ printf("MSG_PLAYLIST_REF_ADDED\n");
break;
}
case MSG_PLAYLIST_REF_REMOVED: {
printf("MSG_PLAYLIST_REF_REMOVED\n");
int32 index;
if (msg->FindInt32("index", &index) == B_OK) {
_RemovePlaylistItem(index);
@@ -335,12 +335,12 @@ printf("MSG_PLAYLIST_REF_REMOVED\n");
break;
}
case MSG_PLAYLIST_CURRENT_REF_CHANGED: {
printf("MSG_PLAYLIST_CURRENT_REF_CHANGED\n");
BAutolock _(fPlaylist);
int32 index;
if (msg->FindInt32("index", &index) < B_OK
|| index != fPlaylist->CurrentRefIndex())
break;
printf(" index: %ld\n", index);
entry_ref ref;
if (fPlaylist->GetRefAt(index, &ref) == B_OK) {
printf("open ref: %s\n", ref.name);
@@ -352,7 +352,6 @@ printf(" index: %ld\n", index);
// ControllerObserver messages
case MSG_CONTROLLER_FILE_FINISHED:
printf("MSG_CONTROLLER_FILE_FINISHED\n");
fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1);
break;
case MSG_CONTROLLER_FILE_CHANGED:
@@ -686,7 +685,7 @@ MainWin::ShowPlaylistWindow()
{
if (!fPlaylistWindow) {
fPlaylistWindow = new PlaylistWindow(BRect(150, 150, 400, 500),
fPlaylist);
fPlaylist, fController);
fPlaylistWindow->Show();
return;
}
@@ -731,34 +730,13 @@ MainWin::VideoFormatChange(int width, int height, float width_scale, float heigh
void
MainWin::_RefsReceived(BMessage *msg)
{
printf("MainWin::_RefsReceived\n");
// the playlist ist replaced by dropped files
// or the dropped files are appended to the end
// of the existing playlist if <shift> is pressed
bool add = modifiers() & B_SHIFT_KEY;
int32 appendIndex = modifiers() & B_SHIFT_KEY ?
fPlaylist->CountItems() : -1;
if (!add)
fPlaylist->MakeEmpty();
bool startPlaying = fPlaylist->CountItems() == 0;
Playlist temporaryPlaylist;
Playlist* playlist = add ? &temporaryPlaylist : fPlaylist;
entry_ref ref;
for (int i = 0; B_OK == msg->FindRef("refs", i, &ref); i++)
_AppendToPlaylist(ref, playlist);
playlist->Sort();
if (add)
fPlaylist->AdoptPlaylist(temporaryPlaylist);
if (startPlaying) {
// open first file
fPlaylist->SetCurrentRefIndex(0);
}
fPlaylist->AppendRefs(msg, appendIndex);
}
@@ -1414,9 +1392,10 @@ MainWin::_UpdateControlsEnabledStatus()
void
MainWin::_UpdatePlaylistMenu()
{
fPlaylistMenu->RemoveItems(0, fPlaylistMenu->CountItems(), true);
if (!fPlaylist->Lock())
return;
// TODO: lock fPlaylist
fPlaylistMenu->RemoveItems(0, fPlaylistMenu->CountItems(), true);
int32 count = fPlaylist->CountItems();
for (int32 i = 0; i < count; i++) {
@@ -1428,6 +1407,8 @@ MainWin::_UpdatePlaylistMenu()
fPlaylistMenu->SetTargetForItems(this);
_MarkPlaylistItem(fPlaylist->CurrentRefIndex());
fPlaylist->Unlock();
}
@@ -1462,25 +1443,3 @@ MainWin::_MarkPlaylistItem(int32 index)
}
void
MainWin::_AppendToPlaylist(const entry_ref& ref, Playlist* playlist)
{
// recursively append the ref (dive into folders)
BEntry entry(&ref, true);
if (entry.InitCheck() < B_OK)
return;
if (!entry.Exists())
return;
if (entry.IsDirectory()) {
BDirectory dir(&entry);
if (dir.InitCheck() < B_OK)
return;
entry.Unset();
entry_ref subRef;
while (dir.GetNextRef(&subRef) == B_OK)
_AppendToPlaylist(subRef, playlist);
} else if (entry.IsFile()) {
playlist->AddRef(ref);
}
}
-2
View File
@@ -91,8 +91,6 @@ private:
int32 index);
void _RemovePlaylistItem(int32 index);
void _MarkPlaylistItem(int32 index);
void _AppendToPlaylist(const entry_ref& ref,
Playlist* playlist);
BMenuBar* fMenuBar;
BView* fBackground;
+91 -13
View File
@@ -25,6 +25,9 @@
#include <stdio.h>
#include <string.h>
#include <Autolock.h>
#include <Directory.h>
#include <Message.h>
#include <Path.h>
using std::nothrow;
@@ -43,7 +46,8 @@ void Playlist::Listener::CurrentRefChanged(int32 newIndex) {}
Playlist::Playlist()
: fRefs()
: BLocker("playlist lock")
, fRefs()
, fCurrentIndex(-1)
{
}
@@ -104,6 +108,10 @@ Playlist::AddRef(const entry_ref &ref, int32 index)
return false;
}
_NotifyRefAdded(ref, index);
if (index <= fCurrentIndex)
SetCurrentRefIndex(fCurrentIndex + 1);
return true;
}
@@ -129,6 +137,8 @@ Playlist::AdoptPlaylist(Playlist& other, int32 index)
entry_ref* ref = (entry_ref*)fRefs.ItemAtFast(i);
_NotifyRefAdded(*ref, i);
}
if (index <= fCurrentIndex)
SetCurrentRefIndex(fCurrentIndex + count);
// empty the other list, so that the entry_refs are no ours
other.fRefs.MakeEmpty();
return true;
@@ -138,7 +148,7 @@ Playlist::AdoptPlaylist(Playlist& other, int32 index)
entry_ref
Playlist::RemoveRef(int32 index)
Playlist::RemoveRef(int32 index, bool careAboutCurrentIndex)
{
entry_ref _ref;
entry_ref* ref = (entry_ref*)fRefs.RemoveItem(index);
@@ -147,21 +157,29 @@ Playlist::RemoveRef(int32 index)
_NotifyRefRemoved(index);
_ref = *ref;
delete ref;
if (careAboutCurrentIndex) {
if (index == fCurrentIndex)
SetCurrentRefIndex(-1);
else if (index < fCurrentIndex)
SetCurrentRefIndex(fCurrentIndex - 1);
}
return _ref;
}
//int32
//Playlist::IndexOf(const entry_ref& _ref) const
//{
// int32 count = CountItems();
// for (int32 i = 0; i < count; i++) {
// entry_ref* ref = (entry_ref*)fRefs.ItemAtFast(i);
// if (*ref == _ref)
// return i;
// }
// return -1;
//}
int32
Playlist::IndexOf(const entry_ref& _ref) const
{
int32 count = CountItems();
for (int32 i = 0; i < count; i++) {
entry_ref* ref = (entry_ref*)fRefs.ItemAtFast(i);
if (*ref == _ref)
return i;
}
return -1;
}
status_t
@@ -223,6 +241,7 @@ Playlist::GetSkipInfo(bool* canSkipPrevious, bool* canSkipNext) const
bool
Playlist::AddListener(Listener* listener)
{
BAutolock _(this);
if (listener && !fListeners.HasItem(listener))
return fListeners.AddItem(listener);
return false;
@@ -232,6 +251,7 @@ Playlist::AddListener(Listener* listener)
void
Playlist::RemoveListener(Listener* listener)
{
BAutolock _(this);
fListeners.RemoveItem(listener);
}
@@ -239,6 +259,64 @@ Playlist::RemoveListener(Listener* listener)
// #pragma mark -
void
Playlist::AppendRefs(BMessage* refsReceivedMessage, int32 appendIndex)
{
// the playlist ist replaced by the refs in the message
// or the refs are appended at the appendIndex
// in the existing playlist
bool add = appendIndex >= 0;
if (!add)
MakeEmpty();
bool startPlaying = CountItems() == 0;
Playlist temporaryPlaylist;
Playlist* playlist = add ? &temporaryPlaylist : this;
entry_ref ref;
for (int i = 0; refsReceivedMessage->FindRef("refs", i, &ref) == B_OK; i++)
AppendToPlaylistRecursive(ref, playlist);
playlist->Sort();
if (add)
AdoptPlaylist(temporaryPlaylist, appendIndex);
if (startPlaying) {
// open first file
SetCurrentRefIndex(0);
}
}
/*static*/ void
Playlist::AppendToPlaylistRecursive(const entry_ref& ref, Playlist* playlist)
{
// recursively append the ref (dive into folders)
BEntry entry(&ref, true);
if (entry.InitCheck() < B_OK)
return;
if (!entry.Exists())
return;
if (entry.IsDirectory()) {
BDirectory dir(&entry);
if (dir.InitCheck() < B_OK)
return;
entry.Unset();
entry_ref subRef;
while (dir.GetNextRef(&subRef) == B_OK)
AppendToPlaylistRecursive(subRef, playlist);
} else if (entry.IsFile()) {
playlist->AddRef(ref);
}
}
// #pragma mark -
int
Playlist::playlist_cmp(const void *p1, const void *p2)
{
+46 -38
View File
@@ -23,8 +23,9 @@
#include <Entry.h>
#include <List.h>
#include <Locker.h>
class Playlist {
class Playlist : public BLocker {
public:
class Listener {
public:
@@ -40,51 +41,58 @@ public:
};
public:
Playlist();
~Playlist();
// list functionality
void MakeEmpty();
int32 CountItems() const;
void Sort();
Playlist();
~Playlist();
// list functionality
void MakeEmpty();
int32 CountItems() const;
void Sort();
bool AddRef(const entry_ref& ref);
bool AddRef(const entry_ref& ref, int32 index);
entry_ref RemoveRef(int32 index,
bool careAboutCurrentIndex = true);
bool AdoptPlaylist(Playlist& other);
bool AdoptPlaylist(Playlist& other, int32 index);
int32 IndexOf(const entry_ref& ref) const;
status_t GetRefAt(int32 index, entry_ref* ref) const;
// bool HasRef(const entry_ref& ref) const;
// navigating current ref
void SetCurrentRefIndex(int32 index);
int32 CurrentRefIndex() const;
void GetSkipInfo(bool* canSkipPrevious,
bool* canSkipNext) const;
bool AddRef(const entry_ref& ref);
bool AddRef(const entry_ref& ref, int32 index);
entry_ref RemoveRef(int32 index);
// listener support
bool AddListener(Listener* listener);
void RemoveListener(Listener* listener);
bool AdoptPlaylist(Playlist& other);
bool AdoptPlaylist(Playlist& other, int32 index);
// int32 IndexOf(const entry_ref& ref) const;
status_t GetRefAt(int32 index, entry_ref* ref) const;
// bool HasRef(const entry_ref& ref) const;
// navigating current ref
void SetCurrentRefIndex(int32 index);
int32 CurrentRefIndex() const;
void GetSkipInfo(bool* canSkipPrevious,
bool* canSkipNext) const;
// listener support
bool AddListener(Listener* listener);
void RemoveListener(Listener* listener);
// support functions
void AppendRefs(BMessage* refsReceivedMessage,
int32 appendIndex = -1);
static void AppendToPlaylistRecursive(const entry_ref& ref,
Playlist* playlist);
private:
static int playlist_cmp(const void* p1, const void* p2);
static int playlist_cmp(const void* p1, const void* p2);
void _NotifyRefAdded(const entry_ref& ref,
int32 index) const;
void _NotifyRefRemoved(int32 index) const;
void _NotifyRefsSorted() const;
void _NotifyCurrentRefChanged(int32 newIndex) const;
void _NotifyRefAdded(const entry_ref& ref,
int32 index) const;
void _NotifyRefRemoved(int32 index) const;
void _NotifyRefsSorted() const;
void _NotifyCurrentRefChanged(int32 newIndex) const;
private:
BList fRefs;
BList fListeners;
BList fRefs;
BList fListeners;
int32 fCurrentIndex;
int32 fCurrentIndex;
};
#endif
+502
View File
@@ -0,0 +1,502 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "PlaylistListView.h"
#include <new>
#include <stdio.h>
#include <Autolock.h>
#include <Message.h>
#include <ScrollBar.h>
#include <ScrollView.h>
#include <Window.h>
#include "Controller.h"
#include "ControllerObserver.h"
#include "ListViews.h"
#include "PlaybackState.h"
#include "Playlist.h"
#include "PlaylistObserver.h"
using std::nothrow;
enum {
DISPLAY_NAME = 0,
DISPLAY_PATH = 1
};
static float
playback_mark_size(const font_height& fh)
{
return ceilf(fh.ascent * 0.7);
}
static float
text_offset(const font_height& fh)
{
return ceilf(fh.ascent * 0.8);
}
class PlaylistItem : public SimpleItem {
public:
PlaylistItem(const entry_ref& ref);
virtual ~PlaylistItem();
void Draw(BView* owner, BRect frame,
const font_height& fh,
bool tintedLine, uint32 mode,
bool active,
uint32 playbackState);
private:
entry_ref fRef;
};
PlaylistItem::PlaylistItem(const entry_ref& ref)
: SimpleItem(ref.name),
fRef(ref)
{
}
PlaylistItem::~PlaylistItem()
{
}
void
PlaylistItem::Draw(BView* owner, BRect frame, const font_height& fh,
bool tintedLine, uint32 mode, bool active, uint32 playbackState)
{
rgb_color color = (rgb_color){ 255, 255, 255, 255 };
if (tintedLine)
color = tint_color(color, 1.04);
// background
if (IsSelected())
color = tint_color(color, B_DARKEN_2_TINT);
owner->SetLowColor(color);
owner->FillRect(frame, B_SOLID_LOW);
// label
rgb_color black = (rgb_color){ 0, 0, 0, 255 };
owner->SetHighColor(black);
const char* text = Text();
switch (mode) {
case DISPLAY_NAME:
// TODO
break;
case DISPLAY_PATH:
// TODO
break;
default:
break;
}
float playbackMarkSize = playback_mark_size(fh);
float textOffset = text_offset(fh);
BString truncatedString(text);
owner->TruncateString(&truncatedString, B_TRUNCATE_MIDDLE,
frame.Width() - playbackMarkSize - textOffset);
owner->DrawString(truncatedString.String(),
BPoint(frame.left + playbackMarkSize + textOffset,
floorf(frame.top + frame.bottom + fh.ascent) / 2 - 1));
// playmark
if (active) {
rgb_color green = (rgb_color){ 0, 255, 0, 255 };
if (playbackState != PLAYBACK_STATE_PLAYING)
green = tint_color(color, B_DARKEN_1_TINT);
BRect r(0, 0, playbackMarkSize, playbackMarkSize);
r.OffsetTo(frame.left + 4,
ceilf((frame.top + frame.bottom) / 2) - 5);
BPoint arrow[3];
arrow[0] = r.LeftTop();
arrow[1] = r.LeftBottom();
arrow[2].x = r.right;
arrow[2].y = (r.top + r.bottom) / 2;
#ifdef __HAIKU__
owner->SetPenSize(2);
owner->StrokePolygon(arrow, 3);
owner->SetPenSize(1);
#else
rgb_color lightGreen = tint_color(green, B_LIGHTEN_2_TINT);
rgb_color darkGreen = tint_color(green, B_DARKEN_2_TINT);
owner->BeginLineArray( 6 );
// black outline
owner->AddLine(arrow[0], arrow[1], black);
owner->AddLine(BPoint(arrow[1].x + 1.0, arrow[1].y - 1.0),
arrow[2], black);
owner->AddLine(arrow[0], arrow[2], black);
// inset arrow
arrow[0].x += 1.0;
arrow[0].y += 2.0;
arrow[1].x += 1.0;
arrow[1].y -= 2.0;
arrow[2].x -= 2.0;
// highlights and shadow
owner->AddLine(arrow[1], arrow[2], darkGreen);
owner->AddLine(arrow[0], arrow[2], lightGreen);
owner->AddLine(arrow[0], arrow[1], lightGreen);
owner->EndLineArray();
// fill green
arrow[0].x += 1.0;
arrow[0].y += 1.0;
arrow[1].x += 1.0;
arrow[1].y -= 1.0;
arrow[2].x -= 2.0;
#endif // __HAIKU__
owner->SetLowColor(owner->HighColor());
owner->SetHighColor(green);
owner->FillPolygon(arrow, 3);
}
}
// #pragma mark -
PlaylistListView::PlaylistListView(BRect frame, Playlist* playlist,
Controller* controller)
: SimpleListView(frame, "playlist listview", NULL)
, fPlaylist(playlist)
, fPlaylistObserver(new PlaylistObserver(this))
, fController(controller)
, fControllerObserver(new ControllerObserver(this,
OBSERVE_PLAYBACK_STATE_CHANGES))
, fCurrentPlaylistIndex(-1)
, fPlaybackState(PLAYBACK_STATE_STOPPED)
, fLastClickedItem(NULL)
{
fPlaylist->AddListener(fPlaylistObserver);
fController->AddListener(fControllerObserver);
#ifdef __HAIKU__
SetFlags(Flags() & B_SUBPIXEL_PRECISE);
#endif
}
PlaylistListView::~PlaylistListView()
{
fPlaylist->RemoveListener(fPlaylistObserver);
delete fPlaylistObserver;
fController->RemoveListener(fControllerObserver);
delete fControllerObserver;
}
void
PlaylistListView::AttachedToWindow()
{
_FullSync();
SimpleListView::AttachedToWindow();
GetFontHeight(&fFontHeight);
MakeFocus(true);
}
void
PlaylistListView::MessageReceived(BMessage* message)
{
switch (message->what) {
// PlaylistObserver messages
case MSG_PLAYLIST_REF_ADDED: {
entry_ref ref;
int32 index;
if (message->FindRef("refs", &ref) == B_OK
&& message->FindInt32("index", &index) == B_OK)
_AddItem(ref, index);
break;
}
case MSG_PLAYLIST_REF_REMOVED: {
int32 index;
if (message->FindInt32("index", &index) == B_OK)
_RemoveItem(index);
break;
}
case MSG_PLAYLIST_REFS_SORTED:
_FullSync();
break;
case MSG_PLAYLIST_CURRENT_REF_CHANGED: {
int32 index;
if (message->FindInt32("index", &index) == B_OK)
_SetCurrentPlaylistIndex(index);
break;
}
// ControllerObserver messages
case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED: {
uint32 state;
if (message->FindInt32("state", (int32*)&state) == B_OK)
_SetPlaybackState(state);
break;
}
case B_SIMPLE_DATA:
if (message->HasRef("refs"))
_RefsReceived(message, fDropIndex);
else if (message->HasPointer("list"))
SimpleListView::MessageReceived(message);
break;
case B_REFS_RECEIVED:
_RefsReceived(message, fDropIndex);
break;
default:
SimpleListView::MessageReceived(message);
break;
}
}
void
PlaylistListView::MouseDown(BPoint where)
{
if (!IsFocus())
MakeFocus(true);
int32 clicks;
if (Window()->CurrentMessage()->FindInt32("clicks", &clicks) < B_OK)
clicks = 1;
bool handled = false;
float playbackMarkSize = playback_mark_size(fFontHeight);
float textOffset = text_offset(fFontHeight);
for (int32 i = 0;
PlaylistItem* item = dynamic_cast<PlaylistItem*>(ItemAt(i)); i++) {
BRect r = ItemFrame(i);
if (r.Contains(where)) {
if (clicks == 2) {
// only do something if user clicked the same item twice
if (fLastClickedItem == item) {
BAutolock _(fPlaylist);
fPlaylist->SetCurrentRefIndex(i);
handled = true;
}
} else {
// remember last clicked item
fLastClickedItem = item;
if (i == fCurrentPlaylistIndex) {
r.right = r.left + playbackMarkSize + textOffset;
if (r.Contains (where)) {
fController->TogglePlaying();
handled = true;
}
}
}
break;
}
}
if (!handled)
SimpleListView::MouseDown(where);
}
void
PlaylistListView::KeyDown(const char* bytes, int32 numBytes)
{
if (numBytes < 1)
return;
if ((bytes[0] == B_BACKSPACE) || (bytes[0] == B_DELETE))
RemoveSelected();
DragSortableListView::KeyDown(bytes, numBytes);
}
void
PlaylistListView::MoveItems(BList& indices, int32 toIndex)
{
if (!fPlaylist->Lock())
return;
entry_ref currentRef;
bool adjustCurrentRef = fPlaylist->GetRefAt(fPlaylist->CurrentRefIndex(),
&currentRef) == B_OK;
int32 count = indices.CountItems();
entry_ref refs[count];
for (int32 i = 0; i < count; i++) {
int32 index = (int32)indices.ItemAtFast(i) - i;
// "-i" to account for items already removed in the
// target list
if (index < 0) {
// asynchronous message is out of date
return;
}
refs[i] = fPlaylist->RemoveRef(index, false);
if (index < toIndex)
toIndex --;
}
for (int32 i = 0; i < count; i++) {
fPlaylist->AddRef(refs[i], toIndex++);
}
if (adjustCurrentRef)
fPlaylist->SetCurrentRefIndex(fPlaylist->IndexOf(currentRef));
fPlaylist->Unlock();
}
void
PlaylistListView::CopyItems(BList& indices, int32 toIndex)
{
if (!fPlaylist->Lock())
return;
int32 count = indices.CountItems();
entry_ref refs[count];
for (int32 i = 0; i < count; i++) {
int32 index = (int32)indices.ItemAtFast(i);
if (index < 0) {
// asynchronous message is out of date
return;
}
if (fPlaylist->GetRefAt(index, &refs[i]) < B_OK)
return;
}
for (int32 i = 0; i < count; i++) {
fPlaylist->AddRef(refs[i], toIndex++);
}
fPlaylist->Unlock();
}
void
PlaylistListView::RemoveItemList(BList& indices)
{
if (!fPlaylist->Lock())
return;
int32 count = indices.CountItems();
int32 lastRemovedIndex = -1;
for (int32 i = 0; i < count; i++) {
lastRemovedIndex = (int32)indices.ItemAtFast(i) - i;
// "-i" to account for items already removed in the
// target list
fPlaylist->RemoveRef(lastRemovedIndex);
}
// in case we removed the currently playing file
if (fPlaylist->CurrentRefIndex() == -1)
fPlaylist->SetCurrentRefIndex(lastRemovedIndex);
fPlaylist->Unlock();
}
void
PlaylistListView::DrawListItem(BView* owner, int32 index, BRect frame) const
{
if (PlaylistItem* item = dynamic_cast<PlaylistItem*>(ItemAt(index))) {
item->Draw(owner, frame, fFontHeight, index % 2,
DISPLAY_NAME, index == fCurrentPlaylistIndex, fPlaybackState);
}
}
// #pragma mark -
void
PlaylistListView::_FullSync()
{
if (!fPlaylist->Lock())
return;
// TODO: detach scrollbar, and this will be quick...
// BScrollBar* scrollBar = ScrollBar(B_VERTICAL);
// SetScrollBar();
//
MakeEmpty();
int32 count = fPlaylist->CountItems();
for (int32 i = 0; i < count; i++) {
entry_ref ref;
if (fPlaylist->GetRefAt(i, &ref) == B_OK)
_AddItem(ref, i);
}
_SetCurrentPlaylistIndex(fPlaylist->CurrentRefIndex());
_SetPlaybackState(fController->PlaybackState());
fPlaylist->Unlock();
}
void
PlaylistListView::_AddItem(const entry_ref& ref, int32 index)
{
PlaylistItem* item = new (nothrow) PlaylistItem(ref);
if (item)
AddItem(item, index);
}
void
PlaylistListView::_RemoveItem(int32 index)
{
delete RemoveItem(index);
}
void
PlaylistListView::_SetCurrentPlaylistIndex(int32 index)
{
if (fCurrentPlaylistIndex == index)
return;
InvalidateItem(fCurrentPlaylistIndex);
fCurrentPlaylistIndex = index;
InvalidateItem(fCurrentPlaylistIndex);
}
void
PlaylistListView::_SetPlaybackState(uint32 state)
{
if (fPlaybackState == state)
return;
fPlaybackState = state;
InvalidateItem(fCurrentPlaylistIndex);
}
void
PlaylistListView::_RefsReceived(BMessage* message, int32 dropIndex)
{
if (!fPlaylist->Lock())
return;
fPlaylist->AppendRefs(message, dropIndex);
fPlaylist->Unlock();
}
+65
View File
@@ -0,0 +1,65 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#ifndef PLAYLIST_LIST_VIEW_H
#define PLAYLIST_LIST_VIEW_H
#include "ListViews.h"
class Controller;
class ControllerObserver;
class Playlist;
class PlaylistItem;
class PlaylistObserver;
class PlaylistListView : public SimpleListView {
public:
PlaylistListView(BRect frame,
Playlist* playlist,
Controller* controller);
virtual ~PlaylistListView();
// BView interface
virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* message);
virtual void MouseDown(BPoint where);
virtual void KeyDown(const char* bytes, int32 numBytes);
// SimpleListView interface
virtual void MoveItems(BList& indices, int32 toIndex);
virtual void CopyItems(BList& indices, int32 toIndex);
virtual void RemoveItemList(BList& indices);
virtual void DrawListItem(BView* owner, int32 index,
BRect frame) const;
private:
void _FullSync();
void _AddItem(const entry_ref& ref, int32 index);
void _RemoveItem(int32 index);
void _SetCurrentPlaylistIndex(int32 index);
void _SetPlaybackState(uint32 state);
void _RefsReceived(BMessage* message,
int32 dropIndex);
Playlist* fPlaylist;
PlaylistObserver* fPlaylistObserver;
Controller* fController;
ControllerObserver* fControllerObserver;
int32 fCurrentPlaylistIndex;
uint32 fPlaybackState;
font_height fFontHeight;
PlaylistItem* fLastClickedItem;
};
#endif // PLAYLIST_LIST_VIEW_H
+20 -149
View File
@@ -10,161 +10,17 @@
#include <ScrollBar.h>
#include <ScrollView.h>
#include "ListViews.h"
#include "Playlist.h"
#include "PlaylistObserver.h"
class PlaylistListView : public SimpleListView {
public:
PlaylistListView(BRect frame,
Playlist* playlist);
virtual ~PlaylistListView();
// BView interface
virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* message);
// SimpleListView interface
virtual void MoveItems(BList& items, int32 toIndex);
virtual void CopyItems(BList& items, int32 toIndex);
virtual void RemoveItemList(BList& indices);
private:
void _FullSync();
void _AddItem(const entry_ref& ref, int32 index);
void _RemoveItem(int32 index);
Playlist* fPlaylist;
PlaylistObserver* fPlaylistObserver;
};
#include "PlaylistListView.h"
// #pragma mark -
PlaylistListView::PlaylistListView(BRect frame, Playlist* playlist)
: SimpleListView(frame, "playlist listview", NULL)
, fPlaylist(playlist)
, fPlaylistObserver(new PlaylistObserver(this))
{
fPlaylist->AddListener(fPlaylistObserver);
}
PlaylistListView::~PlaylistListView()
{
fPlaylist->RemoveListener(fPlaylistObserver);
delete fPlaylistObserver;
}
void
PlaylistListView::AttachedToWindow()
{
_FullSync();
SimpleListView::AttachedToWindow();
}
void
PlaylistListView::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_PLAYLIST_REF_ADDED: {
entry_ref ref;
int32 index;
if (message->FindRef("refs", &ref) == B_OK
&& message->FindInt32("index", &index) == B_OK)
_AddItem(ref, index);
break;
}
case MSG_PLAYLIST_REF_REMOVED: {
int32 index;
if (message->FindInt32("index", &index) == B_OK)
_RemoveItem(index);
break;
}
case MSG_PLAYLIST_REFS_SORTED:
_FullSync();
break;
default:
SimpleListView::MessageReceived(message);
break;
}
}
void
PlaylistListView::MoveItems(BList& items, int32 toIndex)
{
// TODO: drag indices instead of items! (avoids IndexOf())
int32 count = items.CountItems();
for (int32 i = 0; i < count; i++) {
BListItem* item = (BListItem*)items.ItemAtFast(i);
int32 index = IndexOf(item);
entry_ref ref = fPlaylist->RemoveRef(index);
}
}
void
PlaylistListView::CopyItems(BList& items, int32 toIndex)
{
}
void
PlaylistListView::RemoveItemList(BList& indices)
{
int32 count = indices.CountItems();
for (int32 i = 0; i < count; i++) {
int32 index = (int32)indices.ItemAtFast(i);
fPlaylist->RemoveRef(index);
}
}
void
PlaylistListView::_FullSync()
{
// BScrollBar* scrollBar = ScrollBar(B_VERTICAL);
// SetScrollBar();
//
MakeEmpty();
int32 count = fPlaylist->CountItems();
for (int32 i = 0; i < count; i++) {
entry_ref ref;
if (fPlaylist->GetRefAt(i, &ref) == B_OK)
_AddItem(ref, i);
}
}
void
PlaylistListView::_AddItem(const entry_ref& ref, int32 index)
{
SimpleItem* item = new SimpleItem(ref.name);
AddItem(item, index);
}
void
PlaylistListView::_RemoveItem(int32 index)
{
delete RemoveItem(index);
}
// #pragma mark -
PlaylistWindow::PlaylistWindow(BRect frame, Playlist* playlist)
PlaylistWindow::PlaylistWindow(BRect frame, Playlist* playlist,
Controller* controller)
: BWindow(frame, "Playlist", B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS)
{
frame = Bounds();
frame.right -= B_V_SCROLL_BAR_WIDTH;
PlaylistListView* listView = new PlaylistListView(frame, playlist);
PlaylistListView* listView = new PlaylistListView(frame, playlist,
controller);
fTopView = new BScrollView("playlist scrollview",
listView, B_FOLLOW_ALL, 0, false, true, B_NO_BORDER);
@@ -188,3 +44,18 @@ PlaylistWindow::QuitRequested()
return false;
}
void
PlaylistWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case B_MODIFIERS_CHANGED:
if (LastMouseMovedView())
PostMessage(message, LastMouseMovedView());
break;
default:
BWindow::MessageReceived(message);
break;
}
}
+5 -1
View File
@@ -8,17 +8,21 @@
#ifndef PLAYLIST_WINDOW_H
#define PLAYLIST_WINDOW_H
#include <Window.h>
class Controller;
class Playlist;
class PlaylistWindow : public BWindow {
public:
PlaylistWindow(BRect frame,
Playlist* playlist);
Playlist* playlist,
Controller* controller);
virtual ~PlaylistWindow();
virtual bool QuitRequested();
virtual void MessageReceived(BMessage* message);
private:
BView* fTopView;