* added notification support to Playlist and Controller
* added AbstractLOAdapter by Ingo Weinhold which makes notifications asynchronous * removed "Player" interface/concept, replaced it by the notification mechanism (window loads new file when "current" ref index changes in Playlist) * removed some cross classes dependencies * the wind buttons are not displayed anymore for now * lots of changes to the Controller - the decoder/player threads are kept running for the entire lifetime of the Controller object (in essence, makes it possible to playback seamless) - abstracted BMediaTrack usage into "Video-" and "AudioSupplier" objects (the BMediaTrack pointers are only still there, because I have not gotten around to fix the messy/hacky InfoWindow) - reaching the end of the stream will trigger a notification, so that the next file from the playlist is played - fSoundOutput is managed by the Controller - tried to make seeking seem more controlled (slider doesn't jump back to previous position) - playback position is correctly updated in GUI - volume is maintained independend of SoundOutput so that it can be transfered from one to the next output - performance time is maintained correctly (?) even if no audio stream is present * work in progress Playlist window (drag sorting does not work yet!) * rearranged menus a bit * rearranged overlay code in the VideoView, but it cannot work like it is currently designed, since the buffers need to be switched all at once, which the video decoding thread is not doing yet * dragging files into the main window with shift held down appends to the existing playlist * dropping folders adds files recursively * pressing space toggles playback (instead of changing some settings of the GUI) * fixed some more minor issues or unimplemented stuff in the UI git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21276 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
406228de63
commit
5fa5e5fea7
60
src/apps/mediaplayer/AbstractLOAdapter.cpp
Normal file
60
src/apps/mediaplayer/AbstractLOAdapter.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <bonefish@cs.tu-berlin.de>
|
||||
*/
|
||||
|
||||
#include "AbstractLOAdapter.h"
|
||||
|
||||
#include <Handler.h>
|
||||
#include <Looper.h>
|
||||
#include <Messenger.h>
|
||||
|
||||
// constructor
|
||||
AbstractLOAdapter::AbstractLOAdapter(BHandler* handler)
|
||||
: fHandler(handler),
|
||||
fMessenger(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// constructor
|
||||
AbstractLOAdapter::AbstractLOAdapter(const BMessenger& messenger)
|
||||
: fHandler(NULL),
|
||||
fMessenger(new BMessenger(messenger))
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
AbstractLOAdapter::~AbstractLOAdapter()
|
||||
{
|
||||
delete fMessenger;
|
||||
}
|
||||
|
||||
// DeliverMessage
|
||||
void
|
||||
AbstractLOAdapter::DeliverMessage(BMessage* message)
|
||||
{
|
||||
if (fHandler) {
|
||||
if (BLooper* looper = fHandler->Looper())
|
||||
looper->PostMessage(message, fHandler);
|
||||
} else if (fMessenger)
|
||||
fMessenger->SendMessage(message);
|
||||
}
|
||||
|
||||
// DeliverMessage
|
||||
void
|
||||
AbstractLOAdapter::DeliverMessage(BMessage& message)
|
||||
{
|
||||
DeliverMessage(&message);
|
||||
}
|
||||
|
||||
// DeliverMessage
|
||||
void
|
||||
AbstractLOAdapter::DeliverMessage(uint32 command)
|
||||
{
|
||||
BMessage message(command);
|
||||
DeliverMessage(&message);
|
||||
}
|
||||
|
41
src/apps/mediaplayer/AbstractLOAdapter.h
Normal file
41
src/apps/mediaplayer/AbstractLOAdapter.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <bonefish@cs.tu-berlin.de>
|
||||
*/
|
||||
|
||||
// This class provides some basic functionality for derivation of a
|
||||
// listener -> observer adapter.
|
||||
// The derived class should implement constructors similar to the
|
||||
// ones of this class and pass the respective parameter.
|
||||
// Each of the listener hook functions should construct a message
|
||||
// and let it be delivered by DeliverMessage().
|
||||
|
||||
#ifndef ABSTRACT_LO_ADAPTER_H
|
||||
#define ABSTRACT_LO_ADAPTER_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class BHandler;
|
||||
class BLooper;
|
||||
class BMessage;
|
||||
class BMessenger;
|
||||
|
||||
class AbstractLOAdapter {
|
||||
public:
|
||||
AbstractLOAdapter(BHandler* handler);
|
||||
AbstractLOAdapter(const BMessenger& messenger);
|
||||
virtual ~AbstractLOAdapter();
|
||||
|
||||
void DeliverMessage(BMessage* message);
|
||||
void DeliverMessage(BMessage& message);
|
||||
void DeliverMessage(uint32 command);
|
||||
|
||||
private:
|
||||
BHandler* fHandler;
|
||||
BMessenger* fMessenger;
|
||||
};
|
||||
|
||||
#endif // ABSTRACT_LO_ADAPTER_H
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@
|
||||
* Controller.h - Media Player for the Haiku Operating System
|
||||
*
|
||||
* Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
|
||||
* Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -22,22 +23,47 @@
|
||||
|
||||
#include <MediaDefs.h>
|
||||
#include <MediaNode.h>
|
||||
#include <List.h>
|
||||
#include <Locker.h>
|
||||
#include <String.h>
|
||||
|
||||
class AudioSupplier;
|
||||
class BBitmap;
|
||||
class BMediaFile;
|
||||
class BMediaTrack;
|
||||
class SoundOutput;
|
||||
class VideoSupplier;
|
||||
class VideoView;
|
||||
class ControllerView;
|
||||
|
||||
class Controller
|
||||
{
|
||||
class Controller {
|
||||
public:
|
||||
|
||||
class Listener {
|
||||
public:
|
||||
Listener();
|
||||
virtual ~Listener();
|
||||
|
||||
virtual void FileFinished();
|
||||
virtual void FileChanged();
|
||||
|
||||
virtual void VideoTrackChanged(int32 index);
|
||||
virtual void AudioTrackChanged(int32 index);
|
||||
|
||||
virtual void VideoStatsChanged();
|
||||
virtual void AudioStatsChanged();
|
||||
|
||||
virtual void PlaybackStateChanged(uint32 state);
|
||||
virtual void PositionChanged(float position);
|
||||
virtual void VolumeChanged(float volume);
|
||||
};
|
||||
|
||||
Controller();
|
||||
virtual ~Controller();
|
||||
|
||||
bool Lock();
|
||||
status_t LockWithTimeout(bigtime_t timeout);
|
||||
void Unlock();
|
||||
|
||||
status_t SetTo(const entry_ref &ref);
|
||||
void GetSize(int *width, int *height);
|
||||
|
||||
@ -47,51 +73,67 @@ public:
|
||||
status_t SelectAudioTrack(int n);
|
||||
status_t SelectVideoTrack(int n);
|
||||
|
||||
bigtime_t Duration();
|
||||
bigtime_t Position();
|
||||
|
||||
status_t Seek(bigtime_t pos);
|
||||
|
||||
void Stop();
|
||||
void Play();
|
||||
void Pause();
|
||||
bool IsPaused();
|
||||
bool IsStopped();
|
||||
|
||||
bool IsPaused() const;
|
||||
bool IsStopped() const;
|
||||
uint32 PlaybackState() const;
|
||||
|
||||
bigtime_t Duration();
|
||||
bigtime_t Position();
|
||||
|
||||
void SetVolume(float value);
|
||||
float Volume() const;
|
||||
void SetPosition(float value);
|
||||
|
||||
// video view
|
||||
void SetVideoView(VideoView *view);
|
||||
void SetControllerView(ControllerView *view);
|
||||
|
||||
bool IsOverlayActive();
|
||||
|
||||
void LockBitmap();
|
||||
bool LockBitmap();
|
||||
void UnlockBitmap();
|
||||
BBitmap * Bitmap();
|
||||
|
||||
void VolumeUp();
|
||||
void VolumeDown();
|
||||
|
||||
void SetVolume(float value);
|
||||
|
||||
void SetPosition(float value);
|
||||
|
||||
void UpdateVolume(float value);
|
||||
void UpdatePosition(float value);
|
||||
// notification support
|
||||
bool AddListener(Listener* listener);
|
||||
void RemoveListener(Listener* listener);
|
||||
|
||||
private:
|
||||
static int32 audio_decode_thread(void *self);
|
||||
static int32 video_decode_thread(void *self);
|
||||
static int32 audio_play_thread(void *self);
|
||||
static int32 video_play_thread(void *self);
|
||||
void _AudioDecodeThread();
|
||||
void _AudioPlayThread();
|
||||
|
||||
void AudioDecodeThread();
|
||||
void VideoDecodeThread();
|
||||
void AudioPlayThread();
|
||||
void VideoPlayThread();
|
||||
void _VideoDecodeThread();
|
||||
void _VideoPlayThread();
|
||||
|
||||
void StartThreads();
|
||||
void StopThreads();
|
||||
void _StartThreads();
|
||||
void _StopThreads();
|
||||
|
||||
void _EndOfStreamReached(bool isVideo = false);
|
||||
void _UpdatePosition(bigtime_t position,
|
||||
bool isVideoPosition = false,
|
||||
bool force = false);
|
||||
|
||||
static int32 _VideoDecodeThreadEntry(void *self);
|
||||
static int32 _VideoPlayThreadEntry(void *self);
|
||||
static int32 _AudioDecodeThreadEntry(void *self);
|
||||
static int32 _AudioPlayThreadEntry(void *self);
|
||||
|
||||
private:
|
||||
void _NotifyFileChanged();
|
||||
void _NotifyFileFinished();
|
||||
void _NotifyVideoTrackChanged(int32 index);
|
||||
void _NotifyAudioTrackChanged(int32 index);
|
||||
|
||||
void _NotifyVideoStatsChanged();
|
||||
void _NotifyAudioStatsChanged();
|
||||
|
||||
void _NotifyPlaybackStateChanged();
|
||||
void _NotifyPositionChanged(float position);
|
||||
void _NotifyVolumeChanged(float volume);
|
||||
|
||||
friend class InfoWin;
|
||||
|
||||
enum {
|
||||
@ -106,24 +148,29 @@ private:
|
||||
size_t sizeMax;
|
||||
bigtime_t startTime;
|
||||
bool formatChanged;
|
||||
bool endOfStream;
|
||||
media_format mediaFormat;
|
||||
};
|
||||
|
||||
VideoView * fVideoView;
|
||||
ControllerView * fControllerView;
|
||||
BString fName;
|
||||
volatile bool fPaused;
|
||||
volatile bool fStopped;
|
||||
BMediaFile * fMediaFile;
|
||||
BMediaTrack * fAudioTrack;
|
||||
BMediaTrack * fVideoTrack;
|
||||
float fVolume;
|
||||
|
||||
BLocker fAudioTrackLock;
|
||||
BLocker fVideoTrackLock;
|
||||
BMediaFile * fMediaFile;
|
||||
BMediaTrack * fAudioTrack;
|
||||
BMediaTrack * fVideoTrack;
|
||||
mutable BLocker fDataLock;
|
||||
|
||||
VideoSupplier* fVideoSupplier;
|
||||
AudioSupplier* fAudioSupplier;
|
||||
|
||||
BLocker fVideoSupplierLock;
|
||||
BLocker fAudioSupplierLock;
|
||||
|
||||
BList * fAudioTrackList;
|
||||
BList * fVideoTrackList;
|
||||
bigtime_t fPosition;
|
||||
media_format fAudioFormat;
|
||||
media_format fVideoFormat;
|
||||
|
||||
@ -141,6 +188,7 @@ private:
|
||||
volatile bool fSeekAudio;
|
||||
volatile bool fSeekVideo;
|
||||
volatile bigtime_t fSeekPosition;
|
||||
bigtime_t fPosition;
|
||||
bigtime_t fDuration;
|
||||
|
||||
int32 fAudioBufferCount;
|
||||
@ -157,9 +205,13 @@ private:
|
||||
bigtime_t fTimeSourceSysTime;
|
||||
bigtime_t fTimeSourcePerfTime;
|
||||
bool fAutoplay;
|
||||
volatile bool fPauseAtEndOfStream;
|
||||
volatile bool fSeekToStartAfterPause;
|
||||
|
||||
BBitmap * fCurrentBitmap;
|
||||
BLocker fBitmapLock;
|
||||
|
||||
BList fListeners;
|
||||
};
|
||||
|
||||
|
||||
|
139
src/apps/mediaplayer/ControllerObserver.cpp
Normal file
139
src/apps/mediaplayer/ControllerObserver.cpp
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include "ControllerObserver.h"
|
||||
|
||||
#include <Message.h>
|
||||
|
||||
|
||||
ControllerObserver::ControllerObserver(BHandler* target, uint32 observeFlags)
|
||||
: Controller::Listener()
|
||||
, AbstractLOAdapter(target)
|
||||
, fObserveFlags(observeFlags)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ControllerObserver::~ControllerObserver()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerObserver::FileFinished()
|
||||
{
|
||||
if (!(fObserveFlags & OBSERVE_FILE_CHANGES))
|
||||
return;
|
||||
|
||||
BMessage message(MSG_CONTROLLER_FILE_FINISHED);
|
||||
|
||||
DeliverMessage(message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerObserver::FileChanged()
|
||||
{
|
||||
if (!(fObserveFlags & OBSERVE_FILE_CHANGES))
|
||||
return;
|
||||
|
||||
BMessage message(MSG_CONTROLLER_FILE_CHANGED);
|
||||
|
||||
DeliverMessage(message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerObserver::VideoTrackChanged(int32 index)
|
||||
{
|
||||
if (!(fObserveFlags & OBSERVE_TRACK_CHANGES))
|
||||
return;
|
||||
|
||||
BMessage message(MSG_CONTROLLER_VIDEO_TRACK_CHANGED);
|
||||
message.AddInt32("index", index);
|
||||
|
||||
DeliverMessage(message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerObserver::AudioTrackChanged(int32 index)
|
||||
{
|
||||
if (!(fObserveFlags & OBSERVE_TRACK_CHANGES))
|
||||
return;
|
||||
|
||||
BMessage message(MSG_CONTROLLER_AUDIO_TRACK_CHANGED);
|
||||
message.AddInt32("index", index);
|
||||
|
||||
DeliverMessage(message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerObserver::VideoStatsChanged()
|
||||
{
|
||||
if (!(fObserveFlags & OBSERVE_STAT_CHANGES))
|
||||
return;
|
||||
|
||||
BMessage message(MSG_CONTROLLER_VIDEO_STATS_CHANGED);
|
||||
|
||||
DeliverMessage(message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerObserver::AudioStatsChanged()
|
||||
{
|
||||
if (!(fObserveFlags & OBSERVE_STAT_CHANGES))
|
||||
return;
|
||||
|
||||
BMessage message(MSG_CONTROLLER_AUDIO_STATS_CHANGED);
|
||||
|
||||
DeliverMessage(message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerObserver::PlaybackStateChanged(uint32 state)
|
||||
{
|
||||
if (!(fObserveFlags & OBSERVE_PLAYBACK_STATE_CHANGES))
|
||||
return;
|
||||
|
||||
BMessage message(MSG_CONTROLLER_PLAYBACK_STATE_CHANGED);
|
||||
message.AddInt32("state", state);
|
||||
|
||||
DeliverMessage(message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerObserver::PositionChanged(float position)
|
||||
{
|
||||
if (!(fObserveFlags & OBSERVE_POSITION_CHANGES))
|
||||
return;
|
||||
|
||||
BMessage message(MSG_CONTROLLER_POSITION_CHANGED);
|
||||
message.AddFloat("position", position);
|
||||
|
||||
DeliverMessage(message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerObserver::VolumeChanged(float volume)
|
||||
{
|
||||
if (!(fObserveFlags & OBSERVE_VOLUME_CHANGES))
|
||||
return;
|
||||
|
||||
BMessage message(MSG_CONTROLLER_VOLUME_CHANGED);
|
||||
message.AddFloat("volume", volume);
|
||||
|
||||
DeliverMessage(message);
|
||||
}
|
||||
|
||||
|
65
src/apps/mediaplayer/ControllerObserver.h
Normal file
65
src/apps/mediaplayer/ControllerObserver.h
Normal 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 CONTROLLER_OBSERVER_H
|
||||
#define CONTROLLER_OBSERVER_H
|
||||
|
||||
#include "AbstractLOAdapter.h"
|
||||
#include "Controller.h"
|
||||
|
||||
enum {
|
||||
MSG_CONTROLLER_FILE_FINISHED = 'cnff',
|
||||
MSG_CONTROLLER_FILE_CHANGED = 'cnfc',
|
||||
|
||||
MSG_CONTROLLER_VIDEO_TRACK_CHANGED = 'cnvt',
|
||||
MSG_CONTROLLER_AUDIO_TRACK_CHANGED = 'cnat',
|
||||
|
||||
MSG_CONTROLLER_VIDEO_STATS_CHANGED = 'cnvs',
|
||||
MSG_CONTROLLER_AUDIO_STATS_CHANGED = 'cnas',
|
||||
|
||||
MSG_CONTROLLER_PLAYBACK_STATE_CHANGED = 'cnps',
|
||||
MSG_CONTROLLER_POSITION_CHANGED = 'cnpc',
|
||||
MSG_CONTROLLER_VOLUME_CHANGED = 'cnvc'
|
||||
};
|
||||
|
||||
enum {
|
||||
OBSERVE_FILE_CHANGES = 0x0001,
|
||||
OBSERVE_TRACK_CHANGES = 0x0002,
|
||||
OBSERVE_STAT_CHANGES = 0x0004,
|
||||
OBSERVE_PLAYBACK_STATE_CHANGES = 0x0008,
|
||||
OBSERVE_POSITION_CHANGES = 0x0010,
|
||||
OBSERVE_VOLUME_CHANGES = 0x0020,
|
||||
|
||||
OBSERVE_ALL_CHANGES = 0xffff
|
||||
};
|
||||
|
||||
class ControllerObserver : public Controller::Listener,
|
||||
public AbstractLOAdapter {
|
||||
public:
|
||||
ControllerObserver(BHandler* target,
|
||||
uint32 observeFlags = OBSERVE_ALL_CHANGES);
|
||||
virtual ~ControllerObserver();
|
||||
|
||||
// Controller::Listener interface
|
||||
virtual void FileFinished();
|
||||
virtual void FileChanged();
|
||||
|
||||
virtual void VideoTrackChanged(int32 index);
|
||||
virtual void AudioTrackChanged(int32 index);
|
||||
|
||||
virtual void VideoStatsChanged();
|
||||
virtual void AudioStatsChanged();
|
||||
|
||||
virtual void PlaybackStateChanged(uint32 state);
|
||||
virtual void PositionChanged(float position);
|
||||
virtual void VolumeChanged(float volume);
|
||||
|
||||
private:
|
||||
uint32 fObserveFlags;
|
||||
};
|
||||
|
||||
#endif // CONTROLLER_OBSERVER_H
|
@ -2,6 +2,7 @@
|
||||
* Controller.cpp - Media Player for the Haiku Operating System
|
||||
*
|
||||
* Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
|
||||
* Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -17,26 +18,32 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#include "ControllerView.h"
|
||||
|
||||
#include <Message.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ControllerView.h"
|
||||
#include "Controller.h"
|
||||
#include "Playlist.h"
|
||||
#include "Player.h"
|
||||
#include "PlaylistObserver.h"
|
||||
|
||||
ControllerView::ControllerView(BRect frame, Controller *ctrl, Playlist *pl, Player *p)
|
||||
|
||||
ControllerView::ControllerView(BRect frame, Controller* controller,
|
||||
Playlist* playlist)
|
||||
: TransportControlGroup(frame)
|
||||
, fController(ctrl)
|
||||
, fPlaylist(pl)
|
||||
, fPlayer(p)
|
||||
, fController(controller)
|
||||
, fPlaylist(playlist)
|
||||
, fPlaylistObserver(new PlaylistObserver(this))
|
||||
{
|
||||
fPlaylist->AddListener(fPlaylistObserver);
|
||||
}
|
||||
|
||||
|
||||
ControllerView::~ControllerView()
|
||||
{
|
||||
fPlaylist->RemoveListener(fPlaylistObserver);
|
||||
delete fPlaylistObserver;
|
||||
}
|
||||
|
||||
|
||||
@ -58,6 +65,11 @@ void
|
||||
ControllerView::MessageReceived(BMessage *msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case MSG_PLAYLIST_REF_ADDED:
|
||||
case MSG_PLAYLIST_REF_REMOVED:
|
||||
CheckSkippable();
|
||||
break;
|
||||
|
||||
default:
|
||||
TransportControlGroup::MessageReceived(msg);
|
||||
}
|
||||
@ -69,6 +81,7 @@ ControllerView::MessageReceived(BMessage *msg)
|
||||
uint32
|
||||
ControllerView::EnabledButtons()
|
||||
{
|
||||
// TODO: superflous
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
@ -112,11 +125,7 @@ void
|
||||
ControllerView::SkipBackward()
|
||||
{
|
||||
printf("ControllerView::SkipBackward()\n");
|
||||
entry_ref ref;
|
||||
if (fPlaylist->PrevRef(&ref) == B_OK) {
|
||||
printf("prev ref: %s\n", ref.name);
|
||||
fPlayer->OpenFile(ref);
|
||||
}
|
||||
fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() - 1);
|
||||
}
|
||||
|
||||
|
||||
@ -124,11 +133,7 @@ void
|
||||
ControllerView::SkipForward()
|
||||
{
|
||||
printf("ControllerView::SkipForward()\n");
|
||||
entry_ref ref;
|
||||
if (fPlaylist->NextRef(&ref) == B_OK) {
|
||||
printf("next ref: %s\n", ref.name);
|
||||
fPlayer->OpenFile(ref);
|
||||
}
|
||||
fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1);
|
||||
}
|
||||
|
||||
|
||||
@ -155,3 +160,16 @@ ControllerView::PositionChanged(float value)
|
||||
fController->SetPosition(value);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
void
|
||||
ControllerView::CheckSkippable()
|
||||
{
|
||||
bool canSkipNext, canSkipPrevious;
|
||||
fPlaylist->GetSkipInfo(&canSkipPrevious, &canSkipNext);
|
||||
SetSkippable(canSkipPrevious, canSkipNext);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
* Controller.cpp - Media Player for the Haiku Operating System
|
||||
*
|
||||
* Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
|
||||
* Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -26,35 +27,39 @@
|
||||
|
||||
class Controller;
|
||||
class Playlist;
|
||||
class Player;
|
||||
class PlaylistObserver;
|
||||
|
||||
class ControllerView : public TransportControlGroup
|
||||
{
|
||||
public:
|
||||
ControllerView(BRect frame, Controller *ctrl, Playlist *pl, Player *p);
|
||||
~ControllerView();
|
||||
ControllerView(BRect frame, Controller* controller,
|
||||
Playlist* playlist);
|
||||
~ControllerView();
|
||||
|
||||
private:
|
||||
void AttachedToWindow();
|
||||
void MessageReceived(BMessage *msg);
|
||||
void Draw(BRect updateRect);
|
||||
void AttachedToWindow();
|
||||
void MessageReceived(BMessage *msg);
|
||||
void Draw(BRect updateRect);
|
||||
|
||||
// TransportControlGroup interface
|
||||
virtual uint32 EnabledButtons();
|
||||
virtual void TogglePlaying();
|
||||
virtual void Stop();
|
||||
virtual void Rewind();
|
||||
virtual void Forward();
|
||||
virtual void SkipBackward();
|
||||
virtual void SkipForward();
|
||||
virtual void VolumeChanged(float value);
|
||||
virtual void ToggleMute();
|
||||
virtual void PositionChanged(float value);
|
||||
virtual uint32 EnabledButtons();
|
||||
virtual void TogglePlaying();
|
||||
virtual void Stop();
|
||||
virtual void Rewind();
|
||||
virtual void Forward();
|
||||
virtual void SkipBackward();
|
||||
virtual void SkipForward();
|
||||
virtual void VolumeChanged(float value);
|
||||
virtual void ToggleMute();
|
||||
virtual void PositionChanged(float value);
|
||||
|
||||
// ControllerView
|
||||
void CheckSkippable();
|
||||
|
||||
private:
|
||||
Controller * fController;
|
||||
Playlist * fPlaylist;
|
||||
Player * fPlayer;
|
||||
Controller* fController;
|
||||
Playlist* fPlaylist;
|
||||
PlaylistObserver* fPlaylistObserver;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -4,14 +4,36 @@ SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
AddSubDirSupportedPlatforms libbe_test ;
|
||||
|
||||
# source directories
|
||||
local sourceDirs =
|
||||
supplier
|
||||
;
|
||||
|
||||
local sourceDir ;
|
||||
for sourceDir in $(sourceDirs) {
|
||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src apps mediaplayer $(sourceDir) ] ;
|
||||
}
|
||||
|
||||
Application MediaPlayer :
|
||||
# supplier
|
||||
AudioSupplier.cpp
|
||||
MediaTrackAudioSupplier.cpp
|
||||
MediaTrackVideoSupplier.cpp
|
||||
VideoSupplier.cpp
|
||||
|
||||
# .
|
||||
AbstractLOAdapter.cpp
|
||||
Controller.cpp
|
||||
ControllerObserver.cpp
|
||||
ControllerView.cpp
|
||||
DrawingTidbits.cpp
|
||||
InfoWin.cpp
|
||||
ListViews.cpp
|
||||
MainApp.cpp
|
||||
MainWin.cpp
|
||||
Playlist.cpp
|
||||
PlaylistObserver.cpp
|
||||
PlaylistWindow.cpp
|
||||
SoundOutput.cpp
|
||||
TransportButton.cpp
|
||||
TransportControlGroup.cpp
|
||||
@ -19,7 +41,8 @@ Application MediaPlayer :
|
||||
VideoNode.cpp
|
||||
VideoView.cpp
|
||||
VolumeSlider.cpp
|
||||
: be media tracker $(TARGET_LIBSTDC++)
|
||||
|
||||
: be media tracker translation $(TARGET_LIBSTDC++)
|
||||
: MediaPlayer.rdef
|
||||
;
|
||||
|
||||
|
891
src/apps/mediaplayer/ListViews.cpp
Normal file
891
src/apps/mediaplayer/ListViews.cpp
Normal file
@ -0,0 +1,891 @@
|
||||
/*
|
||||
* Copyright 2006-2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <new>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Cursor.h>
|
||||
#include <Entry.h>
|
||||
#include <MessageRunner.h>
|
||||
#include <Messenger.h>
|
||||
#include <ScrollBar.h>
|
||||
#include <ScrollView.h>
|
||||
#include <String.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include "ListViews.h"
|
||||
|
||||
const unsigned char kCopyCursor[] = { 16, 1, 1, 1,
|
||||
0x00, 0x00, 0x70, 0x00, 0x48, 0x00, 0x48, 0x00,
|
||||
0x27, 0xc0, 0x24, 0xb8, 0x12, 0x54, 0x10, 0x02,
|
||||
0x79, 0xe2, 0x99, 0x22, 0x85, 0x7a, 0x61, 0x4a,
|
||||
0x19, 0xca, 0x04, 0x4a, 0x02, 0x78, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x70, 0x00, 0x78, 0x00, 0x78, 0x00,
|
||||
0x3f, 0xc0, 0x3f, 0xf8, 0x1f, 0xfc, 0x1f, 0xfe,
|
||||
0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xfe,
|
||||
0x1f, 0xfe, 0x07, 0xfe, 0x03, 0xf8, 0x00, 0x00 };
|
||||
|
||||
#define MAX_DRAG_HEIGHT 200.0
|
||||
#define ALPHA 170
|
||||
#define TEXT_OFFSET 5.0
|
||||
|
||||
enum {
|
||||
MSG_TICK = 'tick',
|
||||
};
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// SimpleItem class
|
||||
SimpleItem::SimpleItem( const char *name )
|
||||
: BStringItem( name )
|
||||
{
|
||||
}
|
||||
|
||||
SimpleItem::~SimpleItem()
|
||||
{
|
||||
}
|
||||
|
||||
// SimpleItem::DrawItem
|
||||
void
|
||||
SimpleItem::Draw(BView *owner, BRect frame, uint32 flags)
|
||||
{
|
||||
DrawBackground(owner, frame, flags);
|
||||
// label
|
||||
owner->SetHighColor( 0, 0, 0, 255 );
|
||||
font_height fh;
|
||||
owner->GetFontHeight( &fh );
|
||||
const char* text = Text();
|
||||
BString truncatedString( text );
|
||||
owner->TruncateString( &truncatedString, B_TRUNCATE_MIDDLE,
|
||||
frame.Width() - TEXT_OFFSET - 4.0 );
|
||||
float height = frame.Height();
|
||||
float textHeight = fh.ascent + fh.descent;
|
||||
BPoint textPoint;
|
||||
textPoint.x = frame.left + TEXT_OFFSET;
|
||||
textPoint.y = frame.top
|
||||
+ ceilf(height / 2.0 - textHeight / 2.0
|
||||
+ fh.ascent);
|
||||
owner->DrawString(truncatedString.String(), textPoint);
|
||||
}
|
||||
|
||||
// SimpleItem::DrawBackground
|
||||
void
|
||||
SimpleItem::DrawBackground(BView *owner, BRect frame, uint32 flags)
|
||||
{
|
||||
// stroke a blue frame around the item if it's focused
|
||||
if (flags & FLAGS_FOCUSED) {
|
||||
owner->SetLowColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
|
||||
owner->StrokeRect(frame, B_SOLID_LOW);
|
||||
frame.InsetBy(1.0, 1.0);
|
||||
}
|
||||
// figure out bg-color
|
||||
rgb_color color = (rgb_color){ 255, 255, 255, 255 };
|
||||
if ( flags & FLAGS_TINTED_LINE )
|
||||
color = tint_color( color, 1.06 );
|
||||
// background
|
||||
if ( IsSelected() )
|
||||
color = tint_color( color, B_DARKEN_2_TINT );
|
||||
owner->SetLowColor( color );
|
||||
owner->FillRect( frame, B_SOLID_LOW );
|
||||
}
|
||||
|
||||
// DragSortableListView class
|
||||
DragSortableListView::DragSortableListView(BRect frame, const char* name,
|
||||
list_view_type type, uint32 resizingMode,
|
||||
uint32 flags)
|
||||
: BListView(frame, name, type, resizingMode, flags),
|
||||
fDropRect(0.0, 0.0, -1.0, -1.0),
|
||||
fScrollPulse(NULL),
|
||||
fDropIndex(-1),
|
||||
fLastClickedItem(NULL),
|
||||
fScrollView(NULL),
|
||||
fDragCommand(B_SIMPLE_DATA),
|
||||
fFocusedIndex(-1)
|
||||
{
|
||||
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||
}
|
||||
|
||||
DragSortableListView::~DragSortableListView()
|
||||
{
|
||||
delete fScrollPulse;
|
||||
}
|
||||
|
||||
// AttachedToWindow
|
||||
void
|
||||
DragSortableListView::AttachedToWindow()
|
||||
{
|
||||
BListView::AttachedToWindow();
|
||||
|
||||
// work arround a bug in BListView
|
||||
BRect bounds = Bounds();
|
||||
BListView::FrameResized(bounds.Width(), bounds.Height());
|
||||
}
|
||||
|
||||
// DetachedFromWindow
|
||||
void
|
||||
DragSortableListView::DetachedFromWindow()
|
||||
{
|
||||
}
|
||||
|
||||
// FrameResized
|
||||
void
|
||||
DragSortableListView::FrameResized(float width, float height)
|
||||
{
|
||||
BListView::FrameResized(width, height);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
/*
|
||||
// MakeFocus
|
||||
void
|
||||
DragSortableListView::MakeFocus(bool focused)
|
||||
{
|
||||
if (focused != IsFocus()) {
|
||||
Invalidate();
|
||||
BListView::MakeFocus(focused);
|
||||
}
|
||||
}
|
||||
*/
|
||||
// Draw
|
||||
void
|
||||
DragSortableListView::Draw( BRect updateRect )
|
||||
{
|
||||
int32 firstIndex = IndexOf(updateRect.LeftTop());
|
||||
int32 lastIndex = IndexOf(updateRect.RightBottom());
|
||||
if (firstIndex >= 0) {
|
||||
if (lastIndex < firstIndex)
|
||||
lastIndex = CountItems() - 1;
|
||||
// update rect contains items
|
||||
BRect r = updateRect;
|
||||
for (int32 i = firstIndex; i <= lastIndex; i++) {
|
||||
r = ItemFrame(i);
|
||||
DrawListItem(this, i, r);
|
||||
}
|
||||
updateRect.top = r.bottom + 1.0;
|
||||
if (updateRect.IsValid()) {
|
||||
SetLowColor(255, 255, 255, 255);
|
||||
FillRect(updateRect, B_SOLID_LOW);
|
||||
}
|
||||
} else {
|
||||
SetLowColor(255, 255, 255, 255);
|
||||
FillRect(updateRect, B_SOLID_LOW);
|
||||
}
|
||||
// drop anticipation indication
|
||||
if (fDropRect.IsValid()) {
|
||||
SetHighColor(255, 0, 0, 255);
|
||||
StrokeRect(fDropRect);
|
||||
}
|
||||
/* // focus indication
|
||||
if (IsFocus()) {
|
||||
SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
|
||||
StrokeRect(Bounds());
|
||||
}*/
|
||||
}
|
||||
|
||||
// ScrollTo
|
||||
void
|
||||
DragSortableListView::ScrollTo(BPoint where)
|
||||
{
|
||||
uint32 buttons;
|
||||
BPoint point;
|
||||
GetMouse(&point, &buttons, false);
|
||||
uint32 transit = Bounds().Contains(point) ? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
|
||||
MouseMoved(point, transit, &fDragMessageCopy);
|
||||
BListView::ScrollTo(where);
|
||||
}
|
||||
|
||||
// TargetedByScrollView
|
||||
void
|
||||
DragSortableListView::TargetedByScrollView(BScrollView* scrollView)
|
||||
{
|
||||
fScrollView = scrollView;
|
||||
BListView::TargetedByScrollView(scrollView);
|
||||
}
|
||||
|
||||
// InitiateDrag
|
||||
bool
|
||||
DragSortableListView::InitiateDrag( BPoint point, int32 index, bool )
|
||||
{
|
||||
// supress drag&drop while an item is focused
|
||||
if (fFocusedIndex >= 0)
|
||||
return false;
|
||||
|
||||
bool success = false;
|
||||
BListItem* item = ItemAt( CurrentSelection( 0 ) );
|
||||
if ( !item ) {
|
||||
// workarround a timing problem
|
||||
Select( index );
|
||||
item = ItemAt( index );
|
||||
}
|
||||
if ( item ) {
|
||||
// create drag message
|
||||
BMessage msg( fDragCommand );
|
||||
MakeDragMessage( &msg );
|
||||
// figure out drag rect
|
||||
float width = Bounds().Width();
|
||||
BRect dragRect(0.0, 0.0, width, -1.0);
|
||||
// figure out, how many items fit into our bitmap
|
||||
int32 numItems;
|
||||
bool fade = false;
|
||||
for (numItems = 0; BListItem* item = ItemAt( CurrentSelection( numItems ) ); numItems++) {
|
||||
dragRect.bottom += ceilf( item->Height() ) + 1.0;
|
||||
if ( dragRect.Height() > MAX_DRAG_HEIGHT ) {
|
||||
fade = true;
|
||||
dragRect.bottom = MAX_DRAG_HEIGHT;
|
||||
numItems++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BBitmap* dragBitmap = new BBitmap( dragRect, B_RGB32, true );
|
||||
if ( dragBitmap && dragBitmap->IsValid() ) {
|
||||
if ( BView *v = new BView( dragBitmap->Bounds(), "helper", B_FOLLOW_NONE, B_WILL_DRAW ) ) {
|
||||
dragBitmap->AddChild( v );
|
||||
dragBitmap->Lock();
|
||||
BRect itemBounds( dragRect) ;
|
||||
itemBounds.bottom = 0.0;
|
||||
// let all selected items, that fit into our drag_bitmap, draw
|
||||
for ( int32 i = 0; i < numItems; i++ ) {
|
||||
int32 index = CurrentSelection( i );
|
||||
BListItem* item = ItemAt( index );
|
||||
itemBounds.bottom = itemBounds.top + ceilf( item->Height() );
|
||||
if ( itemBounds.bottom > dragRect.bottom )
|
||||
itemBounds.bottom = dragRect.bottom;
|
||||
DrawListItem( v, index, itemBounds );
|
||||
itemBounds.top = itemBounds.bottom + 1.0;
|
||||
}
|
||||
// make a black frame arround the edge
|
||||
v->SetHighColor( 0, 0, 0, 255 );
|
||||
v->StrokeRect( v->Bounds() );
|
||||
v->Sync();
|
||||
|
||||
uint8 *bits = (uint8 *)dragBitmap->Bits();
|
||||
int32 height = (int32)dragBitmap->Bounds().Height() + 1;
|
||||
int32 width = (int32)dragBitmap->Bounds().Width() + 1;
|
||||
int32 bpr = dragBitmap->BytesPerRow();
|
||||
|
||||
if (fade) {
|
||||
for ( int32 y = 0; y < height - ALPHA / 2; y++, bits += bpr ) {
|
||||
uint8 *line = bits + 3;
|
||||
for (uint8 *end = line + 4 * width; line < end; line += 4)
|
||||
*line = ALPHA;
|
||||
}
|
||||
for ( int32 y = height - ALPHA / 2; y < height; y++, bits += bpr ) {
|
||||
uint8 *line = bits + 3;
|
||||
for (uint8 *end = line + 4 * width; line < end; line += 4)
|
||||
*line = (height - y) << 1;
|
||||
}
|
||||
} else {
|
||||
for ( int32 y = 0; y < height; y++, bits += bpr ) {
|
||||
uint8 *line = bits + 3;
|
||||
for (uint8 *end = line + 4 * width; line < end; line += 4)
|
||||
*line = ALPHA;
|
||||
}
|
||||
}
|
||||
dragBitmap->Unlock();
|
||||
}
|
||||
} else {
|
||||
delete dragBitmap;
|
||||
dragBitmap = NULL;
|
||||
}
|
||||
if (dragBitmap)
|
||||
DragMessage( &msg, dragBitmap, B_OP_ALPHA, BPoint( 0.0, 0.0 ) );
|
||||
else
|
||||
DragMessage( &msg, dragRect.OffsetToCopy( point ), this );
|
||||
|
||||
_SetDragMessage(&msg);
|
||||
success = true;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
// WindowActivated
|
||||
void
|
||||
DragSortableListView::WindowActivated( bool active )
|
||||
{
|
||||
// workarround for buggy focus indication of BScrollView
|
||||
if ( BView* view = Parent() )
|
||||
view->Invalidate();
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
DragSortableListView::MessageReceived(BMessage* message)
|
||||
{
|
||||
if (AcceptDragMessage(message)) {
|
||||
DragSortableListView *list = NULL;
|
||||
if ( message->FindPointer( "list", (void **)&list ) == B_OK
|
||||
&& list == this ) {
|
||||
int32 count = CountItems();
|
||||
if ( fDropIndex < 0 || fDropIndex > count )
|
||||
fDropIndex = count;
|
||||
BList items;
|
||||
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 );
|
||||
else
|
||||
MoveItems( items, fDropIndex );
|
||||
}
|
||||
fDropIndex = -1;
|
||||
}
|
||||
} else {
|
||||
switch ( message->what ) {
|
||||
case MSG_TICK: {
|
||||
float scrollV = 0.0;
|
||||
BRect rect(Bounds());
|
||||
BPoint point;
|
||||
uint32 buttons;
|
||||
GetMouse(&point, &buttons, false);
|
||||
if (rect.Contains(point)) {
|
||||
// calculate the vertical scrolling offset
|
||||
float hotDist = rect.Height() * SCROLL_AREA;
|
||||
if (point.y > rect.bottom - hotDist)
|
||||
scrollV = hotDist - (rect.bottom - point.y);
|
||||
else if (point.y < rect.top + hotDist)
|
||||
scrollV = (point.y - rect.top) - hotDist;
|
||||
}
|
||||
// scroll
|
||||
if (scrollV != 0.0 && fScrollView) {
|
||||
if (BScrollBar* scrollBar = fScrollView->ScrollBar(B_VERTICAL)) {
|
||||
float value = scrollBar->Value();
|
||||
scrollBar->SetValue(scrollBar->Value() + scrollV);
|
||||
if (scrollBar->Value() != value) {
|
||||
// update mouse position
|
||||
uint32 buttons;
|
||||
BPoint point;
|
||||
GetMouse(&point, &buttons, false);
|
||||
uint32 transit = Bounds().Contains(point) ? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
|
||||
MouseMoved(point, transit, &fDragMessageCopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// case B_MODIFIERS_CHANGED:
|
||||
// ModifiersChanged();
|
||||
// break;
|
||||
case B_MOUSE_WHEEL_CHANGED: {
|
||||
BListView::MessageReceived( message );
|
||||
BPoint point;
|
||||
uint32 buttons;
|
||||
GetMouse(&point, &buttons, false);
|
||||
uint32 transit = Bounds().Contains(point) ? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
|
||||
MouseMoved(point, transit, &fDragMessageCopy);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BListView::MessageReceived( message );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// KeyDown
|
||||
void
|
||||
DragSortableListView::KeyDown( const char* bytes, int32 numBytes )
|
||||
{
|
||||
if ( numBytes < 1 )
|
||||
return;
|
||||
|
||||
if ( ( bytes[0] == B_BACKSPACE ) || ( bytes[0] == B_DELETE ) )
|
||||
RemoveSelected();
|
||||
|
||||
BListView::KeyDown( bytes, numBytes );
|
||||
}
|
||||
|
||||
// MouseDown
|
||||
void
|
||||
DragSortableListView::MouseDown( BPoint where )
|
||||
{
|
||||
int32 clicks = 1;
|
||||
uint32 buttons = 0;
|
||||
Window()->CurrentMessage()->FindInt32("clicks", &clicks);
|
||||
Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
|
||||
int32 clickedIndex = -1;
|
||||
for (int32 i = 0; BListItem* item = ItemAt(i); i++) {
|
||||
if (ItemFrame(i).Contains(where)) {
|
||||
if (clicks == 2) {
|
||||
// only do something if user clicked the same item twice
|
||||
if (fLastClickedItem == item)
|
||||
DoubleClicked(i);
|
||||
} else {
|
||||
// remember last clicked item
|
||||
fLastClickedItem = item;
|
||||
}
|
||||
clickedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (clickedIndex == -1)
|
||||
fLastClickedItem = NULL;
|
||||
|
||||
BListItem* item = ItemAt(clickedIndex);
|
||||
if (ListType() == B_MULTIPLE_SELECTION_LIST
|
||||
&& item && (buttons & B_SECONDARY_MOUSE_BUTTON)) {
|
||||
if (item->IsSelected())
|
||||
Deselect(clickedIndex);
|
||||
else
|
||||
Select(clickedIndex, true);
|
||||
} else {
|
||||
BListView::MouseDown(where);
|
||||
}
|
||||
}
|
||||
|
||||
// MouseMoved
|
||||
void
|
||||
DragSortableListView::MouseMoved(BPoint where, uint32 transit, const BMessage *msg)
|
||||
{
|
||||
if (msg && AcceptDragMessage(msg)) {
|
||||
switch (transit) {
|
||||
case B_ENTERED_VIEW:
|
||||
case B_INSIDE_VIEW: {
|
||||
// remember drag message
|
||||
// this is needed to react on modifier changes
|
||||
_SetDragMessage(msg);
|
||||
// set drop target through virtual function
|
||||
SetDropTargetRect(msg, where);
|
||||
// go into autoscrolling mode
|
||||
BRect r = Bounds();
|
||||
r.InsetBy(0.0, r.Height() * SCROLL_AREA);
|
||||
SetAutoScrolling(!r.Contains(where));
|
||||
break;
|
||||
}
|
||||
case B_EXITED_VIEW:
|
||||
// forget drag message
|
||||
_SetDragMessage(NULL);
|
||||
SetAutoScrolling(false);
|
||||
// fall through
|
||||
case B_OUTSIDE_VIEW:
|
||||
_RemoveDropAnticipationRect();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_RemoveDropAnticipationRect();
|
||||
BListView::MouseMoved(where, transit, msg);
|
||||
_SetDragMessage(NULL);
|
||||
SetAutoScrolling(false);
|
||||
|
||||
BCursor cursor(B_HAND_CURSOR);
|
||||
SetViewCursor(&cursor, true);
|
||||
}
|
||||
fLastMousePos = where;
|
||||
}
|
||||
|
||||
// MouseUp
|
||||
void
|
||||
DragSortableListView::MouseUp( BPoint where )
|
||||
{
|
||||
// remove drop mark
|
||||
_SetDropAnticipationRect( BRect( 0.0, 0.0, -1.0, -1.0 ) );
|
||||
SetAutoScrolling(false);
|
||||
// be sure to forget drag message
|
||||
_SetDragMessage(NULL);
|
||||
BListView::MouseUp( where );
|
||||
|
||||
BCursor cursor(B_HAND_CURSOR);
|
||||
SetViewCursor(&cursor, true);
|
||||
}
|
||||
|
||||
// DrawItem
|
||||
void
|
||||
DragSortableListView::DrawItem( BListItem *item, BRect itemFrame, bool complete )
|
||||
{
|
||||
DrawListItem( this, IndexOf( item ), itemFrame );
|
||||
/* if (IsFocus()) {
|
||||
SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
|
||||
StrokeRect(Bounds());
|
||||
}*/
|
||||
}
|
||||
|
||||
// MouseWheelChanged
|
||||
bool
|
||||
DragSortableListView::MouseWheelChanged(float x, float y)
|
||||
{
|
||||
BPoint where;
|
||||
uint32 buttons;
|
||||
GetMouse(&where, &buttons, false);
|
||||
if (Bounds().Contains(where))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// SetDragCommand
|
||||
void
|
||||
DragSortableListView::SetDragCommand(uint32 command)
|
||||
{
|
||||
fDragCommand = command;
|
||||
}
|
||||
|
||||
// ModifiersChaned
|
||||
void
|
||||
DragSortableListView::ModifiersChanged()
|
||||
{
|
||||
SetDropTargetRect(&fDragMessageCopy, fLastMousePos);
|
||||
}
|
||||
|
||||
// SetItemFocused
|
||||
void
|
||||
DragSortableListView::SetItemFocused(int32 index)
|
||||
{
|
||||
InvalidateItem(fFocusedIndex);
|
||||
InvalidateItem(index);
|
||||
fFocusedIndex = index;
|
||||
}
|
||||
|
||||
// AcceptDragMessage
|
||||
bool
|
||||
DragSortableListView::AcceptDragMessage(const BMessage* message) const
|
||||
{
|
||||
return message->what == fDragCommand;
|
||||
}
|
||||
|
||||
// SetDropTargetRect
|
||||
void
|
||||
DragSortableListView::SetDropTargetRect(const BMessage* message, BPoint where)
|
||||
|
||||
{
|
||||
if (AcceptDragMessage(message)) {
|
||||
bool copy = modifiers() & B_SHIFT_KEY;
|
||||
bool replaceAll = !message->HasPointer("list") && !copy;
|
||||
BRect r = Bounds();
|
||||
if (replaceAll) {
|
||||
r.bottom--; // compensate for scrollbar offset
|
||||
_SetDropAnticipationRect(r);
|
||||
fDropIndex = -1;
|
||||
} else {
|
||||
// offset where by half of item height
|
||||
r = ItemFrame(0);
|
||||
where.y += r.Height() / 2.0;
|
||||
|
||||
int32 index = IndexOf(where);
|
||||
if (index < 0)
|
||||
index = CountItems();
|
||||
_SetDropIndex(index);
|
||||
|
||||
const uchar* cursorData = copy ? kCopyCursor : B_HAND_CURSOR;
|
||||
BCursor cursor(cursorData);
|
||||
SetViewCursor(&cursor, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetAutoScrolling
|
||||
void
|
||||
DragSortableListView::SetAutoScrolling(bool enable)
|
||||
{
|
||||
if (fScrollPulse && enable)
|
||||
return;
|
||||
if (enable) {
|
||||
BMessenger messenger(this, Window());
|
||||
BMessage message(MSG_TICK);
|
||||
fScrollPulse = new BMessageRunner(messenger, &message, 40000LL);
|
||||
} else {
|
||||
delete fScrollPulse;
|
||||
fScrollPulse = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// DoesAutoScrolling
|
||||
bool
|
||||
DragSortableListView::DoesAutoScrolling() const
|
||||
{
|
||||
return fScrollPulse;
|
||||
}
|
||||
|
||||
// ScrollTo
|
||||
void
|
||||
DragSortableListView::ScrollTo(int32 index)
|
||||
{
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
if (index >= CountItems())
|
||||
index = CountItems() - 1;
|
||||
|
||||
if (BListItem* item = ItemAt(index)) {
|
||||
BRect itemFrame = ItemFrame(index);
|
||||
BRect bounds = Bounds();
|
||||
if (itemFrame.top < bounds.top) {
|
||||
ScrollTo(itemFrame.LeftTop());
|
||||
} else if (itemFrame.bottom > bounds.bottom) {
|
||||
ScrollTo(BPoint(0.0, itemFrame.bottom - bounds.Height()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MoveItems
|
||||
void
|
||||
DragSortableListView::MoveItems( BList& items, 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 )
|
||||
index--;
|
||||
}
|
||||
// else ??? -> blow up
|
||||
}
|
||||
for ( int32 i = 0; BListItem* item = (BListItem*)removedItems.ItemAt( i ); i++ )
|
||||
{
|
||||
if ( AddItem( item, index ) )
|
||||
{
|
||||
// after we're done, the newly inserted items will be selected
|
||||
Select( index, true );
|
||||
// next items will be inserted after this one
|
||||
index++;
|
||||
}
|
||||
else
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
// CopyItems
|
||||
void
|
||||
DragSortableListView::CopyItems( BList& items, int32 index )
|
||||
{
|
||||
DeselectAll();
|
||||
// by inserting the items after we copied all items first, we avoid
|
||||
// cloning an item we already inserted and messing everything up
|
||||
// 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 ) )
|
||||
delete item;
|
||||
}
|
||||
for ( int32 i = 0; BListItem* item = (BListItem*)clonedItems.ItemAt( i ); i++ )
|
||||
{
|
||||
if ( AddItem( item, index ) )
|
||||
{
|
||||
// after we're done, the newly inserted items will be selected
|
||||
Select( index, true );
|
||||
// next items will be inserted after this one
|
||||
index++;
|
||||
}
|
||||
else
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveItemList
|
||||
void
|
||||
DragSortableListView::RemoveItemList( BList& items )
|
||||
{
|
||||
int32 count = items.CountItems();
|
||||
for ( int32 i = 0; i < count; i++ )
|
||||
{
|
||||
BListItem* item = (BListItem*)items.ItemAt( i );
|
||||
if ( RemoveItem( item ) )
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveSelected
|
||||
void
|
||||
DragSortableListView::RemoveSelected()
|
||||
{
|
||||
// if (fFocusedIndex >= 0)
|
||||
// return;
|
||||
|
||||
BList items;
|
||||
for ( int32 i = 0; BListItem* item = ItemAt( CurrentSelection( i ) ); i++ )
|
||||
items.AddItem( (void*)item );
|
||||
RemoveItemList( items );
|
||||
}
|
||||
|
||||
// CountSelectedItems
|
||||
int32
|
||||
DragSortableListView::CountSelectedItems() const
|
||||
{
|
||||
int32 count = 0;
|
||||
while ( CurrentSelection( count ) >= 0 )
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
// SelectAll
|
||||
void
|
||||
DragSortableListView::SelectAll()
|
||||
{
|
||||
Select(0, CountItems() - 1);
|
||||
}
|
||||
|
||||
// DeleteItem
|
||||
bool
|
||||
DragSortableListView::DeleteItem(int32 index)
|
||||
{
|
||||
BListItem* item = ItemAt(index);
|
||||
if (item && RemoveItem(item)) {
|
||||
delete item;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// _SetDropAnticipationRect
|
||||
void
|
||||
DragSortableListView::_SetDropAnticipationRect(BRect r)
|
||||
{
|
||||
if (fDropRect != r) {
|
||||
if (fDropRect.IsValid())
|
||||
Invalidate(fDropRect);
|
||||
fDropRect = r;
|
||||
if (fDropRect.IsValid())
|
||||
Invalidate(fDropRect);
|
||||
}
|
||||
}
|
||||
|
||||
// _SetDropIndex
|
||||
void
|
||||
DragSortableListView::_SetDropIndex(int32 index)
|
||||
{
|
||||
if (fDropIndex != index) {
|
||||
fDropIndex = index;
|
||||
if (fDropIndex >= 0) {
|
||||
int32 count = CountItems();
|
||||
if (fDropIndex == count) {
|
||||
BRect r;
|
||||
if (BListItem* item = ItemAt(count - 1)) {
|
||||
r = ItemFrame(count - 1);
|
||||
r.top = r.bottom;
|
||||
r.bottom = r.top + 1.0;
|
||||
} else {
|
||||
r = Bounds();
|
||||
r.bottom--; // compensate for scrollbars moved slightly out of window
|
||||
}
|
||||
_SetDropAnticipationRect(r);
|
||||
} else {
|
||||
BRect r = ItemFrame(fDropIndex);
|
||||
r.top--;
|
||||
r.bottom = r.top + 1.0;
|
||||
_SetDropAnticipationRect(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _RemoveDropAnticipationRect
|
||||
void
|
||||
DragSortableListView::_RemoveDropAnticipationRect()
|
||||
{
|
||||
_SetDropAnticipationRect(BRect(0.0, 0.0, -1.0, -1.0));
|
||||
// _SetDropIndex(-1);
|
||||
}
|
||||
|
||||
// _SetDragMessage
|
||||
void
|
||||
DragSortableListView::_SetDragMessage(const BMessage* message)
|
||||
{
|
||||
if (message)
|
||||
fDragMessageCopy = *message;
|
||||
else
|
||||
fDragMessageCopy.what = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// SimpleListView class
|
||||
SimpleListView::SimpleListView(BRect frame, BMessage* selectionChangeMessage)
|
||||
: DragSortableListView(frame, "playlist listview",
|
||||
B_MULTIPLE_SELECTION_LIST, B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_FRAME_EVENTS),
|
||||
fSelectionChangeMessage(selectionChangeMessage)
|
||||
{
|
||||
}
|
||||
|
||||
// SimpleListView class
|
||||
SimpleListView::SimpleListView(BRect frame, const char* name,
|
||||
BMessage* selectionChangeMessage,
|
||||
list_view_type type,
|
||||
uint32 resizingMode, uint32 flags)
|
||||
: DragSortableListView(frame, name, type, resizingMode, flags),
|
||||
fSelectionChangeMessage(selectionChangeMessage)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
SimpleListView::~SimpleListView()
|
||||
{
|
||||
delete fSelectionChangeMessage;
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
SimpleListView::MessageReceived( BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
default:
|
||||
DragSortableListView::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SelectionChanged
|
||||
void
|
||||
SimpleListView::SelectionChanged()
|
||||
{
|
||||
BLooper* looper = Looper();
|
||||
if (fSelectionChangeMessage && looper) {
|
||||
BMessage message(*fSelectionChangeMessage);
|
||||
looper->PostMessage(&message);
|
||||
}
|
||||
}
|
||||
|
||||
// CloneItem
|
||||
BListItem*
|
||||
SimpleListView::CloneItem(int32 atIndex) const
|
||||
{
|
||||
BListItem* clone = NULL;
|
||||
if (SimpleItem* item = dynamic_cast<SimpleItem*>(ItemAt(atIndex)))
|
||||
clone = new SimpleItem(item->Text());
|
||||
return clone;
|
||||
}
|
||||
|
||||
// DrawListItem
|
||||
void
|
||||
SimpleListView::DrawListItem(BView* owner, int32 index, BRect frame) const
|
||||
{
|
||||
if (SimpleItem* item = dynamic_cast<SimpleItem*>(ItemAt(index))) {
|
||||
uint32 flags = FLAGS_NONE;
|
||||
if (index == fFocusedIndex)
|
||||
flags |= FLAGS_FOCUSED;
|
||||
if (index % 2)
|
||||
flags |= FLAGS_TINTED_LINE;
|
||||
item->Draw(owner, frame, flags);
|
||||
}
|
||||
}
|
||||
|
||||
// MakeDragMessage
|
||||
void
|
||||
SimpleListView::MakeDragMessage(BMessage* message) const
|
||||
{
|
||||
if (message) {
|
||||
message->AddPointer( "list", (void*)dynamic_cast<const DragSortableListView*>(this));
|
||||
int32 index;
|
||||
for (int32 i = 0; (index = CurrentSelection(i)) >= 0; i++)
|
||||
message->AddInt32( "index", index );
|
||||
}
|
||||
}
|
||||
|
152
src/apps/mediaplayer/ListViews.h
Normal file
152
src/apps/mediaplayer/ListViews.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2006-2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#ifndef LIST_VIEWS_H
|
||||
#define LIST_VIEWS_H
|
||||
|
||||
#include <ListItem.h>
|
||||
#include <ListView.h>
|
||||
#include <Message.h>
|
||||
|
||||
enum {
|
||||
FLAGS_NONE = 0x00,
|
||||
FLAGS_TINTED_LINE = 0x01,
|
||||
FLAGS_FOCUSED = 0x02,
|
||||
};
|
||||
|
||||
// portion of the listviews height that triggers autoscrolling
|
||||
// when the mouse is over it with a dragmessage
|
||||
#define SCROLL_AREA 0.1
|
||||
|
||||
class BMessageRunner;
|
||||
class BMessageFilter;
|
||||
class InterfaceWindow;
|
||||
class BScrollView;
|
||||
|
||||
// SimpleItem
|
||||
class SimpleItem : public BStringItem {
|
||||
public:
|
||||
SimpleItem(const char* name);
|
||||
virtual ~SimpleItem();
|
||||
|
||||
virtual void Draw(BView* owner, BRect frame,
|
||||
uint32 flags);
|
||||
virtual void DrawBackground(BView* owner, BRect frame,
|
||||
uint32 flags);
|
||||
};
|
||||
|
||||
// DragSortableListView
|
||||
class DragSortableListView : public BListView {
|
||||
public:
|
||||
DragSortableListView(BRect frame, const char* name,
|
||||
list_view_type type = B_SINGLE_SELECTION_LIST,
|
||||
uint32 resizingMode = B_FOLLOW_LEFT
|
||||
| B_FOLLOW_TOP,
|
||||
uint32 flags = B_WILL_DRAW | B_NAVIGABLE
|
||||
| B_FRAME_EVENTS);
|
||||
virtual ~DragSortableListView();
|
||||
|
||||
// BListView interface
|
||||
virtual void AttachedToWindow();
|
||||
virtual void DetachedFromWindow();
|
||||
virtual void FrameResized(float width, float height);
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void ScrollTo(BPoint where);
|
||||
virtual void TargetedByScrollView(BScrollView* scrollView);
|
||||
virtual bool InitiateDrag(BPoint point, int32 index,
|
||||
bool wasSelected);
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual void KeyDown(const char* bytes, int32 numBytes);
|
||||
virtual void MouseDown(BPoint where);
|
||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||
const BMessage* dragMessage);
|
||||
virtual void MouseUp(BPoint where);
|
||||
virtual void WindowActivated(bool active);
|
||||
virtual void DrawItem(BListItem *item, BRect itemFrame,
|
||||
bool complete = false);
|
||||
|
||||
// DragSortableListView
|
||||
virtual void SetDragCommand(uint32 command);
|
||||
virtual void ModifiersChanged(); // called by window
|
||||
virtual void DoubleClicked(int32 index) {}
|
||||
|
||||
virtual void SetItemFocused(int32 index);
|
||||
|
||||
virtual bool AcceptDragMessage(const BMessage* message) const;
|
||||
virtual void SetDropTargetRect(const BMessage* message,
|
||||
BPoint where);
|
||||
|
||||
// autoscrolling
|
||||
void SetAutoScrolling(bool enable);
|
||||
bool DoesAutoScrolling() const;
|
||||
BScrollView* ScrollView() const
|
||||
{ return fScrollView; }
|
||||
void ScrollTo(int32 index);
|
||||
|
||||
bool MouseWheelChanged(float x, float y);
|
||||
|
||||
virtual void MoveItems(BList& items, int32 toIndex);
|
||||
virtual void CopyItems(BList& items, int32 toIndex);
|
||||
virtual void RemoveItemList(BList& indices);
|
||||
void RemoveSelected(); // uses RemoveItemList()
|
||||
int32 CountSelectedItems() const;
|
||||
void SelectAll();
|
||||
virtual bool DeleteItem(int32 index);
|
||||
|
||||
virtual BListItem* CloneItem(int32 atIndex) const = 0;
|
||||
virtual void DrawListItem(BView* owner, int32 index,
|
||||
BRect itemFrame) const = 0;
|
||||
virtual void MakeDragMessage(BMessage* message) const = 0;
|
||||
|
||||
private:
|
||||
void _RemoveDropAnticipationRect();
|
||||
void _SetDragMessage(const BMessage* message);
|
||||
|
||||
BRect fDropRect;
|
||||
BMessage fDragMessageCopy;
|
||||
BMessageRunner* fScrollPulse;
|
||||
BPoint fLastMousePos;
|
||||
|
||||
protected:
|
||||
void _SetDropAnticipationRect(BRect r);
|
||||
void _SetDropIndex(int32 index);
|
||||
|
||||
int32 fDropIndex;
|
||||
BListItem* fLastClickedItem;
|
||||
BScrollView* fScrollView;
|
||||
uint32 fDragCommand;
|
||||
int32 fFocusedIndex;
|
||||
};
|
||||
|
||||
// SimpleListView
|
||||
class SimpleListView : public DragSortableListView {
|
||||
public:
|
||||
SimpleListView(BRect frame,
|
||||
BMessage* selectionChangeMessage = NULL);
|
||||
SimpleListView(BRect frame, const char* name,
|
||||
BMessage* selectionChangeMessage = NULL,
|
||||
list_view_type type = B_MULTIPLE_SELECTION_LIST,
|
||||
uint32 resizingMode = B_FOLLOW_ALL_SIDES,
|
||||
uint32 flags = B_WILL_DRAW | B_NAVIGABLE
|
||||
| B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE);
|
||||
~SimpleListView();
|
||||
|
||||
// DragSortableListView interface
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual void SelectionChanged();
|
||||
|
||||
virtual BListItem* CloneItem(int32 atIndex) const;
|
||||
virtual void DrawListItem(BView* owner, int32 index,
|
||||
BRect itemFrame) const;
|
||||
virtual void MakeDragMessage(BMessage* message) const;
|
||||
|
||||
private:
|
||||
|
||||
BMessage* fSelectionChangeMessage;
|
||||
};
|
||||
|
||||
#endif // LIST_VIEWS_H
|
@ -2,6 +2,7 @@
|
||||
* MainWin.cpp - Media Player for the Haiku Operating System
|
||||
*
|
||||
* Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
|
||||
* Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -18,7 +19,6 @@
|
||||
*
|
||||
*/
|
||||
#include "MainWin.h"
|
||||
#include "MainApp.h"
|
||||
|
||||
#include <View.h>
|
||||
#include <Screen.h>
|
||||
@ -35,6 +35,11 @@
|
||||
#include <Debug.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "ControllerObserver.h"
|
||||
#include "PlaylistObserver.h"
|
||||
#include "PlaylistWindow.h"
|
||||
#include "MainApp.h"
|
||||
|
||||
#define NAME "MediaPlayer"
|
||||
#define MIN_WIDTH 250
|
||||
|
||||
@ -48,6 +53,7 @@ enum
|
||||
M_FILE_OPEN = 0x1000,
|
||||
M_FILE_NEWPLAYER,
|
||||
M_FILE_INFO,
|
||||
M_FILE_PLAYLIST,
|
||||
M_FILE_ABOUT,
|
||||
M_FILE_CLOSE,
|
||||
M_FILE_QUIT,
|
||||
@ -79,6 +85,8 @@ enum
|
||||
M_SELECT_AUDIO_TRACK_END = 0x00000fff,
|
||||
M_SELECT_VIDEO_TRACK = 0x00010000,
|
||||
M_SELECT_VIDEO_TRACK_END = 0x000fffff,
|
||||
|
||||
M_SET_PLAYLIST_POSITION
|
||||
};
|
||||
|
||||
//#define printf(a...)
|
||||
@ -88,11 +96,17 @@ MainWin::MainWin()
|
||||
: BWindow(BRect(100,100,350,300), NAME, B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS /* | B_WILL_ACCEPT_FIRST_CLICK */)
|
||||
, fFilePanel(NULL)
|
||||
, fInfoWin(NULL)
|
||||
, fPlaylistWindow(NULL)
|
||||
, fInfoWinShowing(false)
|
||||
, fHasFile(false)
|
||||
, fHasVideo(false)
|
||||
, fHasAudio(false)
|
||||
, fPlaylist(new Playlist)
|
||||
, fPlaylistObserver(new PlaylistObserver(this))
|
||||
, fController(new Controller)
|
||||
, fControllerObserver(new ControllerObserver(this,
|
||||
OBSERVE_FILE_CHANGES | OBSERVE_TRACK_CHANGES
|
||||
| OBSERVE_PLAYBACK_STATE_CHANGES | OBSERVE_POSITION_CHANGES))
|
||||
, fIsFullscreen(false)
|
||||
, fKeepAspectRatio(true)
|
||||
, fAlwaysOnTop(false)
|
||||
@ -121,6 +135,7 @@ MainWin::MainWin()
|
||||
CreateMenu();
|
||||
fBackground->AddChild(fMenuBar);
|
||||
fMenuBar->ResizeToPreferred();
|
||||
fMenuBarWidth = (int)fMenuBar->Frame().Width() + 1;
|
||||
fMenuBarHeight = (int)fMenuBar->Frame().Height() + 1;
|
||||
fMenuBar->SetResizingMode(B_FOLLOW_NONE);
|
||||
|
||||
@ -131,7 +146,7 @@ MainWin::MainWin()
|
||||
|
||||
// controls
|
||||
rect = BRect(0, fMenuBarHeight + 11, fBackground->Bounds().right, fBackground->Bounds().bottom);
|
||||
fControls = new ControllerView(rect, fController, fPlaylist, this);
|
||||
fControls = new ControllerView(rect, fController, fPlaylist);
|
||||
fBackground->AddChild(fControls);
|
||||
fControls->ResizeToPreferred();
|
||||
fControlsHeight = (int)fControls->Frame().Height() + 1;
|
||||
@ -141,13 +156,14 @@ MainWin::MainWin()
|
||||
|
||||
// fVideoView->ResizeTo(fBackground->Bounds().Width(), fBackground->Bounds().Height() - fMenuBarHeight - fControlsHeight);
|
||||
|
||||
fPlaylist->AddListener(fPlaylistObserver);
|
||||
fController->SetVideoView(fVideoView);
|
||||
fController->SetControllerView(fControls);
|
||||
fController->AddListener(fControllerObserver);
|
||||
fVideoView->IsOverlaySupported();
|
||||
|
||||
printf("fMenuBarHeight %d\n", fMenuBarHeight);
|
||||
printf("fControlsHeight %d\n", fControlsHeight);
|
||||
printf("fControlsWidth %d\n", fControlsWidth);
|
||||
// printf("fMenuBarHeight %d\n", fMenuBarHeight);
|
||||
// printf("fControlsHeight %d\n", fControlsHeight);
|
||||
// printf("fControlsWidth %d\n", fControlsWidth);
|
||||
|
||||
SetupWindow();
|
||||
|
||||
@ -158,13 +174,27 @@ MainWin::MainWin()
|
||||
MainWin::~MainWin()
|
||||
{
|
||||
printf("MainWin::~MainWin\n");
|
||||
delete fPlaylist;
|
||||
delete fController;
|
||||
delete fFilePanel;
|
||||
|
||||
fPlaylist->RemoveListener(fPlaylistObserver);
|
||||
fController->RemoveListener(fControllerObserver);
|
||||
|
||||
// give the views a chance to detach from any notifiers
|
||||
// before we delete them
|
||||
fBackground->RemoveSelf();
|
||||
delete fBackground;
|
||||
|
||||
if (fInfoWin) {
|
||||
fInfoWin->Lock();
|
||||
fInfoWin->Quit();
|
||||
}
|
||||
if (fPlaylistWindow) {
|
||||
fPlaylistWindow->Lock();
|
||||
fPlaylistWindow->Quit();
|
||||
}
|
||||
|
||||
delete fPlaylist;
|
||||
delete fController;
|
||||
delete fFilePanel;
|
||||
}
|
||||
|
||||
|
||||
@ -175,16 +205,26 @@ MainWin::OpenFile(const entry_ref &ref)
|
||||
|
||||
status_t err = fController->SetTo(ref);
|
||||
if (err != B_OK) {
|
||||
char s[300];
|
||||
sprintf(s, "Can't open file\n\n%s\n\nError 0x%08lx\n(%s)\n",
|
||||
ref.name, err, strerror(err));
|
||||
(new BAlert("error", s, "OK"))->Go();
|
||||
if (fPlaylist->CountItems() == 1) {
|
||||
// display error if this is the only file we're supposed to play
|
||||
char s[300];
|
||||
sprintf(s, "Can't open file\n\n%s\n\nError 0x%08lx\n(%s)\n",
|
||||
ref.name, err, strerror(err));
|
||||
(new BAlert("error", s, "OK"))->Go();
|
||||
} else {
|
||||
// just go to the next file and don't bother user
|
||||
// TODO: this makes it impossible to skip backwards
|
||||
// over a non recognized file!
|
||||
fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1);
|
||||
}
|
||||
fHasFile = false;
|
||||
fHasVideo = false;
|
||||
fHasAudio = false;
|
||||
SetTitle(NAME);
|
||||
} else {
|
||||
fHasFile = true;
|
||||
fHasVideo = fController->VideoTrackCount() != 0;
|
||||
fHasAudio = fController->AudioTrackCount() != 0;
|
||||
SetTitle(ref.name);
|
||||
}
|
||||
SetupWindow();
|
||||
@ -198,11 +238,15 @@ MainWin::SetupWindow()
|
||||
// Populate the track menus
|
||||
SetupTrackMenus();
|
||||
// Enable both if a file was loaded
|
||||
fAudioMenu->SetEnabled(fHasFile);
|
||||
fVideoMenu->SetEnabled(fHasFile);
|
||||
fAudioTrackMenu->SetEnabled(fHasFile);
|
||||
fVideoTrackMenu->SetEnabled(fHasFile);
|
||||
// Select first track (might be "none") in both
|
||||
fAudioMenu->ItemAt(0)->SetMarked(true);
|
||||
fVideoMenu->ItemAt(0)->SetMarked(true);
|
||||
fAudioTrackMenu->ItemAt(0)->SetMarked(true);
|
||||
fVideoTrackMenu->ItemAt(0)->SetMarked(true);
|
||||
|
||||
fVideoMenu->SetEnabled(fHasVideo);
|
||||
fAudioMenu->SetEnabled(fHasAudio);
|
||||
fDebugMenu->SetEnabled(fHasVideo);
|
||||
|
||||
if (fHasVideo) {
|
||||
fController->GetSize(&fSourceWidth, &fSourceHeight);
|
||||
@ -215,6 +259,8 @@ MainWin::SetupWindow()
|
||||
fHeightScale = 1.0;
|
||||
}
|
||||
|
||||
UpdateControlsEnabledStatus();
|
||||
|
||||
ResizeWindow(100);
|
||||
|
||||
fVideoView->MakeFocus();
|
||||
@ -238,7 +284,11 @@ MainWin::ResizeWindow(int percent)
|
||||
|
||||
// Calculate and set the initial window size
|
||||
int width = max_c(fControlsWidth, video_width);
|
||||
int height = (fNoMenu ? 0 : fMenuBarHeight) + (fNoControls ? 0 : fControlsHeight) + video_height;
|
||||
int height = (fNoControls ? 0 : fControlsHeight) + video_height;
|
||||
if (!fNoMenu) {
|
||||
width = max_c(width, fMenuBarWidth);
|
||||
height += fMenuBarHeight;
|
||||
}
|
||||
SetWindowSizeLimits();
|
||||
ResizeTo(width - 1, height - 1);
|
||||
}
|
||||
@ -247,10 +297,12 @@ MainWin::ResizeWindow(int percent)
|
||||
void
|
||||
MainWin::SetWindowSizeLimits()
|
||||
{
|
||||
int min_width = fNoControls ? MIN_WIDTH : fControlsWidth;
|
||||
int min_height = (fNoMenu ? 0 : fMenuBarHeight) + (fNoControls ? 0 : fControlsHeight);
|
||||
int minWidth = fNoControls ? MIN_WIDTH : fControlsWidth;
|
||||
if (!fNoMenu)
|
||||
minWidth = max_c(minWidth, fMenuBarWidth);
|
||||
int minHeight = (fNoMenu ? 0 : fMenuBarHeight) + (fNoControls ? 0 : fControlsHeight);
|
||||
|
||||
SetSizeLimits(min_width - 1, 32000, min_height - 1, fHasVideo ? 32000 : min_height - 1);
|
||||
SetSizeLimits(minWidth - 1, 32000, minHeight - 1, fHasVideo ? 32000 : minHeight - 1);
|
||||
}
|
||||
|
||||
|
||||
@ -258,48 +310,55 @@ void
|
||||
MainWin::CreateMenu()
|
||||
{
|
||||
fFileMenu = new BMenu(NAME);
|
||||
fViewMenu = new BMenu("View");
|
||||
fPlaylistMenu = new BMenu("Playlist"B_UTF8_ELLIPSIS);
|
||||
fAudioMenu = new BMenu("Audio");
|
||||
fVideoMenu = new BMenu("Video");
|
||||
fSettingsMenu = new BMenu("Settings");
|
||||
fAudioMenu = new BMenu("Audio Track");
|
||||
fVideoMenu = new BMenu("Video Track");
|
||||
fAudioTrackMenu = new BMenu("Track");
|
||||
fVideoTrackMenu = new BMenu("Track");
|
||||
fDebugMenu = new BMenu("Debug");
|
||||
|
||||
fMenuBar->AddItem(fFileMenu);
|
||||
fMenuBar->AddItem(fViewMenu);
|
||||
fMenuBar->AddItem(fAudioMenu);
|
||||
fMenuBar->AddItem(fVideoMenu);
|
||||
fMenuBar->AddItem(fSettingsMenu);
|
||||
fMenuBar->AddItem(fDebugMenu);
|
||||
// fMenuBar->AddItem(fDebugMenu);
|
||||
|
||||
fFileMenu->AddItem(new BMenuItem("New Player", new BMessage(M_FILE_NEWPLAYER), 'N', B_COMMAND_KEY));
|
||||
fFileMenu->AddItem(new BMenuItem("New Player"B_UTF8_ELLIPSIS, new BMessage(M_FILE_NEWPLAYER), 'N', B_COMMAND_KEY));
|
||||
fFileMenu->AddSeparatorItem();
|
||||
fFileMenu->AddItem(new BMenuItem("Open File"B_UTF8_ELLIPSIS, new BMessage(M_FILE_OPEN), 'O', B_COMMAND_KEY));
|
||||
fFileMenu->AddItem(new BMenuItem("File Info"B_UTF8_ELLIPSIS, new BMessage(M_FILE_INFO), 'I', B_COMMAND_KEY));
|
||||
fFileMenu->AddItem(fPlaylistMenu);
|
||||
fPlaylistMenu->Superitem()->SetShortcut('P', B_COMMAND_KEY);
|
||||
fPlaylistMenu->Superitem()->SetMessage(new BMessage(M_FILE_PLAYLIST));
|
||||
|
||||
fFileMenu->AddSeparatorItem();
|
||||
fFileMenu->AddItem(new BMenuItem("About" NAME B_UTF8_ELLIPSIS, new BMessage(M_FILE_ABOUT)));
|
||||
fFileMenu->AddSeparatorItem();
|
||||
fFileMenu->AddItem(new BMenuItem("Close", new BMessage(M_FILE_CLOSE), 'W', B_COMMAND_KEY));
|
||||
fFileMenu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q', B_COMMAND_KEY));
|
||||
|
||||
fViewMenu->AddItem(new BMenuItem("50% scale", new BMessage(M_VIEW_50), '0', B_COMMAND_KEY));
|
||||
fViewMenu->AddItem(new BMenuItem("100% scale", new BMessage(M_VIEW_100), '1', B_COMMAND_KEY));
|
||||
fViewMenu->AddItem(new BMenuItem("200% scale", new BMessage(M_VIEW_200), '2', B_COMMAND_KEY));
|
||||
fViewMenu->AddItem(new BMenuItem("300% scale", new BMessage(M_VIEW_300), '3', B_COMMAND_KEY));
|
||||
fViewMenu->AddItem(new BMenuItem("400% scale", new BMessage(M_VIEW_400), '4', B_COMMAND_KEY));
|
||||
fViewMenu->AddSeparatorItem();
|
||||
fViewMenu->AddItem(new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
|
||||
// fViewMenu->SetRadioMode(true);
|
||||
// fViewMenu->AddSeparatorItem();
|
||||
// fViewMenu->AddItem(new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
|
||||
fPlaylistMenu->SetRadioMode(true);
|
||||
|
||||
fAudioMenu->AddItem(fAudioTrackMenu);
|
||||
|
||||
fVideoMenu->AddItem(fVideoTrackMenu);
|
||||
fVideoMenu->AddSeparatorItem();
|
||||
fVideoMenu->AddItem(new BMenuItem("50% scale", new BMessage(M_VIEW_50), '0', B_COMMAND_KEY));
|
||||
fVideoMenu->AddItem(new BMenuItem("100% scale", new BMessage(M_VIEW_100), '1', B_COMMAND_KEY));
|
||||
fVideoMenu->AddItem(new BMenuItem("200% scale", new BMessage(M_VIEW_200), '2', B_COMMAND_KEY));
|
||||
fVideoMenu->AddItem(new BMenuItem("300% scale", new BMessage(M_VIEW_300), '3', B_COMMAND_KEY));
|
||||
fVideoMenu->AddItem(new BMenuItem("400% scale", new BMessage(M_VIEW_400), '4', B_COMMAND_KEY));
|
||||
fVideoMenu->AddSeparatorItem();
|
||||
fVideoMenu->AddItem(new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
|
||||
fVideoMenu->AddItem(new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
|
||||
|
||||
fSettingsMenu->AddItem(fAudioMenu);
|
||||
fSettingsMenu->AddItem(fVideoMenu);
|
||||
fSettingsMenu->AddSeparatorItem();
|
||||
fSettingsMenu->AddItem(new BMenuItem("No Menu", new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
|
||||
fSettingsMenu->AddItem(new BMenuItem("No Border", new BMessage(M_TOGGLE_NO_BORDER), 'B', B_COMMAND_KEY));
|
||||
fSettingsMenu->AddItem(new BMenuItem("No Controls", new BMessage(M_TOGGLE_NO_CONTROLS), 'C', B_COMMAND_KEY));
|
||||
fSettingsMenu->AddItem(new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
|
||||
fSettingsMenu->AddItem(new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
|
||||
fSettingsMenu->AddSeparatorItem();
|
||||
fSettingsMenu->AddItem(new BMenuItem("Preferences"B_UTF8_ELLIPSIS, new BMessage(M_PREFERENCES), 'P', B_COMMAND_KEY));
|
||||
// fSettingsMenu->AddSeparatorItem();
|
||||
// fSettingsMenu->AddItem(new BMenuItem("Preferences"B_UTF8_ELLIPSIS, new BMessage(M_PREFERENCES), 'P', B_COMMAND_KEY));
|
||||
|
||||
fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", new BMessage(M_ASPECT_100000_1)));
|
||||
fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", new BMessage(M_ASPECT_106666_1)));
|
||||
@ -309,8 +368,8 @@ MainWin::CreateMenu()
|
||||
fDebugMenu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", new BMessage(M_ASPECT_704_576)));
|
||||
fDebugMenu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", new BMessage(M_ASPECT_544_576)));
|
||||
|
||||
fAudioMenu->SetRadioMode(true);
|
||||
fVideoMenu->SetRadioMode(true);
|
||||
fAudioTrackMenu->SetRadioMode(true);
|
||||
fVideoTrackMenu->SetRadioMode(true);
|
||||
/*
|
||||
fSettingsMenu->ItemAt(3)->SetMarked(fIsFullscreen);
|
||||
fSettingsMenu->ItemAt(5)->SetMarked(fNoMenu);
|
||||
@ -325,8 +384,8 @@ MainWin::CreateMenu()
|
||||
void
|
||||
MainWin::SetupTrackMenus()
|
||||
{
|
||||
fAudioMenu->RemoveItems(0, fAudioMenu->CountItems(), true);
|
||||
fVideoMenu->RemoveItems(0, fVideoMenu->CountItems(), true);
|
||||
fAudioTrackMenu->RemoveItems(0, fAudioTrackMenu->CountItems(), true);
|
||||
fVideoTrackMenu->RemoveItems(0, fVideoTrackMenu->CountItems(), true);
|
||||
|
||||
int c, i;
|
||||
char s[100];
|
||||
@ -334,18 +393,18 @@ MainWin::SetupTrackMenus()
|
||||
c = fController->AudioTrackCount();
|
||||
for (i = 0; i < c; i++) {
|
||||
sprintf(s, "Track %d", i + 1);
|
||||
fAudioMenu->AddItem(new BMenuItem(s, new BMessage(M_SELECT_AUDIO_TRACK + i)));
|
||||
fAudioTrackMenu->AddItem(new BMenuItem(s, new BMessage(M_SELECT_AUDIO_TRACK + i)));
|
||||
}
|
||||
if (!c)
|
||||
fAudioMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY)));
|
||||
fAudioTrackMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY)));
|
||||
|
||||
c = fController->VideoTrackCount();
|
||||
for (i = 0; i < c; i++) {
|
||||
sprintf(s, "Track %d", i + 1);
|
||||
fVideoMenu->AddItem(new BMenuItem(s, new BMessage(M_SELECT_VIDEO_TRACK + i)));
|
||||
fVideoTrackMenu->AddItem(new BMenuItem(s, new BMessage(M_SELECT_VIDEO_TRACK + i)));
|
||||
}
|
||||
if (!c)
|
||||
fVideoMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY)));
|
||||
fVideoTrackMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY)));
|
||||
}
|
||||
|
||||
|
||||
@ -358,7 +417,7 @@ MainWin::QuitRequested()
|
||||
|
||||
|
||||
void
|
||||
MainWin::MouseDown(BMessage *msg)
|
||||
MainWin::MouseDown(BMessage *msg, BView* originalHandler)
|
||||
{
|
||||
BPoint screen_where;
|
||||
uint32 buttons = msg->FindInt32("buttons");
|
||||
@ -366,8 +425,9 @@ MainWin::MouseDown(BMessage *msg)
|
||||
// On Zeta, only "screen_where" is relyable, "where" and "be:view_where" seem to be broken
|
||||
if (B_OK != msg->FindPoint("screen_where", &screen_where)) {
|
||||
// Workaround for BeOS R5, it has no "screen_where"
|
||||
fVideoView->GetMouse(&screen_where, &buttons, false);
|
||||
fVideoView->ConvertToScreen(&screen_where);
|
||||
if (!originalHandler || msg->FindPoint("where", &screen_where) < B_OK)
|
||||
return;
|
||||
originalHandler->ConvertToScreen(&screen_where);
|
||||
}
|
||||
|
||||
// msg->PrintToStream();
|
||||
@ -423,7 +483,7 @@ MainWin::MouseDown(BMessage *msg)
|
||||
|
||||
|
||||
void
|
||||
MainWin::MouseMoved(BMessage *msg)
|
||||
MainWin::MouseMoved(BMessage *msg, BView* originalHandler)
|
||||
{
|
||||
// msg->PrintToStream();
|
||||
|
||||
@ -437,11 +497,13 @@ MainWin::MouseMoved(BMessage *msg)
|
||||
printf("view where: %.0f, %.0f => ", mousePos.x, mousePos.y);
|
||||
fVideoView->ConvertToScreen(&mousePos);
|
||||
*/
|
||||
// On Zeta, only "screen_where" is relyable, "where" and "be:view_where" seem to be broken
|
||||
// On Zeta, only "screen_where" is relyable, "where"
|
||||
// and "be:view_where" seem to be broken
|
||||
if (B_OK != msg->FindPoint("screen_where", &mousePos)) {
|
||||
// Workaround for BeOS R5, it has no "screen_where"
|
||||
fVideoView->GetMouse(&mousePos, &buttons, false);
|
||||
fVideoView->ConvertToScreen(&mousePos);
|
||||
if (!originalHandler || msg->FindPoint("where", &mousePos) < B_OK)
|
||||
return;
|
||||
originalHandler->ConvertToScreen(&mousePos);
|
||||
}
|
||||
// printf("screen where: %.0f, %.0f => ", mousePos.x, mousePos.y);
|
||||
float delta_x = mousePos.x - fMouseDownMousePos.x;
|
||||
@ -470,6 +532,11 @@ MainWin::ShowContextMenu(const BPoint &screen_point)
|
||||
BMenuItem *item;
|
||||
menu->AddItem(item = new BMenuItem("Full Screen", new BMessage(M_TOGGLE_FULLSCREEN), 'F', B_COMMAND_KEY));
|
||||
item->SetMarked(fIsFullscreen);
|
||||
item->SetEnabled(fHasVideo);
|
||||
menu->AddItem(item = new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
|
||||
item->SetMarked(fKeepAspectRatio);
|
||||
item->SetEnabled(fHasVideo);
|
||||
|
||||
menu->AddSeparatorItem();
|
||||
menu->AddItem(item = new BMenuItem("No Menu", new BMessage(M_TOGGLE_NO_MENU), 'M', B_COMMAND_KEY));
|
||||
item->SetMarked(fNoMenu);
|
||||
@ -477,8 +544,7 @@ MainWin::ShowContextMenu(const BPoint &screen_point)
|
||||
item->SetMarked(fNoBorder);
|
||||
menu->AddItem(item = new BMenuItem("Always on Top", new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T', B_COMMAND_KEY));
|
||||
item->SetMarked(fAlwaysOnTop);
|
||||
menu->AddItem(item = new BMenuItem("Keep Aspect Ratio", new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K', B_COMMAND_KEY));
|
||||
item->SetMarked(fKeepAspectRatio);
|
||||
|
||||
menu->AddSeparatorItem();
|
||||
menu->AddItem(new BMenuItem("About" NAME B_UTF8_ELLIPSIS, new BMessage(M_FILE_ABOUT)));
|
||||
menu->AddSeparatorItem();
|
||||
@ -592,6 +658,15 @@ MainWin::ShowFileInfo()
|
||||
{
|
||||
if (!fInfoWin)
|
||||
fInfoWin = new InfoWin(this);
|
||||
|
||||
if (fInfoWin->Lock()) {
|
||||
if (fInfoWin->IsHidden())
|
||||
fInfoWin->Show();
|
||||
else
|
||||
fInfoWin->Activate();
|
||||
fInfoWin->Unlock();
|
||||
}
|
||||
|
||||
BMessenger msgr(fInfoWin);
|
||||
BMessage m(M_UPDATE_INFO);
|
||||
m.AddInt32("which", INFO_ALL);
|
||||
@ -599,6 +674,27 @@ MainWin::ShowFileInfo()
|
||||
msgr.SendMessage(B_WINDOW_ACTIVATED);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWin::ShowPlaylistWindow()
|
||||
{
|
||||
if (!fPlaylistWindow) {
|
||||
fPlaylistWindow = new PlaylistWindow(BRect(150, 150, 400, 500),
|
||||
fPlaylist);
|
||||
fPlaylistWindow->Show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (fPlaylistWindow->Lock()) {
|
||||
if (fPlaylistWindow->IsHidden())
|
||||
fPlaylistWindow->Show();
|
||||
else
|
||||
fPlaylistWindow->Activate();
|
||||
fPlaylistWindow->Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWin::MaybeUpdateFileInfo(uint32 which)
|
||||
{
|
||||
@ -776,29 +872,110 @@ MainWin::ToggleKeepAspectRatio()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWin::UpdateControlsEnabledStatus()
|
||||
{
|
||||
uint32 enabledButtons = 0;
|
||||
if (fHasVideo || fHasAudio) {
|
||||
enabledButtons |= PLAYBACK_ENABLED | SEEK_ENABLED
|
||||
| SEEK_BACK_ENABLED | SEEK_FORWARD_ENABLED;
|
||||
}
|
||||
if (fHasAudio)
|
||||
enabledButtons |= VOLUME_ENABLED;
|
||||
|
||||
bool canSkipPrevious, canSkipNext;
|
||||
fPlaylist->GetSkipInfo(&canSkipPrevious, &canSkipNext);
|
||||
if (canSkipPrevious)
|
||||
enabledButtons |= SKIP_BACK_ENABLED;
|
||||
if (canSkipNext)
|
||||
enabledButtons |= SKIP_FORWARD_ENABLED;
|
||||
|
||||
fControls->SetEnabled(enabledButtons);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWin::_UpdatePlaylistMenu()
|
||||
{
|
||||
fPlaylistMenu->RemoveItems(0, fPlaylistMenu->CountItems(), true);
|
||||
|
||||
// TODO: lock fPlaylist
|
||||
|
||||
int32 count = fPlaylist->CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
entry_ref ref;
|
||||
if (fPlaylist->GetRefAt(i, &ref) < B_OK)
|
||||
continue;
|
||||
_AddPlaylistItem(ref, i);
|
||||
}
|
||||
fPlaylistMenu->SetTargetForItems(this);
|
||||
|
||||
_MarkPlaylistItem(fPlaylist->CurrentRefIndex());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWin::_AddPlaylistItem(const entry_ref& ref, int32 index)
|
||||
{
|
||||
BMessage* message = new BMessage(M_SET_PLAYLIST_POSITION);
|
||||
message->AddInt32("index", index);
|
||||
BMenuItem* item = new BMenuItem(ref.name, message);
|
||||
fPlaylistMenu->AddItem(item, index);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWin::_RemovePlaylistItem(int32 index)
|
||||
{
|
||||
delete fPlaylistMenu->RemoveItem(index);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWin::_MarkPlaylistItem(int32 index)
|
||||
{
|
||||
if (BMenuItem* item = fPlaylistMenu->ItemAt(index)) {
|
||||
item->SetMarked(true);
|
||||
// ... and in case the menu is currently on screen:
|
||||
if (fPlaylistMenu->LockLooper()) {
|
||||
fPlaylistMenu->Invalidate();
|
||||
fPlaylistMenu->UnlockLooper();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
fPlaylist->MakeEmpty();
|
||||
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++) {
|
||||
BEntry entry(&ref, true);
|
||||
if (!entry.Exists() || !entry.IsFile())
|
||||
continue;
|
||||
fPlaylist->AddRef(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->Sort();
|
||||
|
||||
// open first file
|
||||
if (fPlaylist->NextRef(&ref) == B_OK)
|
||||
OpenFile(ref);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -818,7 +995,10 @@ MainWin::KeyDown(BMessage *msg)
|
||||
|
||||
switch (raw_char) {
|
||||
case B_SPACE:
|
||||
PostMessage(M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS);
|
||||
if (fController->IsPaused() || fController->IsStopped())
|
||||
fController->Play();
|
||||
else
|
||||
fController->Pause();
|
||||
return B_OK;
|
||||
|
||||
case B_ESCAPE:
|
||||
@ -928,14 +1108,22 @@ MainWin::KeyDown(BMessage *msg)
|
||||
void
|
||||
MainWin::DispatchMessage(BMessage *msg, BHandler *handler)
|
||||
{
|
||||
if ((msg->what == B_MOUSE_DOWN) && (handler == fBackground || handler == fVideoView))
|
||||
MouseDown(msg);
|
||||
if ((msg->what == B_MOUSE_MOVED) && (handler == fBackground || handler == fVideoView))
|
||||
MouseMoved(msg);
|
||||
if ((msg->what == B_MOUSE_UP) && (handler == fBackground || handler == fVideoView))
|
||||
if ((msg->what == B_MOUSE_DOWN)
|
||||
&& (handler == fBackground || handler == fVideoView
|
||||
|| handler == fControls))
|
||||
MouseDown(msg, dynamic_cast<BView*>(handler));
|
||||
|
||||
if ((msg->what == B_MOUSE_MOVED)
|
||||
&& (handler == fBackground || handler == fVideoView
|
||||
|| handler == fControls))
|
||||
MouseMoved(msg, dynamic_cast<BView*>(handler));
|
||||
|
||||
if ((msg->what == B_MOUSE_UP)
|
||||
&& (handler == fBackground || handler == fVideoView))
|
||||
MouseUp(msg);
|
||||
|
||||
if ((msg->what == B_KEY_DOWN) && (handler == fBackground || handler == fVideoView)) {
|
||||
if ((msg->what == B_KEY_DOWN)
|
||||
&& (handler == fBackground || handler == fVideoView)) {
|
||||
|
||||
// special case for PrintScreen key
|
||||
if (msg->FindInt32("key") == B_PRINT_KEY) {
|
||||
@ -969,6 +1157,75 @@ MainWin::MessageReceived(BMessage *msg)
|
||||
if (msg->HasRef("refs"))
|
||||
RefsReceived(msg);
|
||||
break;
|
||||
|
||||
// PlaylistObserver messages
|
||||
case MSG_PLAYLIST_REF_ADDED: {
|
||||
entry_ref ref;
|
||||
int32 index;
|
||||
if (msg->FindRef("refs", &ref) == B_OK
|
||||
&& msg->FindInt32("index", &index) == B_OK) {
|
||||
_AddPlaylistItem(ref, index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MSG_PLAYLIST_REF_REMOVED: {
|
||||
int32 index;
|
||||
if (msg->FindInt32("index", &index) == B_OK) {
|
||||
_RemovePlaylistItem(index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MSG_PLAYLIST_CURRENT_REF_CHANGED: {
|
||||
entry_ref ref;
|
||||
int32 index = fPlaylist->CurrentRefIndex();
|
||||
if (fPlaylist->GetRefAt(index, &ref) == B_OK) {
|
||||
printf("open ref: %s\n", ref.name);
|
||||
OpenFile(ref);
|
||||
_MarkPlaylistItem(index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// ControllerObserver messages
|
||||
case MSG_CONTROLLER_FILE_FINISHED:
|
||||
fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1);
|
||||
break;
|
||||
case MSG_CONTROLLER_FILE_CHANGED:
|
||||
// TODO: move all other GUI changes as a reaction to this notification
|
||||
// _UpdatePlaylistMenu();
|
||||
break;
|
||||
case MSG_CONTROLLER_VIDEO_TRACK_CHANGED: {
|
||||
int32 index;
|
||||
if (msg->FindInt32("index", &index) == B_OK) {
|
||||
BMenuItem* item = fVideoTrackMenu->ItemAt(index);
|
||||
if (item)
|
||||
item->SetMarked(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MSG_CONTROLLER_AUDIO_TRACK_CHANGED: {
|
||||
int32 index;
|
||||
if (msg->FindInt32("index", &index) == B_OK) {
|
||||
BMenuItem* item = fAudioTrackMenu->ItemAt(index);
|
||||
if (item)
|
||||
item->SetMarked(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED: {
|
||||
uint32 state;
|
||||
if (msg->FindInt32("state", (int32*)&state) == B_OK)
|
||||
fControls->SetPlaybackState(state);
|
||||
break;
|
||||
}
|
||||
case MSG_CONTROLLER_POSITION_CHANGED: {
|
||||
float position;
|
||||
if (msg->FindFloat("position", &position) == B_OK)
|
||||
fControls->SetPosition(position);
|
||||
break;
|
||||
}
|
||||
|
||||
// menu item messages
|
||||
case M_FILE_NEWPLAYER:
|
||||
gMainApp->NewWindow();
|
||||
break;
|
||||
@ -983,6 +1240,9 @@ MainWin::MessageReceived(BMessage *msg)
|
||||
case M_FILE_INFO:
|
||||
ShowFileInfo();
|
||||
break;
|
||||
case M_FILE_PLAYLIST:
|
||||
ShowPlaylistWindow();
|
||||
break;
|
||||
case M_FILE_ABOUT:
|
||||
BAlert *alert;
|
||||
alert = new BAlert("about", NAME"\n\n Written by Marcus Overhagen","Thanks");
|
||||
@ -1176,8 +1436,39 @@ MainWin::MessageReceived(BMessage *msg)
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case M_SET_PLAYLIST_POSITION: {
|
||||
int32 index;
|
||||
if (msg->FindInt32("index", &index) == B_OK)
|
||||
fPlaylist->SetCurrentRefIndex(index);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// let BWindow handle the rest
|
||||
BWindow::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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,6 +2,7 @@
|
||||
* MainWin.h - Media Player for the Haiku Operating System
|
||||
*
|
||||
* Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
|
||||
* Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -29,11 +30,13 @@
|
||||
#include "ControllerView.h"
|
||||
#include "InfoWin.h"
|
||||
#include "VideoView.h"
|
||||
#include "Player.h"
|
||||
#include "Playlist.h"
|
||||
|
||||
class MainWin : public BWindow, public Player
|
||||
{
|
||||
class ControllerObserver;
|
||||
class PlaylistObserver;
|
||||
class PlaylistWindow;
|
||||
|
||||
class MainWin : public BWindow {
|
||||
public:
|
||||
MainWin();
|
||||
~MainWin();
|
||||
@ -45,8 +48,8 @@ public:
|
||||
void MessageReceived(BMessage *msg);
|
||||
bool QuitRequested();
|
||||
|
||||
void MouseDown(BMessage *msg);
|
||||
void MouseMoved(BMessage *msg);
|
||||
void MouseDown(BMessage *msg, BView* originalHandler);
|
||||
void MouseMoved(BMessage *msg, BView* originalHandler);
|
||||
void MouseUp(BMessage *msg);
|
||||
status_t KeyDown(BMessage *msg);
|
||||
|
||||
@ -58,9 +61,9 @@ public:
|
||||
void ResizeVideoView(int x, int y, int width, int height);
|
||||
|
||||
void ShowFileInfo();
|
||||
void ShowPlaylistWindow();
|
||||
void MaybeUpdateFileInfo(uint32 which=INFO_ALL);
|
||||
|
||||
// from Player
|
||||
void OpenFile(const entry_ref &ref);
|
||||
|
||||
void VideoFormatChange(int width, int height, float width_scale, float height_scale);
|
||||
@ -75,26 +78,38 @@ public:
|
||||
|
||||
void ShowContextMenu(const BPoint &screen_point);
|
||||
|
||||
void UpdateControlsEnabledStatus();
|
||||
void _UpdatePlaylistMenu();
|
||||
void _AddPlaylistItem(const entry_ref& ref, int32 index);
|
||||
void _RemovePlaylistItem(int32 index);
|
||||
void _MarkPlaylistItem(int32 index);
|
||||
|
||||
BMenuBar * fMenuBar;
|
||||
BView * fBackground;
|
||||
VideoView * fVideoView;
|
||||
BFilePanel * fFilePanel;
|
||||
ControllerView * fControls;
|
||||
InfoWin * fInfoWin;
|
||||
PlaylistWindow* fPlaylistWindow;
|
||||
bool fInfoWinShowing;
|
||||
|
||||
BMenu * fFileMenu;
|
||||
BMenu * fViewMenu;
|
||||
BMenu * fAudioMenu;
|
||||
BMenu * fVideoMenu;
|
||||
BMenu * fAudioTrackMenu;
|
||||
BMenu * fVideoTrackMenu;
|
||||
BMenu * fSettingsMenu;
|
||||
BMenu * fPlaylistMenu;
|
||||
BMenu * fDebugMenu;
|
||||
|
||||
bool fHasFile;
|
||||
bool fHasVideo;
|
||||
bool fHasAudio;
|
||||
|
||||
Playlist * fPlaylist;
|
||||
PlaylistObserver* fPlaylistObserver;
|
||||
Controller * fController;
|
||||
ControllerObserver* fControllerObserver;
|
||||
volatile bool fIsFullscreen;
|
||||
volatile bool fKeepAspectRatio;
|
||||
volatile bool fAlwaysOnTop;
|
||||
@ -105,6 +120,7 @@ public:
|
||||
int fSourceHeight;
|
||||
float fWidthScale;
|
||||
float fHeightScale;
|
||||
int fMenuBarWidth;
|
||||
int fMenuBarHeight;
|
||||
int fControlsHeight;
|
||||
int fControlsWidth;
|
||||
@ -112,6 +128,10 @@ public:
|
||||
bool fMouseDownTracking;
|
||||
BPoint fMouseDownMousePos;
|
||||
BPoint fMouseDownWindowPos;
|
||||
|
||||
private:
|
||||
void _AppendToPlaylist(const entry_ref& ref,
|
||||
Playlist* playlist);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
17
src/apps/mediaplayer/PlaybackState.h
Normal file
17
src/apps/mediaplayer/PlaybackState.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#ifndef PLAYBACK_STATE_H
|
||||
#define PLAYBACK_STATE_H
|
||||
|
||||
enum {
|
||||
PLAYBACK_STATE_STOPPED = 0,
|
||||
PLAYBACK_STATE_PLAYING = 1,
|
||||
PLAYBACK_STATE_PAUSED = 2,
|
||||
};
|
||||
|
||||
#endif // PLAYBACK_STATE_H
|
@ -1,10 +0,0 @@
|
||||
#ifndef __PLAYER_H
|
||||
#define __PLAYER_H
|
||||
|
||||
class Player
|
||||
{
|
||||
public:
|
||||
virtual void OpenFile(const entry_ref &ref) = 0;
|
||||
};
|
||||
|
||||
#endif
|
@ -2,6 +2,7 @@
|
||||
* Playlist.cpp - Media Player for the Haiku Operating System
|
||||
*
|
||||
* Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
|
||||
* Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -17,14 +18,31 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#include "Playlist.h"
|
||||
|
||||
#include <debugger.h>
|
||||
#include <new.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Playlist.h"
|
||||
#include <Path.h>
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// TODO: using BList for objects is bad, replace it with a template
|
||||
|
||||
Playlist::Listener::Listener() {}
|
||||
Playlist::Listener::~Listener() {}
|
||||
void Playlist::Listener::RefAdded(const entry_ref& ref, int32 index) {}
|
||||
void Playlist::Listener::RefRemoved(int32 index) {}
|
||||
void Playlist::Listener::RefsSorted() {}
|
||||
void Playlist::Listener::CurrentRefChanged(int32 newIndex) {}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
Playlist::Playlist()
|
||||
: fList()
|
||||
: fRefs()
|
||||
, fCurrentIndex(-1)
|
||||
{
|
||||
}
|
||||
@ -33,67 +51,274 @@ Playlist::Playlist()
|
||||
Playlist::~Playlist()
|
||||
{
|
||||
MakeEmpty();
|
||||
|
||||
if (fListeners.CountItems() > 0)
|
||||
debugger("Playlist::~Playlist() - there are still listeners attached!");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Playlist::MakeEmpty()
|
||||
{
|
||||
int count = fList.CountItems();
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
entry_ref *ref = (entry_ref *)fList.RemoveItem(i);
|
||||
int32 count = fRefs.CountItems();
|
||||
for (int32 i = count - 1; i >= 0; i--) {
|
||||
entry_ref* ref = (entry_ref*)fRefs.RemoveItem(i);
|
||||
_NotifyRefRemoved(i);
|
||||
delete ref;
|
||||
}
|
||||
fCurrentIndex = -1;
|
||||
SetCurrentRefIndex(-1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Playlist::CountItems()
|
||||
int32
|
||||
Playlist::CountItems() const
|
||||
{
|
||||
return fList.CountItems();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Playlist::playlist_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
return strcasecmp((*(const entry_ref **)p1)->name, (*(const entry_ref **)p2)->name);
|
||||
return fRefs.CountItems();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Playlist::Sort()
|
||||
{
|
||||
fList.SortItems(playlist_cmp);
|
||||
fRefs.SortItems(playlist_cmp);
|
||||
_NotifyRefsSorted();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Playlist::AddRef(const entry_ref &ref)
|
||||
{
|
||||
return AddRef(ref, CountItems());
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Playlist::AddRef(const entry_ref &ref, int32 index)
|
||||
{
|
||||
entry_ref* copy = new (nothrow) entry_ref(ref);
|
||||
if (!copy)
|
||||
return false;
|
||||
if (!fRefs.AddItem(copy, index)) {
|
||||
delete copy;
|
||||
return false;
|
||||
}
|
||||
_NotifyRefAdded(ref, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Playlist::AdoptPlaylist(Playlist& other)
|
||||
{
|
||||
return AdoptPlaylist(other, CountItems());
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Playlist::AdoptPlaylist(Playlist& other, int32 index)
|
||||
{
|
||||
if (&other == this)
|
||||
return false;
|
||||
// NOTE: this is not intended to merge two "equal" playlists
|
||||
// the given playlist is assumed to be a temporary "dummy"
|
||||
if (fRefs.AddList(&other.fRefs, index)) {
|
||||
// take care of the notifications
|
||||
int32 count = other.fRefs.CountItems();
|
||||
for (int32 i = index; i < index + count; i++) {
|
||||
entry_ref* ref = (entry_ref*)fRefs.ItemAtFast(i);
|
||||
_NotifyRefAdded(*ref, i);
|
||||
}
|
||||
// empty the other list, so that the entry_refs are no ours
|
||||
other.fRefs.MakeEmpty();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
entry_ref
|
||||
Playlist::RemoveRef(int32 index)
|
||||
{
|
||||
entry_ref _ref;
|
||||
entry_ref* ref = (entry_ref*)fRefs.RemoveItem(index);
|
||||
if (!ref)
|
||||
return _ref;
|
||||
_NotifyRefRemoved(index);
|
||||
_ref = *ref;
|
||||
delete ref;
|
||||
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;
|
||||
//}
|
||||
|
||||
|
||||
status_t
|
||||
Playlist::GetRefAt(int32 index, entry_ref* _ref) const
|
||||
{
|
||||
if (!_ref)
|
||||
return B_BAD_VALUE;
|
||||
entry_ref* ref = (entry_ref*)fRefs.ItemAt(index);
|
||||
if (!ref)
|
||||
return B_BAD_INDEX;
|
||||
*_ref = *ref;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
//bool
|
||||
//Playlist::HasRef(const entry_ref& ref) const
|
||||
//{
|
||||
// return IndexOf(ref) >= 0;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
//status_t
|
||||
//Playlist::NextRef(entry_ref* ref)
|
||||
//{
|
||||
// int count = fRefs.CountItems();
|
||||
// if (fCurrentIndex + 2 > count)
|
||||
// return B_ERROR;
|
||||
// *ref = *(entry_ref*)fRefs.ItemAt(++fCurrentIndex);
|
||||
// return B_OK;
|
||||
//}
|
||||
//
|
||||
//
|
||||
//status_t
|
||||
//Playlist::PrevRef(entry_ref* ref)
|
||||
//{
|
||||
// int count = fRefs.CountItems();
|
||||
// if (count == 0 || fCurrentIndex <= 0)
|
||||
// return B_ERROR;
|
||||
// *ref = *(entry_ref*)fRefs.ItemAt(--fCurrentIndex);
|
||||
// return B_OK;
|
||||
//}
|
||||
|
||||
|
||||
void
|
||||
Playlist::SetCurrentRefIndex(int32 index)
|
||||
{
|
||||
if (index == fCurrentIndex)
|
||||
return;
|
||||
|
||||
fCurrentIndex = index;
|
||||
_NotifyCurrentRefChanged(fCurrentIndex);
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
Playlist::CurrentRefIndex() const
|
||||
{
|
||||
return fCurrentIndex;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Playlist::AddRef(const entry_ref &ref)
|
||||
Playlist::GetSkipInfo(bool* canSkipPrevious, bool* canSkipNext) const
|
||||
{
|
||||
fList.AddItem(new entry_ref(ref));
|
||||
if (canSkipPrevious)
|
||||
*canSkipPrevious = fCurrentIndex > 0;
|
||||
if (canSkipNext)
|
||||
*canSkipNext = fCurrentIndex < CountItems() - 1;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Playlist::NextRef(entry_ref *ref)
|
||||
// pragma mark -
|
||||
|
||||
|
||||
bool
|
||||
Playlist::AddListener(Listener* listener)
|
||||
{
|
||||
int count = fList.CountItems();
|
||||
if (fCurrentIndex + 2 > count)
|
||||
return B_ERROR;
|
||||
*ref = *(entry_ref *)fList.ItemAt(++fCurrentIndex);
|
||||
return B_OK;
|
||||
if (listener && !fListeners.HasItem(listener))
|
||||
return fListeners.AddItem(listener);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Playlist::PrevRef(entry_ref *ref)
|
||||
void
|
||||
Playlist::RemoveListener(Listener* listener)
|
||||
{
|
||||
int count = fList.CountItems();
|
||||
if (count == 0 || fCurrentIndex <= 0)
|
||||
return B_ERROR;
|
||||
*ref = *(entry_ref *)fList.ItemAt(--fCurrentIndex);
|
||||
return B_OK;
|
||||
fListeners.RemoveItem(listener);
|
||||
}
|
||||
|
||||
|
||||
// pragma mark -
|
||||
|
||||
|
||||
int
|
||||
Playlist::playlist_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
// compare complete path
|
||||
|
||||
BEntry a(*(const entry_ref **)p1, false);
|
||||
BEntry b(*(const entry_ref **)p2, false);
|
||||
|
||||
BPath aPath(&a);
|
||||
BPath bPath(&b);
|
||||
|
||||
return strcmp(aPath.Path(), bPath.Path());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Playlist::_NotifyRefAdded(const entry_ref& ref, int32 index) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Listener* listener = (Listener*)listeners.ItemAtFast(i);
|
||||
listener->RefAdded(ref, index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Playlist::_NotifyRefRemoved(int32 index) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Listener* listener = (Listener*)listeners.ItemAtFast(i);
|
||||
listener->RefRemoved(index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Playlist::_NotifyRefsSorted() const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Listener* listener = (Listener*)listeners.ItemAtFast(i);
|
||||
listener->RefsSorted();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Playlist::_NotifyCurrentRefChanged(int32 newIndex) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Listener* listener = (Listener*)listeners.ItemAtFast(i);
|
||||
listener->CurrentRefChanged(newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
* Playlist.h - Media Player for the Haiku Operating System
|
||||
*
|
||||
* Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
|
||||
* Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -23,28 +24,71 @@
|
||||
#include <Entry.h>
|
||||
#include <List.h>
|
||||
|
||||
class Playlist
|
||||
{
|
||||
class Playlist {
|
||||
public:
|
||||
Playlist();
|
||||
~Playlist();
|
||||
class Listener {
|
||||
public:
|
||||
Listener();
|
||||
virtual ~Listener();
|
||||
|
||||
void MakeEmpty();
|
||||
int CountItems();
|
||||
virtual void RefAdded(const entry_ref& ref, int32 index);
|
||||
virtual void RefRemoved(int32 index);
|
||||
|
||||
void Sort();
|
||||
virtual void RefsSorted();
|
||||
|
||||
void AddRef(const entry_ref &ref);
|
||||
virtual void CurrentRefChanged(int32 newIndex);
|
||||
};
|
||||
|
||||
status_t NextRef(entry_ref *ref);
|
||||
status_t PrevRef(entry_ref *ref);
|
||||
public:
|
||||
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 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
|
||||
// TODO: replace with SetCurrentRef() and listener
|
||||
// status_t NextRef(entry_ref* ref);
|
||||
// status_t PrevRef(entry_ref* 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);
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
BList fList;
|
||||
int fCurrentIndex;
|
||||
BList fRefs;
|
||||
BList fListeners;
|
||||
|
||||
int32 fCurrentIndex;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
64
src/apps/mediaplayer/PlaylistObserver.cpp
Normal file
64
src/apps/mediaplayer/PlaylistObserver.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include "PlaylistObserver.h"
|
||||
|
||||
#include <Message.h>
|
||||
|
||||
|
||||
PlaylistObserver::PlaylistObserver(BHandler* target)
|
||||
: Playlist::Listener()
|
||||
, AbstractLOAdapter(target)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PlaylistObserver::~PlaylistObserver()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistObserver::RefAdded(const entry_ref& ref, int32 index)
|
||||
{
|
||||
BMessage message(MSG_PLAYLIST_REF_ADDED);
|
||||
message.AddRef("refs", &ref);
|
||||
message.AddInt32("index", index);
|
||||
|
||||
DeliverMessage(message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistObserver::RefRemoved(int32 index)
|
||||
{
|
||||
BMessage message(MSG_PLAYLIST_REF_REMOVED);
|
||||
message.AddInt32("index", index);
|
||||
|
||||
DeliverMessage(message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistObserver::RefsSorted()
|
||||
{
|
||||
BMessage message(MSG_PLAYLIST_REFS_SORTED);
|
||||
|
||||
DeliverMessage(message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistObserver::CurrentRefChanged(int32 newIndex)
|
||||
{
|
||||
BMessage message(MSG_PLAYLIST_CURRENT_REF_CHANGED);
|
||||
message.AddInt32("index", newIndex);
|
||||
|
||||
DeliverMessage(message);
|
||||
}
|
||||
|
35
src/apps/mediaplayer/PlaylistObserver.h
Normal file
35
src/apps/mediaplayer/PlaylistObserver.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#ifndef PLAYLIST_OBSERVER_H
|
||||
#define PLAYLIST_OBSERVER_H
|
||||
|
||||
#include "AbstractLOAdapter.h"
|
||||
#include "Playlist.h"
|
||||
|
||||
enum {
|
||||
MSG_PLAYLIST_REF_ADDED = 'plra',
|
||||
MSG_PLAYLIST_REF_REMOVED = 'plrr',
|
||||
MSG_PLAYLIST_REFS_SORTED = 'plrs',
|
||||
MSG_PLAYLIST_CURRENT_REF_CHANGED = 'plcc'
|
||||
};
|
||||
|
||||
class PlaylistObserver : public Playlist::Listener,
|
||||
public AbstractLOAdapter {
|
||||
public:
|
||||
PlaylistObserver(BHandler* target);
|
||||
virtual ~PlaylistObserver();
|
||||
|
||||
virtual void RefAdded(const entry_ref& ref, int32 index);
|
||||
virtual void RefRemoved(int32 index);
|
||||
|
||||
virtual void RefsSorted();
|
||||
|
||||
virtual void CurrentRefChanged(int32 newIndex);
|
||||
};
|
||||
|
||||
#endif // PLAYLIST_OBSERVER_H
|
190
src/apps/mediaplayer/PlaylistWindow.cpp
Normal file
190
src/apps/mediaplayer/PlaylistWindow.cpp
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#include "PlaylistWindow.h"
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
|
||||
// #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)
|
||||
: BWindow(frame, "Playlist", B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS)
|
||||
{
|
||||
frame = Bounds();
|
||||
frame.right -= B_V_SCROLL_BAR_WIDTH;
|
||||
PlaylistListView* listView = new PlaylistListView(frame, playlist);
|
||||
|
||||
fTopView = new BScrollView("playlist scrollview",
|
||||
listView, B_FOLLOW_ALL, 0, false, true, B_NO_BORDER);
|
||||
|
||||
AddChild(fTopView);
|
||||
}
|
||||
|
||||
|
||||
PlaylistWindow::~PlaylistWindow()
|
||||
{
|
||||
// give listeners a chance to detach themselves
|
||||
fTopView->RemoveSelf();
|
||||
delete fTopView;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PlaylistWindow::QuitRequested()
|
||||
{
|
||||
Hide();
|
||||
return false;
|
||||
}
|
||||
|
27
src/apps/mediaplayer/PlaylistWindow.h
Normal file
27
src/apps/mediaplayer/PlaylistWindow.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#ifndef PLAYLIST_WINDOW_H
|
||||
#define PLAYLIST_WINDOW_H
|
||||
|
||||
#include <Window.h>
|
||||
|
||||
class Playlist;
|
||||
|
||||
class PlaylistWindow : public BWindow {
|
||||
public:
|
||||
PlaylistWindow(BRect frame,
|
||||
Playlist* playlist);
|
||||
virtual ~PlaylistWindow();
|
||||
|
||||
virtual bool QuitRequested();
|
||||
|
||||
private:
|
||||
BView* fTopView;
|
||||
};
|
||||
|
||||
#endif // PLAYLIST_WINDOW_H
|
@ -32,11 +32,12 @@ const char* kDisabledSeekMessage = "Drop files to play";
|
||||
SeekSlider::SeekSlider(BRect frame, const char* name, BMessage* message,
|
||||
int32 minValue, int32 maxValue)
|
||||
: BControl(frame, name, NULL, message, B_FOLLOW_NONE,
|
||||
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
|
||||
fTracking(false),
|
||||
fKnobPos(_KnobPosFor(Bounds(), Value())),
|
||||
fMinValue(minValue),
|
||||
fMaxValue(maxValue)
|
||||
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE)
|
||||
, fTracking(false)
|
||||
, fLastTrackTime(0)
|
||||
, fKnobPos(_KnobPosFor(Bounds(), Value()))
|
||||
, fMinValue(minValue)
|
||||
, fMaxValue(maxValue)
|
||||
{
|
||||
BFont font(be_plain_font);
|
||||
font.SetSize(9.0);
|
||||
@ -67,26 +68,13 @@ SeekSlider::SetValue(int32 value)
|
||||
BControl::SetValueNoUpdate(value);
|
||||
#else
|
||||
BControl::SetValue(value);
|
||||
// this will Invalidate() the whole view
|
||||
#endif
|
||||
Invoke();
|
||||
|
||||
#if __HAIKU__
|
||||
int32 oldKnobPos = fKnobPos;
|
||||
fKnobPos = _KnobPosFor(Bounds(), Value());
|
||||
// invalidate
|
||||
if (oldKnobPos != fKnobPos) {
|
||||
float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
|
||||
BRect oldKnob(Bounds());
|
||||
BRect newKnob(oldKnob);
|
||||
oldKnob.left = oldKnobPos - knobWidth2;
|
||||
oldKnob.right = oldKnobPos + knobWidth2;
|
||||
newKnob.left = fKnobPos - knobWidth2;
|
||||
newKnob.right = fKnobPos + knobWidth2;
|
||||
Invalidate(oldKnob | newKnob);
|
||||
}
|
||||
#else
|
||||
fKnobPos = _KnobPosFor(Bounds(), Value());
|
||||
#endif
|
||||
_SetKnobPosition(_KnobPosFor(Bounds(), Value()));
|
||||
|
||||
fLastTrackTime = system_time();
|
||||
}
|
||||
|
||||
|
||||
@ -138,7 +126,7 @@ SeekSlider::Draw(BRect updateRect)
|
||||
float sliderStart = (r.left + knobWidth2);
|
||||
|
||||
for (int32 i = 0; i < dotCount; i++) {
|
||||
dotPos.x = sliderStart + i * 6.0 + 5.0;
|
||||
dotPos.x = sliderStart + i * 6.0;
|
||||
StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
|
||||
}
|
||||
// slider handle
|
||||
@ -298,11 +286,20 @@ SeekSlider::SetPosition(float position)
|
||||
int32 value = fMinValue + (int32)floorf((fMaxValue - fMinValue) * position + 0.5);
|
||||
if (value != Value()) {
|
||||
BControl::SetValue(value);
|
||||
|
||||
_SetKnobPosition(_KnobPosFor(Bounds(), Value()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SeekSlider::IsTracking() const
|
||||
{
|
||||
if (fTracking)
|
||||
return true;
|
||||
return system_time() - fLastTrackTime < 250000;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
@ -349,5 +346,22 @@ SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SeekSlider::_SetKnobPosition(int32 knobPos)
|
||||
{
|
||||
if (fKnobPos == knobPos)
|
||||
return;
|
||||
|
||||
float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
|
||||
BRect oldKnob(Bounds());
|
||||
BRect newKnob(oldKnob);
|
||||
oldKnob.left = fKnobPos - knobWidth2;
|
||||
oldKnob.right = fKnobPos + knobWidth2;
|
||||
|
||||
fKnobPos = knobPos;
|
||||
|
||||
newKnob.left = fKnobPos - knobWidth2;
|
||||
newKnob.right = fKnobPos + knobWidth2;
|
||||
Invalidate(oldKnob | newKnob);
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@ class SeekSlider : public BControl {
|
||||
|
||||
// SeekSlider
|
||||
void SetPosition(float position);
|
||||
bool IsTracking() const;
|
||||
|
||||
private:
|
||||
int32 _ValueFor(float x) const;
|
||||
@ -44,8 +45,11 @@ private:
|
||||
rgb_color top,
|
||||
rgb_color right,
|
||||
rgb_color bottom);
|
||||
void _SetKnobPosition(int32 knobPos);
|
||||
|
||||
|
||||
bool fTracking;
|
||||
bigtime_t fLastTrackTime;
|
||||
int32 fKnobPos;
|
||||
int32 fMinValue;
|
||||
int32 fMaxValue;
|
||||
|
@ -63,6 +63,13 @@ SoundOutput::InitCheck()
|
||||
}
|
||||
|
||||
|
||||
media_raw_audio_format
|
||||
SoundOutput::Format() const
|
||||
{
|
||||
return fSoundPlayer->Format();
|
||||
}
|
||||
|
||||
|
||||
bigtime_t
|
||||
SoundOutput::Latency()
|
||||
{
|
||||
|
@ -32,6 +32,8 @@ public:
|
||||
|
||||
status_t InitCheck();
|
||||
|
||||
media_raw_audio_format Format() const;
|
||||
|
||||
bigtime_t Latency();
|
||||
|
||||
float Volume();
|
||||
|
@ -18,8 +18,9 @@
|
||||
#include <String.h>
|
||||
|
||||
#include "ButtonBitmaps.h"
|
||||
#include "TransportButton.h"
|
||||
#include "PlaybackState.h"
|
||||
#include "SeekSlider.h"
|
||||
#include "TransportButton.h"
|
||||
#include "VolumeSlider.h"
|
||||
|
||||
enum {
|
||||
@ -51,11 +52,12 @@ enum {
|
||||
#define kPositionFactor 3000
|
||||
|
||||
// constructor
|
||||
TransportControlGroup::TransportControlGroup(BRect frame)
|
||||
TransportControlGroup::TransportControlGroup(BRect frame, bool useSkipButtons,
|
||||
bool useWindButtons)
|
||||
: BView(frame, "transport control group",
|
||||
B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
|
||||
B_WILL_DRAW | B_FRAME_EVENTS),
|
||||
fBottomControlHeight(0.0)
|
||||
B_WILL_DRAW | B_FRAME_EVENTS)
|
||||
, fBottomControlHeight(0.0)
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
@ -69,40 +71,50 @@ TransportControlGroup::TransportControlGroup(BRect frame)
|
||||
AddChild(fSeekSlider);
|
||||
|
||||
// Buttons
|
||||
// Skip Back
|
||||
frame.right = kRewindBitmapWidth - 1;
|
||||
frame.bottom = kRewindBitmapHeight - 1;
|
||||
fBottomControlHeight = kRewindBitmapHeight - 1.0;
|
||||
fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kSkipBackBitmapBits,
|
||||
kPressedSkipBackBitmapBits,
|
||||
kDisabledSkipBackBitmapBits,
|
||||
new BMessage(MSG_SKIP_BACKWARDS));
|
||||
AddChild(fSkipBack);
|
||||
if (useSkipButtons) {
|
||||
// Skip Back
|
||||
frame.right = kRewindBitmapWidth - 1;
|
||||
frame.bottom = kRewindBitmapHeight - 1;
|
||||
fBottomControlHeight = kRewindBitmapHeight - 1.0;
|
||||
fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kSkipBackBitmapBits,
|
||||
kPressedSkipBackBitmapBits,
|
||||
kDisabledSkipBackBitmapBits,
|
||||
new BMessage(MSG_SKIP_BACKWARDS));
|
||||
AddChild(fSkipBack);
|
||||
|
||||
// Skip Foward
|
||||
fSkipForward = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kSkipForwardBitmapBits,
|
||||
kPressedSkipForwardBitmapBits,
|
||||
kDisabledSkipForwardBitmapBits,
|
||||
new BMessage(MSG_SKIP_FORWARD));
|
||||
AddChild(fSkipForward);
|
||||
// Skip Foward
|
||||
fSkipForward = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kSkipForwardBitmapBits,
|
||||
kPressedSkipForwardBitmapBits,
|
||||
kDisabledSkipForwardBitmapBits,
|
||||
new BMessage(MSG_SKIP_FORWARD));
|
||||
AddChild(fSkipForward);
|
||||
} else {
|
||||
fSkipBack = NULL;
|
||||
fSkipForward = NULL;
|
||||
}
|
||||
|
||||
// Forward
|
||||
fForward = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kForwardBitmapBits,
|
||||
kPressedForwardBitmapBits,
|
||||
kDisabledForwardBitmapBits,
|
||||
new BMessage(MSG_FORWARD));
|
||||
AddChild(fForward);
|
||||
if (useWindButtons) {
|
||||
// Forward
|
||||
fForward = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kForwardBitmapBits,
|
||||
kPressedForwardBitmapBits,
|
||||
kDisabledForwardBitmapBits,
|
||||
new BMessage(MSG_FORWARD));
|
||||
AddChild(fForward);
|
||||
|
||||
// Rewind
|
||||
fRewind = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kRewindBitmapBits,
|
||||
kPressedRewindBitmapBits,
|
||||
kDisabledRewindBitmapBits,
|
||||
new BMessage(MSG_REWIND));
|
||||
AddChild(fRewind);
|
||||
// Rewind
|
||||
fRewind = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kRewindBitmapBits,
|
||||
kPressedRewindBitmapBits,
|
||||
kDisabledRewindBitmapBits,
|
||||
new BMessage(MSG_REWIND));
|
||||
AddChild(fRewind);
|
||||
} else {
|
||||
fForward = NULL;
|
||||
fRewind = NULL;
|
||||
}
|
||||
|
||||
// Play Pause
|
||||
frame.right = kPlayPauseBitmapWidth - 1;
|
||||
@ -171,10 +183,14 @@ TransportControlGroup::AttachedToWindow()
|
||||
// we are now a valid BHandler
|
||||
fSeekSlider->SetTarget(this);
|
||||
fVolumeSlider->SetTarget(this);
|
||||
fSkipBack->SetTarget(this);
|
||||
fSkipForward->SetTarget(this);
|
||||
fRewind->SetTarget(this);
|
||||
fForward->SetTarget(this);
|
||||
if (fSkipBack)
|
||||
fSkipBack->SetTarget(this);
|
||||
if (fSkipForward)
|
||||
fSkipForward->SetTarget(this);
|
||||
if (fRewind)
|
||||
fRewind->SetTarget(this);
|
||||
if (fForward)
|
||||
fForward->SetTarget(this);
|
||||
fPlayPause->SetTarget(this);
|
||||
fStop->SetTarget(this);
|
||||
fMute->SetTarget(this);
|
||||
@ -320,21 +336,26 @@ TransportControlGroup::_GainToDb(float gain)
|
||||
void
|
||||
TransportControlGroup::SetEnabled(uint32 buttons)
|
||||
{
|
||||
// if (B_OK != LockLooperWithTimeout(50000))
|
||||
if (!LockLooper())
|
||||
return;
|
||||
|
||||
fSeekSlider->SetEnabled(buttons & SEEK_ENABLED);
|
||||
|
||||
fVolumeSlider->SetEnabled(buttons & VOLUME_ENABLED);
|
||||
fMute->SetEnabled(buttons & VOLUME_ENABLED);
|
||||
|
||||
fSkipBack->SetEnabled(buttons & SKIP_BACK_ENABLED);
|
||||
fSkipForward->SetEnabled(buttons & SKIP_FORWARD_ENABLED);
|
||||
fRewind->SetEnabled(buttons & SEEK_BACK_ENABLED);
|
||||
fForward->SetEnabled(buttons & SEEK_FORWARD_ENABLED);
|
||||
if (fSkipBack)
|
||||
fSkipBack->SetEnabled(buttons & SKIP_BACK_ENABLED);
|
||||
if (fSkipForward)
|
||||
fSkipForward->SetEnabled(buttons & SKIP_FORWARD_ENABLED);
|
||||
if (fRewind)
|
||||
fRewind->SetEnabled(buttons & SEEK_BACK_ENABLED);
|
||||
if (fForward)
|
||||
fForward->SetEnabled(buttons & SEEK_FORWARD_ENABLED);
|
||||
|
||||
fPlayPause->SetEnabled(buttons & PLAYBACK_ENABLED);
|
||||
fStop->SetEnabled(buttons & PLAYBACK_ENABLED);
|
||||
|
||||
UnlockLooper();
|
||||
}
|
||||
|
||||
@ -344,9 +365,9 @@ TransportControlGroup::SetEnabled(uint32 buttons)
|
||||
void
|
||||
TransportControlGroup::SetPlaybackState(uint32 state)
|
||||
{
|
||||
// if (B_OK != LockLooperWithTimeout(50000))
|
||||
if (!LockLooper())
|
||||
return;
|
||||
|
||||
switch (state) {
|
||||
case PLAYBACK_STATE_PLAYING:
|
||||
fPlayPause->SetPlaying();
|
||||
@ -358,6 +379,7 @@ TransportControlGroup::SetPlaybackState(uint32 state)
|
||||
fPlayPause->SetStopped();
|
||||
break;
|
||||
}
|
||||
|
||||
UnlockLooper();
|
||||
}
|
||||
|
||||
@ -365,11 +387,14 @@ TransportControlGroup::SetPlaybackState(uint32 state)
|
||||
void
|
||||
TransportControlGroup::SetSkippable(bool backward, bool forward)
|
||||
{
|
||||
// if (B_OK != LockLooperWithTimeout(50000))
|
||||
if (!LockLooper())
|
||||
return;
|
||||
fSkipBack->SetEnabled(backward);
|
||||
fSkipForward->SetEnabled(forward);
|
||||
|
||||
if (fSkipBack)
|
||||
fSkipBack->SetEnabled(backward);
|
||||
if (fSkipForward)
|
||||
fSkipForward->SetEnabled(forward);
|
||||
|
||||
UnlockLooper();
|
||||
}
|
||||
|
||||
@ -379,11 +404,12 @@ TransportControlGroup::SetSkippable(bool backward, bool forward)
|
||||
void
|
||||
TransportControlGroup::SetAudioEnabled(bool enabled)
|
||||
{
|
||||
// if (B_OK != LockLooperWithTimeout(50000))
|
||||
if (!LockLooper())
|
||||
return;
|
||||
|
||||
fMute->SetEnabled(enabled);
|
||||
fVolumeSlider->SetEnabled(enabled);
|
||||
|
||||
UnlockLooper();
|
||||
}
|
||||
|
||||
@ -391,10 +417,11 @@ TransportControlGroup::SetAudioEnabled(bool enabled)
|
||||
void
|
||||
TransportControlGroup::SetMuted(bool mute)
|
||||
{
|
||||
// if (B_OK != LockLooperWithTimeout(50000))
|
||||
if (!LockLooper())
|
||||
return;
|
||||
|
||||
fVolumeSlider->SetMuted(mute);
|
||||
|
||||
UnlockLooper();
|
||||
}
|
||||
|
||||
@ -404,7 +431,10 @@ TransportControlGroup::SetVolume(float value)
|
||||
{
|
||||
if (B_OK != LockLooperWithTimeout(50000))
|
||||
return;
|
||||
fVolumeSlider->SetValue(_DbToGain(_ExponentialToLinear(_GainToDb(value))) * kVolumeFactor);
|
||||
|
||||
fVolumeSlider->SetValue(_DbToGain(_ExponentialToLinear(
|
||||
_GainToDb(value))) * kVolumeFactor);
|
||||
|
||||
UnlockLooper();
|
||||
}
|
||||
|
||||
@ -412,10 +442,10 @@ TransportControlGroup::SetVolume(float value)
|
||||
void
|
||||
TransportControlGroup::SetPosition(float value)
|
||||
{
|
||||
if (B_OK != LockLooperWithTimeout(50000))
|
||||
if (fSeekSlider->IsTracking())
|
||||
return;
|
||||
|
||||
fSeekSlider->SetPosition(value);
|
||||
UnlockLooper();
|
||||
}
|
||||
|
||||
|
||||
@ -427,12 +457,17 @@ TransportControlGroup::_LayoutControls(BRect frame) const
|
||||
{
|
||||
BRect r(frame);
|
||||
// calculate absolutly minimal width
|
||||
float minWidth = fSkipBack->Bounds().Width();
|
||||
minWidth += fRewind->Bounds().Width();
|
||||
float minWidth = 0.0;
|
||||
if (fSkipBack)
|
||||
minWidth += fSkipBack->Bounds().Width();
|
||||
if (fRewind)
|
||||
minWidth += fRewind->Bounds().Width();
|
||||
minWidth += fStop->Bounds().Width();
|
||||
minWidth += fPlayPause->Bounds().Width();
|
||||
minWidth += fForward->Bounds().Width();
|
||||
minWidth += fSkipForward->Bounds().Width();
|
||||
if (fForward)
|
||||
minWidth += fForward->Bounds().Width();
|
||||
if (fSkipForward)
|
||||
minWidth += fSkipForward->Bounds().Width();
|
||||
minWidth += fMute->Bounds().Width();
|
||||
minWidth += VOLUME_MIN_WIDTH;
|
||||
|
||||
@ -449,28 +484,37 @@ TransportControlGroup::_LayoutControls(BRect frame) const
|
||||
r.top = r.bottom + MIN_SPACE + 1.0;
|
||||
r.bottom = frame.bottom;
|
||||
// skip back
|
||||
r.right = r.left + fSkipBack->Bounds().Width();
|
||||
_LayoutControl(fSkipBack, r);
|
||||
if (fSkipBack) {
|
||||
r.right = r.left + fSkipBack->Bounds().Width();
|
||||
_LayoutControl(fSkipBack, r);
|
||||
r.left = r.right + space;
|
||||
}
|
||||
// rewind
|
||||
r.left = r.right + space;
|
||||
r.right = r.left + fRewind->Bounds().Width();
|
||||
_LayoutControl(fRewind, r);
|
||||
if (fRewind) {
|
||||
r.right = r.left + fRewind->Bounds().Width();
|
||||
_LayoutControl(fRewind, r);
|
||||
r.left = r.right + space;
|
||||
}
|
||||
// stop
|
||||
r.left = r.right + space;
|
||||
r.right = r.left + fStop->Bounds().Width();
|
||||
_LayoutControl(fStop, r);
|
||||
// play/pause
|
||||
r.left = r.right + space;
|
||||
// play/pause
|
||||
r.right = r.left + fPlayPause->Bounds().Width();
|
||||
_LayoutControl(fPlayPause, r);
|
||||
r.left = r.right + space;
|
||||
// forward
|
||||
r.left = r.right + space;
|
||||
r.right = r.left + fForward->Bounds().Width();
|
||||
_LayoutControl(fForward, r);
|
||||
if (fForward) {
|
||||
r.right = r.left + fForward->Bounds().Width();
|
||||
_LayoutControl(fForward, r);
|
||||
r.left = r.right + space;
|
||||
}
|
||||
// skip forward
|
||||
r.left = r.right + space;
|
||||
r.right = r.left + fSkipForward->Bounds().Width();
|
||||
_LayoutControl(fSkipForward, r);
|
||||
if (fSkipForward) {
|
||||
r.right = r.left + fSkipForward->Bounds().Width();
|
||||
_LayoutControl(fSkipForward, r);
|
||||
r.left = r.right + space;
|
||||
}
|
||||
// speaker icon
|
||||
r.left = r.right + space + space;
|
||||
r.right = r.left + fMute->Bounds().Width();
|
||||
@ -488,12 +532,16 @@ TransportControlGroup::_MinFrame() const
|
||||
{
|
||||
// add up width of controls along bottom (seek slider will likely adopt)
|
||||
float minWidth = 2 * BORDER_INSET;
|
||||
minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
|
||||
minWidth += fRewind->Bounds().Width() + MIN_SPACE;
|
||||
if (fSkipBack)
|
||||
minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
|
||||
if (fRewind)
|
||||
minWidth += fRewind->Bounds().Width() + MIN_SPACE;
|
||||
minWidth += fStop->Bounds().Width() + MIN_SPACE;
|
||||
minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
|
||||
minWidth += fForward->Bounds().Width() + MIN_SPACE;
|
||||
minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
|
||||
if (fForward)
|
||||
minWidth += fForward->Bounds().Width() + MIN_SPACE;
|
||||
if (fSkipForward)
|
||||
minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
|
||||
minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
|
||||
minWidth += VOLUME_MIN_WIDTH;
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
// NOTE: Based on my code in the BeOS interface for the VLC media player
|
||||
// that I did during the VLC 0.4.3 - 0.4.6 times. Code not done by me
|
||||
// that I did during the VLC 0.4.3 - 0.4.6 times. Code not written by me
|
||||
// removed. -Stephan Aßmus
|
||||
|
||||
#ifndef TRANSPORT_CONTROL_GROUP_H
|
||||
@ -20,12 +20,6 @@ class TransportButton;
|
||||
class SeekSlider;
|
||||
class VolumeSlider;
|
||||
|
||||
enum {
|
||||
PLAYBACK_STATE_PLAYING = 0,
|
||||
PLAYBACK_STATE_PAUSED,
|
||||
PLAYBACK_STATE_STOPPED,
|
||||
};
|
||||
|
||||
enum {
|
||||
SKIP_BACK_ENABLED = 1 << 0,
|
||||
SEEK_BACK_ENABLED = 1 << 1,
|
||||
@ -38,7 +32,9 @@ enum {
|
||||
|
||||
class TransportControlGroup : public BView {
|
||||
public:
|
||||
TransportControlGroup(BRect frame);
|
||||
TransportControlGroup(BRect frame,
|
||||
bool useSkipButtons = true,
|
||||
bool useWindButtons = false);
|
||||
virtual ~TransportControlGroup();
|
||||
|
||||
// BView interface
|
||||
@ -106,7 +102,6 @@ class TransportControlGroup : public BView {
|
||||
TransportButton* fStop;
|
||||
TransportButton* fMute;
|
||||
|
||||
int fCurrentStatus;
|
||||
float fBottomControlHeight;
|
||||
};
|
||||
|
||||
|
@ -161,37 +161,54 @@ VideoView::DrawFrame()
|
||||
{
|
||||
// printf("VideoView::DrawFrame\n");
|
||||
|
||||
bool want_overlay = fController->IsOverlayActive();
|
||||
if (LockLooperWithTimeout(50000) != B_OK)
|
||||
return;
|
||||
|
||||
if (!want_overlay && fOverlayActive) {
|
||||
if (LockLooperWithTimeout(50000) == B_OK) {
|
||||
ClearViewOverlay();
|
||||
UnlockLooper();
|
||||
fOverlayActive = false;
|
||||
fController->LockBitmap();
|
||||
BBitmap *bmp = fController->Bitmap();
|
||||
|
||||
if (bmp) {
|
||||
bool want_overlay = bmp->ColorSpace() == B_YCbCr422;
|
||||
|
||||
if (!want_overlay && fOverlayActive) {
|
||||
if (LockLooperWithTimeout(50000) == B_OK) {
|
||||
ClearViewOverlay();
|
||||
UnlockLooper();
|
||||
fOverlayActive = false;
|
||||
} else {
|
||||
printf("can't ClearViewOverlay, as LockLooperWithTimeout failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (want_overlay && !fOverlayActive ) {
|
||||
printf("trying to activate overlay...");
|
||||
// reserve overlay channel
|
||||
status_t ret = SetViewOverlay(bmp, bmp->Bounds(), Bounds(),
|
||||
&fOverlayKeyColor, B_FOLLOW_ALL,
|
||||
B_OVERLAY_FILTER_HORIZONTAL | B_OVERLAY_FILTER_VERTICAL);
|
||||
if (ret == B_OK) {
|
||||
printf("success\n");
|
||||
fOverlayActive = true;
|
||||
Invalidate();
|
||||
} else {
|
||||
printf("failed: %s\n", strerror(ret));
|
||||
}
|
||||
} else if (fOverlayActive) {
|
||||
// transfer overlay channel
|
||||
rgb_color overlayKey;
|
||||
SetViewOverlay(bmp, bmp->Bounds(), Bounds(), &overlayKey,
|
||||
B_FOLLOW_ALL, B_OVERLAY_TRANSFER_CHANNEL
|
||||
| B_OVERLAY_FILTER_HORIZONTAL | B_OVERLAY_FILTER_VERTICAL);
|
||||
} else {
|
||||
printf("can't ClearViewOverlay, as LockLooperWithTimeout failed\n");
|
||||
// no overlay
|
||||
DrawBitmap(bmp, Bounds());
|
||||
}
|
||||
}
|
||||
if (want_overlay && !fOverlayActive ) {
|
||||
fController->LockBitmap();
|
||||
BBitmap *bmp = fController->Bitmap();
|
||||
if (bmp && LockLooperWithTimeout(50000) == B_OK) {
|
||||
SetViewOverlay(bmp, bmp->Bounds(), Bounds(), &fOverlayKeyColor,
|
||||
B_FOLLOW_ALL,
|
||||
/*B_OVERLAY_TRANSFER_CHANNEL | */B_OVERLAY_FILTER_HORIZONTAL | B_OVERLAY_FILTER_VERTICAL );
|
||||
fOverlayActive = true;
|
||||
|
||||
Invalidate();
|
||||
UnlockLooper();
|
||||
}
|
||||
fController->UnlockBitmap();
|
||||
}
|
||||
if (!fOverlayActive) {
|
||||
if (LockLooperWithTimeout(50000) != B_OK)
|
||||
return;
|
||||
Invalidate();
|
||||
UnlockLooper();
|
||||
}
|
||||
fController->UnlockBitmap();
|
||||
|
||||
UnlockLooper();
|
||||
}
|
||||
|
||||
|
||||
|
@ -51,7 +51,7 @@ private:
|
||||
|
||||
private:
|
||||
Controller * fController;
|
||||
bool fOverlayActive;
|
||||
volatile bool fOverlayActive;
|
||||
rgb_color fOverlayKeyColor;
|
||||
};
|
||||
|
||||
|
19
src/apps/mediaplayer/supplier/AudioSupplier.cpp
Normal file
19
src/apps/mediaplayer/supplier/AudioSupplier.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#include "AudioSupplier.h"
|
||||
|
||||
|
||||
AudioSupplier::AudioSupplier()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
AudioSupplier::~AudioSupplier()
|
||||
{
|
||||
}
|
||||
|
27
src/apps/mediaplayer/supplier/AudioSupplier.h
Normal file
27
src/apps/mediaplayer/supplier/AudioSupplier.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#ifndef AUDIO_SUPPLIER_H
|
||||
#define AUDIO_SUPPLIER_H
|
||||
|
||||
#include <MediaDefs.h>
|
||||
|
||||
class AudioSupplier {
|
||||
public:
|
||||
AudioSupplier();
|
||||
virtual ~AudioSupplier();
|
||||
|
||||
virtual media_format Format() const = 0;
|
||||
virtual status_t ReadFrames(void* buffer, int64* framesRead,
|
||||
bigtime_t* performanceTime) = 0;
|
||||
virtual status_t SeekToTime(bigtime_t* performanceTime) = 0;
|
||||
|
||||
virtual bigtime_t Position() const = 0;
|
||||
virtual bigtime_t Duration() const = 0;
|
||||
};
|
||||
|
||||
#endif // AUDIO_SUPPLIER_H
|
106
src/apps/mediaplayer/supplier/MediaTrackAudioSupplier.cpp
Normal file
106
src/apps/mediaplayer/supplier/MediaTrackAudioSupplier.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#include "MediaTrackAudioSupplier.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <MediaTrack.h>
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
MediaTrackAudioSupplier::MediaTrackAudioSupplier(BMediaTrack* track)
|
||||
: AudioSupplier()
|
||||
, fMediaTrack(track)
|
||||
|
||||
, fPerformanceTime(0)
|
||||
, fDuration(0)
|
||||
{
|
||||
if (!fMediaTrack) {
|
||||
printf("MediaTrackAudioSupplier() - no media track\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fFormat.u.raw_audio = media_multi_audio_format::wildcard;
|
||||
#ifdef __HAIKU__
|
||||
fFormat.u.raw_audio.format = media_multi_audio_format::B_AUDIO_FLOAT;
|
||||
#endif
|
||||
status_t ret = fMediaTrack->DecodedFormat(&fFormat);
|
||||
if (ret < B_OK) {
|
||||
printf("MediaTrackAudioSupplier() - "
|
||||
"fMediaTrack->DecodedFormat(): %s\n", strerror(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
fDuration = fMediaTrack->Duration();
|
||||
//
|
||||
// for (bigtime_t time = 0; time < fDuration; time += 10000) {
|
||||
// bigtime_t keyFrameTime = time;
|
||||
// fMediaTrack->FindKeyFrameForTime(&keyFrameTime,
|
||||
// B_MEDIA_SEEK_CLOSEST_BACKWARD);
|
||||
// printf("audio keyframe time for time: %lld -> %lld\n", time, keyFrameTime);
|
||||
// }
|
||||
}
|
||||
|
||||
// destructor
|
||||
MediaTrackAudioSupplier::~MediaTrackAudioSupplier()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
media_format
|
||||
MediaTrackAudioSupplier::Format() const
|
||||
{
|
||||
return fFormat;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MediaTrackAudioSupplier::ReadFrames(void* buffer, int64* framesRead,
|
||||
bigtime_t* performanceTime)
|
||||
{
|
||||
if (!fMediaTrack)
|
||||
return B_NO_INIT;
|
||||
if (!buffer || !framesRead)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
media_header mediaHeader;
|
||||
status_t ret = fMediaTrack->ReadFrames(buffer, framesRead, &mediaHeader);
|
||||
|
||||
if (ret < B_OK) {
|
||||
printf("MediaTrackAudioSupplier::ReadFrame() - "
|
||||
"error while reading frames: %s\n", strerror(ret));
|
||||
} else {
|
||||
fPerformanceTime = mediaHeader.start_time;
|
||||
}
|
||||
|
||||
if (performanceTime)
|
||||
*performanceTime = fPerformanceTime;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MediaTrackAudioSupplier::SeekToTime(bigtime_t* performanceTime)
|
||||
{
|
||||
if (!fMediaTrack)
|
||||
return B_NO_INIT;
|
||||
|
||||
bigtime_t _performanceTime = *performanceTime;
|
||||
status_t ret = fMediaTrack->SeekToTime(performanceTime);
|
||||
if (ret == B_OK) {
|
||||
printf("seeked: %lld -> %lld\n", _performanceTime, *performanceTime);
|
||||
fPerformanceTime = *performanceTime;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
38
src/apps/mediaplayer/supplier/MediaTrackAudioSupplier.h
Normal file
38
src/apps/mediaplayer/supplier/MediaTrackAudioSupplier.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#ifndef MEDIA_TRACK_AUDIO_SUPPLIER_H
|
||||
#define MEDIA_TRACK_AUDIO_SUPPLIER_H
|
||||
|
||||
#include "AudioSupplier.h"
|
||||
|
||||
class BMediaTrack;
|
||||
|
||||
class MediaTrackAudioSupplier : public AudioSupplier {
|
||||
public:
|
||||
MediaTrackAudioSupplier(BMediaTrack* track);
|
||||
virtual ~MediaTrackAudioSupplier();
|
||||
|
||||
virtual media_format Format() const;
|
||||
virtual status_t ReadFrames(void* buffer, int64* framesRead,
|
||||
bigtime_t* performanceTime);
|
||||
virtual status_t SeekToTime(bigtime_t* performanceTime);
|
||||
|
||||
virtual bigtime_t Position() const
|
||||
{ return fPerformanceTime; }
|
||||
virtual bigtime_t Duration() const
|
||||
{ return fDuration; }
|
||||
private:
|
||||
BMediaTrack* fMediaTrack;
|
||||
|
||||
media_format fFormat;
|
||||
|
||||
bigtime_t fPerformanceTime;
|
||||
bigtime_t fDuration;
|
||||
};
|
||||
|
||||
#endif // MEDIA_TRACK_AUDIO_SUPPLIER_H
|
281
src/apps/mediaplayer/supplier/MediaTrackVideoSupplier.cpp
Normal file
281
src/apps/mediaplayer/supplier/MediaTrackVideoSupplier.cpp
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#include "MediaTrackVideoSupplier.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <MediaTrack.h>
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
#define DEBUG_DECODED_FRAME 0
|
||||
#if DEBUG_DECODED_FRAME
|
||||
# include <Bitmap.h>
|
||||
# include <BitmapStream.h>
|
||||
# include <File.h>
|
||||
# include <TranslatorRoster.h>
|
||||
#endif // DEBUG_DECODED_FRAME
|
||||
|
||||
static const char* string_for_color_space(color_space format);
|
||||
|
||||
|
||||
// constructor
|
||||
MediaTrackVideoSupplier::MediaTrackVideoSupplier(BMediaTrack* track,
|
||||
color_space format)
|
||||
: VideoSupplier()
|
||||
, fVideoTrack(track)
|
||||
|
||||
, fPerformanceTime(0)
|
||||
, fDuration(0)
|
||||
{
|
||||
if (!fVideoTrack) {
|
||||
printf("MediaTrackVideoSupplier() - no video track\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// get the encoded format
|
||||
memset(&fFormat, 0, sizeof(media_format));
|
||||
status_t ret = fVideoTrack->EncodedFormat(&fFormat);
|
||||
if (ret < B_OK) {
|
||||
printf("MediaTrackVideoSupplier::InitCheck() - "
|
||||
"fVideoTrack->EncodedFormat(): %s\n", strerror(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
// get ouput video frame size
|
||||
uint32 width = fFormat.u.encoded_video.output.display.line_width;
|
||||
uint32 height = fFormat.u.encoded_video.output.display.line_count;
|
||||
|
||||
// specifiy the decoded format. we derive this information from
|
||||
// the encoded format (width & height).
|
||||
memset(&fFormat, 0, sizeof(media_format));
|
||||
// fFormat.u.raw_video.last_active = height - 1;
|
||||
// fFormat.u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT;
|
||||
// fFormat.u.raw_video.pixel_width_aspect = 1;
|
||||
// fFormat.u.raw_video.pixel_height_aspect = 1;
|
||||
fFormat.u.raw_video.display.format = format;
|
||||
fFormat.u.raw_video.display.line_width = width;
|
||||
fFormat.u.raw_video.display.line_count = height;
|
||||
if (format == B_RGB32 || format == B_RGBA32)
|
||||
fFormat.u.raw_video.display.bytes_per_row = width * 4;
|
||||
else if (format == B_YCbCr422)
|
||||
fFormat.u.raw_video.display.bytes_per_row = ((width * 2 + 3) / 4) * 4;
|
||||
|
||||
ret = fVideoTrack->DecodedFormat(&fFormat);
|
||||
|
||||
if (ret < B_OK) {
|
||||
printf("MediaTrackVideoSupplier() - "
|
||||
"fVideoTrack->DecodedFormat(): %s\n", strerror(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
if (fFormat.u.raw_video.display.format != format) {
|
||||
printf("MediaTrackVideoSupplier() - "
|
||||
" codec changed colorspace of decoded format (%s -> %s)!\n"
|
||||
" this is bad for performance, since colorspace conversion\n"
|
||||
" needs to happen during playback.\n",
|
||||
string_for_color_space(format),
|
||||
string_for_color_space(fFormat.u.raw_video.display.format));
|
||||
// check if the codec forgot to adjust bytes_per_row
|
||||
uint32 minBPR;
|
||||
format = fFormat.u.raw_video.display.format;
|
||||
if (format == B_YCbCr422)
|
||||
minBPR = ((width * 2 + 3) / 4) * 4;
|
||||
else
|
||||
minBPR = width * 4;
|
||||
if (minBPR != fFormat.u.raw_video.display.bytes_per_row) {
|
||||
printf(" -> stupid codec forgot to adjust bytes_per_row!\n");
|
||||
fFormat.u.raw_video.display.bytes_per_row = minBPR;
|
||||
fVideoTrack->DecodedFormat(&fFormat);
|
||||
}
|
||||
}
|
||||
|
||||
fDuration = fVideoTrack->Duration();
|
||||
|
||||
// for (bigtime_t time = 0; time < fDuration; time += 10000) {
|
||||
// bigtime_t keyFrameTime = time;
|
||||
// fVideoTrack->FindKeyFrameForTime(&keyFrameTime,
|
||||
// B_MEDIA_SEEK_CLOSEST_BACKWARD);
|
||||
// printf("keyframe time for time: %lld -> %lld\n", time, keyFrameTime);
|
||||
// }
|
||||
}
|
||||
|
||||
// destructor
|
||||
MediaTrackVideoSupplier::~MediaTrackVideoSupplier()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
media_format
|
||||
MediaTrackVideoSupplier::Format() const
|
||||
{
|
||||
return fFormat;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MediaTrackVideoSupplier::ReadFrame(void* buffer, bigtime_t* performanceTime)
|
||||
{
|
||||
if (!fVideoTrack)
|
||||
return B_NO_INIT;
|
||||
if (!buffer)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// read a frame
|
||||
int64 frameCount = 1;
|
||||
// TODO: how does this work for interlaced video (field count > 1)?
|
||||
media_header mediaHeader;
|
||||
status_t ret = fVideoTrack->ReadFrames(buffer, &frameCount, &mediaHeader);
|
||||
|
||||
if (ret < B_OK) {
|
||||
printf("MediaTrackVideoSupplier::ReadFrame() - "
|
||||
"error while reading frame of track: %s\n", strerror(ret));
|
||||
} else {
|
||||
fPerformanceTime = mediaHeader.start_time;
|
||||
}
|
||||
|
||||
if (performanceTime)
|
||||
*performanceTime = fPerformanceTime;
|
||||
|
||||
#if DEBUG_DECODED_FRAME
|
||||
if (modifiers() & B_SHIFT_KEY) {
|
||||
BFile fileStream("/boot/home/Desktop/decoded.png", B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
|
||||
BTranslatorRoster* roster = BTranslatorRoster::Default();
|
||||
BBitmap* bitmap = new BBitmap(Bounds(), 0, ColorSpace(), BytesPerRow());
|
||||
memcpy(bitmap->Bits(), buffer, bitmap->BitsLength());
|
||||
BBitmapStream bitmapStream(bitmap);
|
||||
roster->Translate(&bitmapStream, NULL, NULL, &fileStream, B_PNG_FORMAT, 0);
|
||||
bitmapStream.DetachBitmap(&bitmap);
|
||||
delete bitmap;
|
||||
}
|
||||
#endif // DEBUG_DECODED_FRAME
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MediaTrackVideoSupplier::SeekToTime(bigtime_t* performanceTime)
|
||||
{
|
||||
if (!fVideoTrack)
|
||||
return B_NO_INIT;
|
||||
|
||||
bigtime_t _performanceTime = *performanceTime;
|
||||
status_t ret = fVideoTrack->SeekToTime(performanceTime);
|
||||
if (ret == B_OK) {
|
||||
printf("seeked: %lld -> %lld\n", _performanceTime, *performanceTime);
|
||||
fPerformanceTime = *performanceTime;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
BRect
|
||||
MediaTrackVideoSupplier::Bounds() const
|
||||
{
|
||||
return BRect(0, 0, fFormat.u.raw_video.display.line_width - 1,
|
||||
fFormat.u.raw_video.display.line_count - 1);
|
||||
}
|
||||
|
||||
|
||||
color_space
|
||||
MediaTrackVideoSupplier::ColorSpace() const
|
||||
{
|
||||
return fFormat.u.raw_video.display.format;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
MediaTrackVideoSupplier::BytesPerRow() const
|
||||
{
|
||||
return fFormat.u.raw_video.display.bytes_per_row;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
const char*
|
||||
string_for_color_space(color_space format)
|
||||
{
|
||||
const char* name = "<unkown format>";
|
||||
switch (format) {
|
||||
case B_RGB32:
|
||||
name = "B_RGB32";
|
||||
break;
|
||||
case B_RGBA32:
|
||||
name = "B_RGBA32";
|
||||
break;
|
||||
case B_RGB32_BIG:
|
||||
name = "B_RGB32_BIG";
|
||||
break;
|
||||
case B_RGBA32_BIG:
|
||||
name = "B_RGBA32_BIG";
|
||||
break;
|
||||
case B_RGB24:
|
||||
name = "B_RGB24";
|
||||
break;
|
||||
case B_RGB24_BIG:
|
||||
name = "B_RGB24_BIG";
|
||||
break;
|
||||
case B_CMAP8:
|
||||
name = "B_CMAP8";
|
||||
break;
|
||||
case B_GRAY8:
|
||||
name = "B_GRAY8";
|
||||
break;
|
||||
case B_GRAY1:
|
||||
name = "B_GRAY1";
|
||||
break;
|
||||
|
||||
// YCbCr
|
||||
case B_YCbCr422:
|
||||
name = "B_YCbCr422";
|
||||
break;
|
||||
case B_YCbCr411:
|
||||
name = "B_YCbCr411";
|
||||
break;
|
||||
case B_YCbCr444:
|
||||
name = "B_YCbCr444";
|
||||
break;
|
||||
case B_YCbCr420:
|
||||
name = "B_YCbCr420";
|
||||
break;
|
||||
|
||||
// YUV
|
||||
case B_YUV422:
|
||||
name = "B_YUV422";
|
||||
break;
|
||||
case B_YUV411:
|
||||
name = "B_YUV411";
|
||||
break;
|
||||
case B_YUV444:
|
||||
name = "B_YUV444";
|
||||
break;
|
||||
case B_YUV420:
|
||||
name = "B_YUV420";
|
||||
break;
|
||||
|
||||
case B_YUV9:
|
||||
name = "B_YUV9";
|
||||
break;
|
||||
case B_YUV12:
|
||||
name = "B_YUV12";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return name;
|
||||
}
|
44
src/apps/mediaplayer/supplier/MediaTrackVideoSupplier.h
Normal file
44
src/apps/mediaplayer/supplier/MediaTrackVideoSupplier.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#ifndef MEDIA_TRACK_VIDEO_SUPPLIER_H
|
||||
#define MEDIA_TRACK_VIDEO_SUPPLIER_H
|
||||
|
||||
#include "VideoSupplier.h"
|
||||
|
||||
class BMediaTrack;
|
||||
|
||||
class MediaTrackVideoSupplier : public VideoSupplier {
|
||||
public:
|
||||
MediaTrackVideoSupplier(BMediaTrack* track,
|
||||
color_space preferredFormat);
|
||||
virtual ~MediaTrackVideoSupplier();
|
||||
|
||||
virtual media_format Format() const;
|
||||
virtual status_t ReadFrame(void* buffer,
|
||||
bigtime_t* performanceTime);
|
||||
virtual status_t SeekToTime(bigtime_t* performanceTime);
|
||||
|
||||
virtual bigtime_t Position() const
|
||||
{ return fPerformanceTime; }
|
||||
virtual bigtime_t Duration() const
|
||||
{ return fDuration; }
|
||||
|
||||
virtual BRect Bounds() const;
|
||||
virtual color_space ColorSpace() const;
|
||||
virtual uint32 BytesPerRow() const;
|
||||
|
||||
private:
|
||||
BMediaTrack* fVideoTrack;
|
||||
|
||||
media_format fFormat;
|
||||
|
||||
bigtime_t fPerformanceTime;
|
||||
bigtime_t fDuration;
|
||||
};
|
||||
|
||||
#endif // MEDIA_TRACK_VIDEO_SUPPLIER_H
|
19
src/apps/mediaplayer/supplier/VideoSupplier.cpp
Normal file
19
src/apps/mediaplayer/supplier/VideoSupplier.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#include "VideoSupplier.h"
|
||||
|
||||
|
||||
VideoSupplier::VideoSupplier()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
VideoSupplier::~VideoSupplier()
|
||||
{
|
||||
}
|
||||
|
27
src/apps/mediaplayer/supplier/VideoSupplier.h
Normal file
27
src/apps/mediaplayer/supplier/VideoSupplier.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#ifndef VIDEO_SUPPLIER_H
|
||||
#define VIDEO_SUPPLIER_H
|
||||
|
||||
#include <MediaDefs.h>
|
||||
|
||||
class VideoSupplier {
|
||||
public:
|
||||
VideoSupplier();
|
||||
virtual ~VideoSupplier();
|
||||
|
||||
virtual media_format Format() const = 0;
|
||||
virtual status_t ReadFrame(void* buffer,
|
||||
bigtime_t* performanceTime) = 0;
|
||||
virtual status_t SeekToTime(bigtime_t* performanceTime) = 0;
|
||||
|
||||
virtual bigtime_t Position() const = 0;
|
||||
virtual bigtime_t Duration() const = 0;
|
||||
};
|
||||
|
||||
#endif // VIDEO_SUPPLIER_H
|
Loading…
Reference in New Issue
Block a user