Massive retooling of drive-watching code to reduce complexity and thus, (hopefully) bugs.
Squished the CD-exchanging bug which I thought I got last checkin. Added a minor bug which will get fixed later -- clicking on a data track will cause the track menu and the track name to disappear git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14239 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,558 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
|
||||||
This file may be used under the terms of the Be Sample Code License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <Debug.h>
|
|
||||||
#include <Entry.h>
|
|
||||||
#include <Directory.h>
|
|
||||||
#include <Path.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include "scsi.h"
|
|
||||||
#include "CDEngine.h"
|
|
||||||
#include "PlayList.h"
|
|
||||||
|
|
||||||
static PlayList sPlayList;
|
|
||||||
CDAudioDevice gCDDevice;
|
|
||||||
|
|
||||||
const bigtime_t kPulseRate = 500000;
|
|
||||||
|
|
||||||
PeriodicWatcher::PeriodicWatcher(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BHandler *
|
|
||||||
PeriodicWatcher::RecipientHandler() const
|
|
||||||
{
|
|
||||||
return engine;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PeriodicWatcher::DoPulse()
|
|
||||||
{
|
|
||||||
// control the period here
|
|
||||||
if(UpdateState())
|
|
||||||
Notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PeriodicWatcher::UpdateNow()
|
|
||||||
{
|
|
||||||
if(UpdateState())
|
|
||||||
Notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PlayState::PlayState(CDEngine *engine)
|
|
||||||
: oldState(kInit),
|
|
||||||
fEngine(engine)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
PlayState::UpdateState(void)
|
|
||||||
{
|
|
||||||
CDState state = gCDDevice.GetState();
|
|
||||||
if(state == kStopped)
|
|
||||||
{
|
|
||||||
if(fEngine->GetState() == kPlaying)
|
|
||||||
{
|
|
||||||
// this means we have come to the end of a song, but probably not
|
|
||||||
// the last song in the playlist
|
|
||||||
int16 next = sPlayList.GetNextTrack();
|
|
||||||
if(next > 0)
|
|
||||||
{
|
|
||||||
gCDDevice.Play(next);
|
|
||||||
return CurrentState(kPlaying);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int16 count = gCDDevice.CountTracks();
|
|
||||||
if(count != sPlayList.TrackCount())
|
|
||||||
sPlayList.SetTrackCount(count);
|
|
||||||
|
|
||||||
// TODO: Is this correct?
|
|
||||||
|
|
||||||
/*
|
|
||||||
int16 start = gCDDevice.GetTrack();
|
|
||||||
if(start != sPlayList.StartingTrack())
|
|
||||||
sPlayList.SetStartingTrack(start);
|
|
||||||
*/
|
|
||||||
|
|
||||||
return CurrentState(kStopped);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(state == kPlaying && fEngine->GetState() == kStopped)
|
|
||||||
{
|
|
||||||
// This happens when the CD drive is started by R5's player
|
|
||||||
// or this app is started while the drive is playing. We should
|
|
||||||
// reset the to start at the current track and finish at the
|
|
||||||
// last one and send a notification.
|
|
||||||
sPlayList.SetTrackCount(gCDDevice.CountTracks());
|
|
||||||
sPlayList.SetStartingTrack(gCDDevice.GetTrack());
|
|
||||||
return CurrentState(kPlaying);
|
|
||||||
}
|
|
||||||
|
|
||||||
return CurrentState(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
CDState
|
|
||||||
PlayState::GetState() const
|
|
||||||
{
|
|
||||||
return oldState;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
PlayState::CurrentState(CDState newState)
|
|
||||||
{
|
|
||||||
if (newState != oldState)
|
|
||||||
{
|
|
||||||
oldState = newState;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
TrackState::TrackState(void)
|
|
||||||
: currentTrack(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int32
|
|
||||||
TrackState::GetTrack() const
|
|
||||||
{
|
|
||||||
return currentTrack;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TrackState::UpdateState()
|
|
||||||
{
|
|
||||||
// It's possible that the state of the cd drive was changed by outside means
|
|
||||||
// As a result, we want to make sure this hasn't happened. If it has, then we
|
|
||||||
// need to update the playlist's position.
|
|
||||||
int16 cdTrack, count;
|
|
||||||
|
|
||||||
if(gCDDevice.GetState() == kPlaying)
|
|
||||||
{
|
|
||||||
cdTrack = gCDDevice.GetTrack();
|
|
||||||
if(cdTrack != sPlayList.GetCurrentTrack())
|
|
||||||
sPlayList.SetCurrentTrack(cdTrack);
|
|
||||||
return CurrentState(cdTrack, trackCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're not playing, just monitor the current track in the playlist
|
|
||||||
count = gCDDevice.CountTracks();
|
|
||||||
if(count>0)
|
|
||||||
{
|
|
||||||
cdTrack = sPlayList.GetCurrentTrack();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sPlayList.SetTrackCount(0);
|
|
||||||
cdTrack=-1;
|
|
||||||
}
|
|
||||||
return CurrentState(cdTrack,count);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32
|
|
||||||
TrackState::GetNumTracks() const
|
|
||||||
{
|
|
||||||
return gCDDevice.CountTracks();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TrackState::CurrentState(int32 track, int32 count)
|
|
||||||
{
|
|
||||||
if( (track != currentTrack) || (count != trackCount) )
|
|
||||||
{
|
|
||||||
currentTrack = track;
|
|
||||||
trackCount = count;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TimeState::UpdateState()
|
|
||||||
{
|
|
||||||
// check the current CD time and force a notification to
|
|
||||||
// be sent if it changed from last time
|
|
||||||
// currently only supports global time
|
|
||||||
|
|
||||||
cdaudio_time track;
|
|
||||||
cdaudio_time disc;
|
|
||||||
|
|
||||||
if(gCDDevice.GetTime(track,disc))
|
|
||||||
{
|
|
||||||
cdaudio_time ttrack;
|
|
||||||
cdaudio_time tdisc;
|
|
||||||
int16 ctrack = gCDDevice.GetTrack();
|
|
||||||
|
|
||||||
gCDDevice.GetTimeForDisc(tdisc);
|
|
||||||
gCDDevice.GetTimeForTrack(ctrack,ttrack);
|
|
||||||
|
|
||||||
return CurrentState(track,ttrack,disc,tdisc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
track.minutes = -1;
|
|
||||||
track.seconds = -1;
|
|
||||||
disc.minutes = -1;
|
|
||||||
disc.seconds = -1;
|
|
||||||
return CurrentState(disc,disc,track,track);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TimeState::CurrentState(cdaudio_time tracktime, cdaudio_time totaltracktime,
|
|
||||||
cdaudio_time disctime, cdaudio_time totaldisctime)
|
|
||||||
{
|
|
||||||
if (disctime.minutes == fDiscTime.minutes && disctime.seconds == fDiscTime.seconds)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
fDiscTime = disctime;
|
|
||||||
fTotalDiscTime = totaldisctime;
|
|
||||||
|
|
||||||
fTrackTime = tracktime;
|
|
||||||
fTotalTrackTime = totaltracktime;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TimeState::GetDiscTime(int32 &minutes, int32 &seconds) const
|
|
||||||
{
|
|
||||||
minutes = fDiscTime.minutes;
|
|
||||||
seconds = fDiscTime.seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TimeState::GetTotalDiscTime(int32 &minutes, int32 &seconds) const
|
|
||||||
{
|
|
||||||
minutes = fTotalDiscTime.minutes;
|
|
||||||
seconds = fTotalDiscTime.seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TimeState::GetTrackTime(int32 &minutes, int32 &seconds) const
|
|
||||||
{
|
|
||||||
minutes = fTrackTime.minutes;
|
|
||||||
seconds = fTrackTime.seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TimeState::GetTotalTrackTime(int32 &minutes, int32 &seconds) const
|
|
||||||
{
|
|
||||||
minutes = fTotalTrackTime.minutes;
|
|
||||||
seconds = fTotalTrackTime.seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CDContentWatcher::CDContentWatcher(void)
|
|
||||||
: cddbQuery("us.freedb.org", 888),
|
|
||||||
discID(-1)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CDContentWatcher::GetContent(BString *title, vector<BString> *tracks)
|
|
||||||
{
|
|
||||||
if(discID == -1)
|
|
||||||
{
|
|
||||||
title->SetTo("");
|
|
||||||
tracks->empty();
|
|
||||||
tracks->push_back("");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cddbQuery.GetTitles(title, tracks, 1000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CDContentWatcher::UpdateState()
|
|
||||||
{
|
|
||||||
int32 newDiscID = -1;
|
|
||||||
|
|
||||||
if (engine->PlayStateWatcher()->GetState() == kNoCD)
|
|
||||||
{
|
|
||||||
if(discID != -1)
|
|
||||||
{
|
|
||||||
discID = -1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the table of contents to see if the new one is different
|
|
||||||
// from the old one whenever there is a CD in the drive
|
|
||||||
newDiscID = gCDDevice.GetDiscID();
|
|
||||||
|
|
||||||
if (discID == newDiscID)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// We have changed CDs, so we are not ready until the CDDB lookup finishes
|
|
||||||
cddbQuery.SetToCD(gCDDevice.GetDrivePath());
|
|
||||||
|
|
||||||
// Notify when the query is ready
|
|
||||||
if(cddbQuery.Ready())
|
|
||||||
{
|
|
||||||
discID = newDiscID;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
VolumeState::VolumeState(void)
|
|
||||||
: fVolume(-1)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
VolumeState::UpdateState(void)
|
|
||||||
{
|
|
||||||
uint8 volume = gCDDevice.GetVolume();
|
|
||||||
if(fVolume == volume)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
fVolume = volume;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32
|
|
||||||
VolumeState::GetVolume(void) const
|
|
||||||
{
|
|
||||||
return fVolume;
|
|
||||||
}
|
|
||||||
|
|
||||||
CDEngine::CDEngine(void)
|
|
||||||
: BHandler("CDEngine"),
|
|
||||||
playState(this),
|
|
||||||
fEngineState(kStopped)
|
|
||||||
{
|
|
||||||
sPlayList.SetTrackCount(gCDDevice.CountTracks());
|
|
||||||
}
|
|
||||||
|
|
||||||
CDEngine::~CDEngine()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::AttachedToLooper(BLooper *looper)
|
|
||||||
{
|
|
||||||
looper->AddHandler(this);
|
|
||||||
playState.AttachedToLooper(this);
|
|
||||||
trackState.AttachedToLooper(this);
|
|
||||||
timeState.AttachedToLooper(this);
|
|
||||||
volumeState.AttachedToLooper(this);
|
|
||||||
contentWatcher.AttachedToLooper(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::Pause()
|
|
||||||
{
|
|
||||||
gCDDevice.Pause();
|
|
||||||
fEngineState = gCDDevice.GetState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::Play()
|
|
||||||
{
|
|
||||||
if(fEngineState == kPaused)
|
|
||||||
{
|
|
||||||
gCDDevice.Resume();
|
|
||||||
fEngineState = gCDDevice.GetState();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if(fEngineState == kPlaying)
|
|
||||||
{
|
|
||||||
Pause();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gCDDevice.Play(sPlayList.GetCurrentTrack());
|
|
||||||
fEngineState = gCDDevice.GetState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::Stop()
|
|
||||||
{
|
|
||||||
fEngineState = kStopped;
|
|
||||||
gCDDevice.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::Eject()
|
|
||||||
{
|
|
||||||
gCDDevice.Eject();
|
|
||||||
fEngineState = gCDDevice.GetState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::SkipOneForward()
|
|
||||||
{
|
|
||||||
int16 track = sPlayList.GetNextTrack();
|
|
||||||
|
|
||||||
if(track <= 0)
|
|
||||||
{
|
|
||||||
// force a "wrap around" when possible. This makes it
|
|
||||||
// possible for the user to be able to, for example, jump
|
|
||||||
// back to the first track from the last one with 1 button push
|
|
||||||
track = sPlayList.GetFirstTrack();
|
|
||||||
|
|
||||||
if(track <= 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CDState state = gCDDevice.GetState();
|
|
||||||
if(state == kPlaying)
|
|
||||||
gCDDevice.Play(track);
|
|
||||||
|
|
||||||
if(state == kPaused)
|
|
||||||
{
|
|
||||||
gCDDevice.Play(track);
|
|
||||||
gCDDevice.Pause();
|
|
||||||
}
|
|
||||||
trackState.UpdateNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::SkipOneBackward()
|
|
||||||
{
|
|
||||||
int16 track = sPlayList.GetPreviousTrack();
|
|
||||||
|
|
||||||
if(track <= 0)
|
|
||||||
{
|
|
||||||
// force a "wrap around" when possible. This way the user
|
|
||||||
// can search backwards to get to a later track
|
|
||||||
track = sPlayList.GetLastTrack();
|
|
||||||
|
|
||||||
if(track <= 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CDState state = gCDDevice.GetState();
|
|
||||||
|
|
||||||
if(state == kPlaying)
|
|
||||||
gCDDevice.Play(track);
|
|
||||||
|
|
||||||
if(state == kPaused)
|
|
||||||
{
|
|
||||||
gCDDevice.Play(track);
|
|
||||||
gCDDevice.Pause();
|
|
||||||
}
|
|
||||||
trackState.UpdateNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::StartSkippingBackward()
|
|
||||||
{
|
|
||||||
gCDDevice.StartRewind();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::StartSkippingForward()
|
|
||||||
{
|
|
||||||
gCDDevice.StartFastFwd();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::StopSkipping()
|
|
||||||
{
|
|
||||||
gCDDevice.StopFastFwd();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::SelectTrack(int32 trackNumber)
|
|
||||||
{
|
|
||||||
sPlayList.SetCurrentTrack(trackNumber);
|
|
||||||
if(GetState() == kPlaying)
|
|
||||||
gCDDevice.Play(trackNumber);
|
|
||||||
trackState.UpdateNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::SetVolume(uint8 value)
|
|
||||||
{
|
|
||||||
gCDDevice.SetVolume(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::ToggleShuffle(void)
|
|
||||||
{
|
|
||||||
if(sPlayList.IsShuffled())
|
|
||||||
{
|
|
||||||
// If already in random mode, we will play to the end of the cd
|
|
||||||
int16 track = sPlayList.GetCurrentTrack();
|
|
||||||
sPlayList.SetShuffle(false);
|
|
||||||
sPlayList.SetStartingTrack(track);
|
|
||||||
sPlayList.SetTrackCount(gCDDevice.CountTracks());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Not shuffled, so we will play the entire CD and randomly pick
|
|
||||||
sPlayList.SetTrackCount(gCDDevice.CountTracks());
|
|
||||||
sPlayList.SetShuffle(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CDEngine::IsShuffled(void)
|
|
||||||
{
|
|
||||||
return sPlayList.IsShuffled();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::ToggleRepeat(void)
|
|
||||||
{
|
|
||||||
if(sPlayList.IsLoop())
|
|
||||||
sPlayList.SetLoop(false);
|
|
||||||
else
|
|
||||||
sPlayList.SetLoop(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CDEngine::IsRepeated(void)
|
|
||||||
{
|
|
||||||
return sPlayList.IsLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::DoPulse()
|
|
||||||
{
|
|
||||||
// this is the CDEngine's heartbeat; Since it is a Notifier, it checks if
|
|
||||||
// any values changed since the last hearbeat and sends notices to observers
|
|
||||||
|
|
||||||
bigtime_t time = system_time();
|
|
||||||
if (time > lastPulse && time < lastPulse + kPulseRate)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// every pulse rate have all the different state watchers check the
|
|
||||||
// curent state and send notifications if anything changed
|
|
||||||
|
|
||||||
lastPulse = time;
|
|
||||||
|
|
||||||
playState.DoPulse();
|
|
||||||
trackState.DoPulse();
|
|
||||||
timeState.DoPulse();
|
|
||||||
volumeState.DoPulse();
|
|
||||||
contentWatcher.DoPulse();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::MessageReceived(BMessage *message)
|
|
||||||
{
|
|
||||||
// handle observing
|
|
||||||
if (!Notifier::HandleObservingMessages(message) &&
|
|
||||||
!CDEngineFunctorFactory::DispatchIfFunctionObject(message))
|
|
||||||
BHandler::MessageReceived(message);
|
|
||||||
}
|
|
||||||
@@ -1,232 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
|
||||||
This file may be used under the terms of the Be Sample Code License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This defines an engine that tracks the state of the CD player
|
|
||||||
// and supports the CD player control and status calls
|
|
||||||
|
|
||||||
#ifndef __CD_ENGINE__
|
|
||||||
#define __CD_ENGINE__
|
|
||||||
|
|
||||||
#include <Looper.h>
|
|
||||||
#include <String.h>
|
|
||||||
#include <View.h>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "CDAudioDevice.h"
|
|
||||||
#include "Observer.h"
|
|
||||||
#include "FunctionObjectMessage.h"
|
|
||||||
#include "CDDBSupport.h"
|
|
||||||
#include "PlayList.h"
|
|
||||||
|
|
||||||
class CDEngine;
|
|
||||||
|
|
||||||
// watcher sits somewhere were it can get pulses and makes sure
|
|
||||||
// notices get sent if state changes
|
|
||||||
class PeriodicWatcher : public Notifier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PeriodicWatcher(void);
|
|
||||||
virtual ~PeriodicWatcher() {}
|
|
||||||
|
|
||||||
void DoPulse();
|
|
||||||
void UpdateNow();
|
|
||||||
|
|
||||||
void AttachedToLooper(CDEngine *engine)
|
|
||||||
{ this->engine = engine; }
|
|
||||||
virtual BHandler *RecipientHandler() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual bool UpdateState() = 0;
|
|
||||||
CDEngine *engine;
|
|
||||||
};
|
|
||||||
|
|
||||||
// this watcher sends notices to observers that are interrested
|
|
||||||
// about play state changes
|
|
||||||
class PlayState : public PeriodicWatcher
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PlayState(CDEngine *engine);
|
|
||||||
|
|
||||||
CDState GetState() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool UpdateState();
|
|
||||||
bool CurrentState(CDState);
|
|
||||||
CDState oldState;
|
|
||||||
|
|
||||||
CDEngine *fEngine;
|
|
||||||
};
|
|
||||||
|
|
||||||
// this watcher sends notices to observers that are interested
|
|
||||||
// about changes in the current track
|
|
||||||
class TrackState : public PeriodicWatcher
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TrackState(void);
|
|
||||||
|
|
||||||
int32 GetTrack() const;
|
|
||||||
int32 GetNumTracks() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool UpdateState();
|
|
||||||
bool CurrentState(int32,int32);
|
|
||||||
int32 currentTrack;
|
|
||||||
int32 trackCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
// this watcher sends notices to observers that are interested
|
|
||||||
// about changes in the current time
|
|
||||||
class TimeState : public PeriodicWatcher
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TimeState(void) : PeriodicWatcher() { }
|
|
||||||
|
|
||||||
void GetDiscTime(int32 &minutes, int32 &seconds) const;
|
|
||||||
void GetTotalDiscTime(int32 &minutes, int32 &seconds) const;
|
|
||||||
|
|
||||||
void GetTrackTime(int32 &minutes, int32 &seconds) const;
|
|
||||||
void GetTotalTrackTime(int32 &minutes, int32 &seconds) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool UpdateState();
|
|
||||||
bool CurrentState(cdaudio_time tracktime,
|
|
||||||
cdaudio_time totaltracktime,
|
|
||||||
cdaudio_time disctime,
|
|
||||||
cdaudio_time totaldisctime);
|
|
||||||
|
|
||||||
cdaudio_time fDiscTime,
|
|
||||||
fTotalDiscTime,
|
|
||||||
fTrackTime,
|
|
||||||
fTotalTrackTime;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CDContentWatcher : public PeriodicWatcher
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CDContentWatcher(void);
|
|
||||||
|
|
||||||
bool GetContent(BString *title, vector<BString> *tracks);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool UpdateState();
|
|
||||||
|
|
||||||
CDDBQuery cddbQuery;
|
|
||||||
int32 discID;
|
|
||||||
};
|
|
||||||
|
|
||||||
// this watcher sends notices to observers that are interested
|
|
||||||
// about changes in the current volume
|
|
||||||
// currently not used yet
|
|
||||||
class VolumeState : public PeriodicWatcher
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VolumeState(void);
|
|
||||||
|
|
||||||
int32 GetVolume() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool UpdateState();
|
|
||||||
int32 fVolume;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// The CD engine defines all the different CD control calls; also,
|
|
||||||
// it hosts the different state watchers and helps them send notices
|
|
||||||
// to observers about the CD state changes
|
|
||||||
class CDEngine : public BHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CDEngine(void);
|
|
||||||
|
|
||||||
virtual ~CDEngine();
|
|
||||||
|
|
||||||
// observing support
|
|
||||||
virtual void MessageReceived(BMessage *);
|
|
||||||
void AttachedToLooper(BLooper *);
|
|
||||||
void DoPulse();
|
|
||||||
|
|
||||||
// control calls
|
|
||||||
void Play();
|
|
||||||
void Pause();
|
|
||||||
void Stop();
|
|
||||||
void Eject();
|
|
||||||
void SkipOneForward();
|
|
||||||
void SkipOneBackward();
|
|
||||||
void StartSkippingBackward();
|
|
||||||
void StartSkippingForward();
|
|
||||||
void StopSkipping();
|
|
||||||
void SelectTrack(int32);
|
|
||||||
|
|
||||||
void SetVolume(uint8 value);
|
|
||||||
|
|
||||||
void ToggleShuffle(void);
|
|
||||||
bool IsShuffled(void);
|
|
||||||
|
|
||||||
void ToggleRepeat(void);
|
|
||||||
bool IsRepeated(void);
|
|
||||||
|
|
||||||
CDState GetState(void) const { return fEngineState; }
|
|
||||||
|
|
||||||
// to find the current Track, you may call the GetTrack function
|
|
||||||
// TrackState defines
|
|
||||||
TrackState *TrackStateWatcher()
|
|
||||||
{ return &trackState; }
|
|
||||||
|
|
||||||
// to find the current play state, you may call the GetState function
|
|
||||||
// PlayState defines
|
|
||||||
PlayState *PlayStateWatcher()
|
|
||||||
{ return &playState; }
|
|
||||||
|
|
||||||
// to find the current location on the CD, you may call the GetTime function
|
|
||||||
// TimeState defines
|
|
||||||
TimeState *TimeStateWatcher()
|
|
||||||
{ return &timeState; }
|
|
||||||
|
|
||||||
CDContentWatcher *ContentWatcher()
|
|
||||||
{ return &contentWatcher; }
|
|
||||||
|
|
||||||
// to find the current location on the CD, you may call the GetVolume function
|
|
||||||
// VolumeState defines
|
|
||||||
VolumeState *VolumeStateWatcher()
|
|
||||||
{ return &volumeState; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
PlayState playState;
|
|
||||||
TrackState trackState;
|
|
||||||
TimeState timeState;
|
|
||||||
VolumeState volumeState;
|
|
||||||
CDContentWatcher contentWatcher;
|
|
||||||
|
|
||||||
bigtime_t lastPulse;
|
|
||||||
|
|
||||||
CDState fEngineState;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// some function object glue
|
|
||||||
class CDEngineFunctorFactory : public FunctorFactoryCommon
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static BMessage *NewFunctorMessage(void (CDEngine::*func)(),
|
|
||||||
CDEngine *target)
|
|
||||||
{
|
|
||||||
PlainMemberFunctionObject<void (CDEngine::*)(),
|
|
||||||
CDEngine> tmp(func, target);
|
|
||||||
return NewMessage(&tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static BMessage *NewFunctorMessage(void (CDEngine::*func)(ulong),
|
|
||||||
CDEngine *target, ulong param)
|
|
||||||
{
|
|
||||||
SingleParamMemberFunctionObject<void (CDEngine::*)(ulong),
|
|
||||||
CDEngine, ulong> tmp(func, target, param);
|
|
||||||
return NewMessage(&tmp);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
extern CDAudioDevice gCDDevice;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
+358
-207
@@ -48,17 +48,18 @@ enum
|
|||||||
};
|
};
|
||||||
|
|
||||||
CDPlayer::CDPlayer(BRect frame, const char *name, uint32 resizeMask, uint32 flags)
|
CDPlayer::CDPlayer(BRect frame, const char *name, uint32 resizeMask, uint32 flags)
|
||||||
: BView(frame, name, resizeMask, flags | B_FRAME_EVENTS)
|
: BView(frame, name, resizeMask, flags | B_FRAME_EVENTS),
|
||||||
|
fCDQuery("freedb.freedb.org")
|
||||||
{
|
{
|
||||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
|
||||||
// TODO: Support multiple CD drives
|
fDiscID=-1;
|
||||||
engine = new CDEngine;
|
fVolume=255;
|
||||||
|
fUseTrackNames=false;
|
||||||
|
|
||||||
BuildGUI();
|
BuildGUI();
|
||||||
|
|
||||||
CDAudioDevice cd;
|
if(fCDDrive.CountDrives()<1)
|
||||||
if(cd.CountDrives()<1)
|
|
||||||
{
|
{
|
||||||
BAlert *alert = new BAlert("CDPlayer","It appears that there are no CD drives on your"
|
BAlert *alert = new BAlert("CDPlayer","It appears that there are no CD drives on your"
|
||||||
"computer or there is no system software to support one."
|
"computer or there is no system software to support one."
|
||||||
@@ -66,12 +67,15 @@ CDPlayer::CDPlayer(BRect frame, const char *name, uint32 resizeMask, uint32 flag
|
|||||||
alert->Go();
|
alert->Go();
|
||||||
be_app->PostMessage(B_QUIT_REQUESTED);
|
be_app->PostMessage(B_QUIT_REQUESTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fWindowState=fCDDrive.GetState();
|
||||||
|
fVolumeSlider->SetValue(fCDDrive.GetVolume());
|
||||||
|
WatchCDState();
|
||||||
}
|
}
|
||||||
|
|
||||||
CDPlayer::~CDPlayer()
|
CDPlayer::~CDPlayer()
|
||||||
{
|
{
|
||||||
engine->Stop();
|
fCDDrive.Stop();
|
||||||
delete engine;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDPlayer::BuildGUI(void)
|
void CDPlayer::BuildGUI(void)
|
||||||
@@ -120,7 +124,7 @@ void CDPlayer::BuildGUI(void)
|
|||||||
|
|
||||||
fCurrentTrack = new BStringView( view->Bounds(),"TrackNumber","Track:",B_FOLLOW_ALL);
|
fCurrentTrack = new BStringView( view->Bounds(),"TrackNumber","Track:",B_FOLLOW_ALL);
|
||||||
view->AddChild(fCurrentTrack);
|
view->AddChild(fCurrentTrack);
|
||||||
fCurrentTrack->SetHighColor(fPlayColor);
|
fCurrentTrack->SetHighColor(fStopColor);
|
||||||
fCurrentTrack->SetFont(be_bold_font);
|
fCurrentTrack->SetFont(be_bold_font);
|
||||||
|
|
||||||
r.OffsetBy(0, r.Height() + 5);
|
r.OffsetBy(0, r.Height() + 5);
|
||||||
@@ -147,15 +151,15 @@ void CDPlayer::BuildGUI(void)
|
|||||||
fDiscTime->SetHighColor(120,120,255);
|
fDiscTime->SetHighColor(120,120,255);
|
||||||
fDiscTime->SetFont(be_bold_font);
|
fDiscTime->SetFont(be_bold_font);
|
||||||
|
|
||||||
fVolume = new BSlider( BRect(0,0,75,30), "VolumeSlider", "Volume", new BMessage(M_SET_VOLUME),0,255);
|
fVolumeSlider = new BSlider( BRect(0,0,75,30), "VolumeSlider", "Volume", new BMessage(M_SET_VOLUME),0,255);
|
||||||
fVolume->MoveTo(5, Bounds().bottom - 10 - fVolume->Frame().Height());
|
fVolumeSlider->MoveTo(5, Bounds().bottom - 10 - fVolumeSlider->Frame().Height());
|
||||||
AddChild(fVolume);
|
AddChild(fVolumeSlider);
|
||||||
|
|
||||||
fStop = new DrawButton( BRect(0,0,1,1), "Stop", BTranslationUtils::GetBitmap(B_PNG_FORMAT,"stop_up"),
|
fStop = new DrawButton( BRect(0,0,1,1), "Stop", BTranslationUtils::GetBitmap(B_PNG_FORMAT,"stop_up"),
|
||||||
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"stop_down"), new BMessage(M_STOP),
|
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"stop_down"), new BMessage(M_STOP),
|
||||||
B_FOLLOW_BOTTOM, B_WILL_DRAW);
|
B_FOLLOW_BOTTOM, B_WILL_DRAW);
|
||||||
fStop->ResizeToPreferred();
|
fStop->ResizeToPreferred();
|
||||||
fStop->MoveTo(fVolume->Frame().right + 10, Bounds().bottom - 5 - fStop->Frame().Height());
|
fStop->MoveTo(fVolumeSlider->Frame().right + 10, Bounds().bottom - 5 - fStop->Frame().Height());
|
||||||
fStop->SetDisabled(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"stop_disabled"));
|
fStop->SetDisabled(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"stop_disabled"));
|
||||||
AddChild(fStop);
|
AddChild(fStop);
|
||||||
|
|
||||||
@@ -252,70 +256,123 @@ CDPlayer::MessageReceived(BMessage *msg)
|
|||||||
{
|
{
|
||||||
case M_SET_VOLUME:
|
case M_SET_VOLUME:
|
||||||
{
|
{
|
||||||
engine->SetVolume(fVolume->Value());
|
fCDDrive.SetVolume(fVolumeSlider->Value());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case M_STOP:
|
case M_STOP:
|
||||||
{
|
{
|
||||||
if(engine->GetState()==kPlaying)
|
fWindowState=kStopped;
|
||||||
fPlay->SetState(0);
|
fCDDrive.Stop();
|
||||||
|
|
||||||
engine->Stop();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case M_PLAY:
|
case M_PLAY:
|
||||||
{
|
{
|
||||||
// If we are currently playing, then we will be showing
|
// If we are currently playing, then we will be showing
|
||||||
// the pause images and will want to switch back to the play images
|
// the pause images and will want to switch back to the play images
|
||||||
if(engine->GetState()==kPlaying)
|
if(fWindowState==kPlaying)
|
||||||
{
|
{
|
||||||
fPlay->SetState(0);
|
fWindowState=kPaused;
|
||||||
engine->Pause();
|
fCDDrive.Pause();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(fWindowState==kPaused)
|
||||||
|
{
|
||||||
|
fWindowState=kPlaying;
|
||||||
|
fCDDrive.Resume();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fPlay->SetState(1);
|
fWindowState=kPlaying;
|
||||||
engine->Play();
|
fCDDrive.Play(fPlayList.GetCurrentTrack());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case M_SELECT_TRACK:
|
case M_SELECT_TRACK:
|
||||||
{
|
{
|
||||||
engine->SelectTrack(fTrackMenu->Value()+1);
|
fPlayList.SetCurrentTrack(fTrackMenu->Value()+1);
|
||||||
break;
|
fWindowState=kPlaying;
|
||||||
}
|
fCDDrive.Play(fPlayList.GetCurrentTrack());
|
||||||
case M_NEXT_TRACK:
|
|
||||||
{
|
|
||||||
engine->SkipOneForward();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case M_PREV_TRACK:
|
|
||||||
{
|
|
||||||
engine->SkipOneBackward();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case M_EJECT:
|
case M_EJECT:
|
||||||
{
|
{
|
||||||
engine->Eject();
|
fCDDrive.Eject();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case M_NEXT_TRACK:
|
||||||
|
{
|
||||||
|
int16 next = fPlayList.GetNextTrack();
|
||||||
|
if(next <= 0)
|
||||||
|
{
|
||||||
|
// force a "wrap around" when possible. This makes it
|
||||||
|
// possible for the user to be able to, for example, jump
|
||||||
|
// back to the first track from the last one with 1 button push
|
||||||
|
next = fPlayList.GetFirstTrack();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(next > 0)
|
||||||
|
{
|
||||||
|
CDState state = fCDDrive.GetState();
|
||||||
|
if(state == kPlaying)
|
||||||
|
fCDDrive.Play(next);
|
||||||
|
else
|
||||||
|
if(state == kPaused)
|
||||||
|
{
|
||||||
|
fCDDrive.Play(next);
|
||||||
|
fCDDrive.Pause();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fPlayList.SetCurrentTrack(next);
|
||||||
|
|
||||||
|
// Force an update for better responsiveness
|
||||||
|
WatchCDState();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case M_PREV_TRACK:
|
||||||
|
{
|
||||||
|
int16 prev = fPlayList.GetPreviousTrack();
|
||||||
|
if(prev <= 0)
|
||||||
|
{
|
||||||
|
// force a "wrap around" when possible. This makes it
|
||||||
|
// possible for the user to be able to, for example, jump
|
||||||
|
// back to the first track from the last one with 1 button push
|
||||||
|
prev = fPlayList.GetLastTrack();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(prev > 0)
|
||||||
|
{
|
||||||
|
CDState state = fCDDrive.GetState();
|
||||||
|
if(state == kPlaying)
|
||||||
|
fCDDrive.Play(prev);
|
||||||
|
else
|
||||||
|
if(state == kPaused)
|
||||||
|
{
|
||||||
|
fCDDrive.Play(prev);
|
||||||
|
fCDDrive.Pause();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fPlayList.SetCurrentTrack(prev);
|
||||||
|
|
||||||
|
// Force an update for better responsiveness
|
||||||
|
WatchCDState();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case M_FFWD:
|
case M_FFWD:
|
||||||
{
|
{
|
||||||
if(fFastFwd->Value() == B_CONTROL_ON)
|
if(fFastFwd->Value() == B_CONTROL_ON)
|
||||||
engine->StartSkippingForward();
|
fCDDrive.StartFastFwd();
|
||||||
else
|
else
|
||||||
engine->StopSkipping();
|
fCDDrive.StopFastFwd();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case M_REWIND:
|
case M_REWIND:
|
||||||
{
|
{
|
||||||
if(fRewind->Value() == B_CONTROL_ON)
|
if(fRewind->Value() == B_CONTROL_ON)
|
||||||
engine->StartSkippingBackward();
|
fCDDrive.StartRewind();
|
||||||
else
|
else
|
||||||
engine->StopSkipping();
|
fCDDrive.StopRewind();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case M_SAVE:
|
case M_SAVE:
|
||||||
@@ -326,131 +383,40 @@ CDPlayer::MessageReceived(BMessage *msg)
|
|||||||
|
|
||||||
case M_SHUFFLE:
|
case M_SHUFFLE:
|
||||||
{
|
{
|
||||||
engine->ToggleShuffle();
|
if(fPlayList.IsShuffled())
|
||||||
|
|
||||||
if(engine->IsShuffled() && fShuffle->GetState()==0)
|
|
||||||
{
|
{
|
||||||
fShuffle->SetState(1);
|
int16 track = fPlayList.GetCurrentTrack();
|
||||||
|
fPlayList.SetShuffle(false);
|
||||||
|
fPlayList.SetStartingTrack(track);
|
||||||
|
fPlayList.SetTrackCount(fCDDrive.CountTracks());
|
||||||
|
fShuffle->SetState(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(fShuffle->GetState()==1)
|
fPlayList.SetTrackCount(fCDDrive.CountTracks());
|
||||||
fShuffle->SetState(0);
|
fPlayList.SetShuffle(true);
|
||||||
|
fShuffle->SetState(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case M_REPEAT:
|
case M_REPEAT:
|
||||||
{
|
{
|
||||||
engine->ToggleRepeat();
|
if(fPlayList.IsLoop())
|
||||||
if(engine->IsRepeated() && fRepeat->GetState()==0)
|
|
||||||
{
|
{
|
||||||
fRepeat->SetState(1);
|
fPlayList.SetLoop(false);
|
||||||
|
fRepeat->SetState(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(fRepeat->GetState()==1)
|
fPlayList.SetLoop(true);
|
||||||
fRepeat->SetState(0);
|
fRepeat->SetState(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!Observer::HandleObservingMessages(msg))
|
|
||||||
{
|
|
||||||
// just support observing messages
|
|
||||||
BView::MessageReceived(msg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDPlayer::NoticeChange(Notifier *notifier)
|
|
||||||
{
|
|
||||||
PlayState *ps;
|
|
||||||
TrackState *trs;
|
|
||||||
TimeState *tms;
|
|
||||||
CDContentWatcher *ccw;
|
|
||||||
VolumeState *vs;
|
|
||||||
|
|
||||||
ps = dynamic_cast<PlayState *>(notifier);
|
|
||||||
trs = dynamic_cast<TrackState *>(notifier);
|
|
||||||
tms = dynamic_cast<TimeState *>(notifier);
|
|
||||||
ccw = dynamic_cast<CDContentWatcher *>(notifier);
|
|
||||||
vs = dynamic_cast<VolumeState *>(notifier);
|
|
||||||
|
|
||||||
if(ps)
|
|
||||||
{
|
|
||||||
AdjustButtonStates();
|
|
||||||
HandlePlayState();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if(trs)
|
|
||||||
{
|
|
||||||
|
|
||||||
if(fTrackMenu->CountItems() != engine->TrackStateWatcher()->GetNumTracks())
|
|
||||||
fTrackMenu->SetItemCount(engine->TrackStateWatcher()->GetNumTracks());
|
|
||||||
|
|
||||||
fTrackMenu->SetValue(engine->TrackStateWatcher()->GetTrack()-1);
|
|
||||||
|
|
||||||
UpdateCDInfo();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if(tms)
|
|
||||||
{
|
|
||||||
UpdateTimeInfo();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if(ccw)
|
|
||||||
{
|
|
||||||
UpdateCDInfo();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if(vs)
|
|
||||||
{
|
|
||||||
fVolume->SetValue(engine->VolumeStateWatcher()->GetVolume());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDPlayer::HandlePlayState(void)
|
|
||||||
{
|
|
||||||
switch(engine->PlayStateWatcher()->GetState())
|
|
||||||
{
|
|
||||||
case kNoCD:
|
|
||||||
{
|
|
||||||
fCurrentTrack->SetHighColor(fStopColor);
|
|
||||||
fCurrentTrack->Invalidate();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kStopped:
|
|
||||||
{
|
|
||||||
fCurrentTrack->SetHighColor(fStopColor);
|
|
||||||
fCurrentTrack->Invalidate();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kPaused:
|
|
||||||
{
|
|
||||||
fCurrentTrack->SetHighColor(fPlayColor);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kPlaying:
|
|
||||||
{
|
|
||||||
fCurrentTrack->SetHighColor(fPlayColor);
|
|
||||||
fCurrentTrack->Invalidate();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kSkipping:
|
|
||||||
{
|
|
||||||
fCurrentTrack->SetHighColor(fStopColor);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
break;
|
BView::MessageReceived(msg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -458,7 +424,7 @@ CDPlayer::HandlePlayState(void)
|
|||||||
void
|
void
|
||||||
CDPlayer::AdjustButtonStates(void)
|
CDPlayer::AdjustButtonStates(void)
|
||||||
{
|
{
|
||||||
CDState state = gCDDevice.GetState();
|
/* CDState state = gCDDevice.GetState();
|
||||||
|
|
||||||
if(state==kNoCD)
|
if(state==kNoCD)
|
||||||
{
|
{
|
||||||
@@ -485,56 +451,13 @@ CDPlayer::AdjustButtonStates(void)
|
|||||||
fPlay->SetState(1);
|
fPlay->SetState(1);
|
||||||
else
|
else
|
||||||
fPlay->SetState(0);
|
fPlay->SetState(0);
|
||||||
}
|
*/
|
||||||
|
|
||||||
void
|
|
||||||
CDPlayer::UpdateCDInfo(void)
|
|
||||||
{
|
|
||||||
BString CDName, currentTrackName;
|
|
||||||
vector<BString> trackNames;
|
|
||||||
|
|
||||||
int32 currentTrack = engine->TrackStateWatcher()->GetTrack();
|
|
||||||
|
|
||||||
bool trackresult = engine->ContentWatcher()->GetContent(&CDName,&trackNames);
|
|
||||||
|
|
||||||
if(currentTrack < 0)
|
|
||||||
{
|
|
||||||
fCDTitle->SetText("");
|
|
||||||
fCurrentTrack->SetText("");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(currentTrack == 0)
|
|
||||||
currentTrack++;
|
|
||||||
|
|
||||||
if(trackresult)
|
|
||||||
{
|
|
||||||
if(CDName.CountChars()<1)
|
|
||||||
{
|
|
||||||
// if the CD name is NULL, then it means we have no disc in the drive.
|
|
||||||
fCDTitle->SetText("");
|
|
||||||
fCurrentTrack->SetText("");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
currentTrackName << "Track " << currentTrack << ": " << trackNames[ currentTrack - 1];
|
|
||||||
fCurrentTrack->SetText(currentTrackName.String());
|
|
||||||
fCDTitle->SetText(CDName.String());
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fCDTitle->SetText("Audio CD");
|
|
||||||
currentTrackName << "Track " << currentTrack;
|
|
||||||
fCurrentTrack->SetText(currentTrackName.String());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDPlayer::UpdateTimeInfo(void)
|
CDPlayer::UpdateTimeInfo(void)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
int32 min,sec;
|
int32 min,sec;
|
||||||
char string[1024];
|
char string[1024];
|
||||||
|
|
||||||
@@ -561,21 +484,13 @@ CDPlayer::UpdateTimeInfo(void)
|
|||||||
else
|
else
|
||||||
sprintf(string,"Track --:-- / --:--");
|
sprintf(string,"Track --:-- / --:--");
|
||||||
fTrackTime->SetText(string);
|
fTrackTime->SetText(string);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDPlayer::AttachedToWindow()
|
CDPlayer::AttachedToWindow()
|
||||||
{
|
{
|
||||||
|
fVolumeSlider->SetTarget(this);
|
||||||
// start observing
|
|
||||||
engine->AttachedToLooper(Window());
|
|
||||||
StartObserving(engine->TrackStateWatcher());
|
|
||||||
StartObserving(engine->PlayStateWatcher());
|
|
||||||
StartObserving(engine->ContentWatcher());
|
|
||||||
StartObserving(engine->TimeStateWatcher());
|
|
||||||
StartObserving(engine->VolumeStateWatcher());
|
|
||||||
|
|
||||||
fVolume->SetTarget(this);
|
|
||||||
fStop->SetTarget(this);
|
fStop->SetTarget(this);
|
||||||
fPlay->SetTarget(this);
|
fPlay->SetTarget(this);
|
||||||
fNextTrack->SetTarget(this);
|
fNextTrack->SetTarget(this);
|
||||||
@@ -619,7 +534,243 @@ CDPlayer::FrameResized(float new_width, float new_height)
|
|||||||
void
|
void
|
||||||
CDPlayer::Pulse()
|
CDPlayer::Pulse()
|
||||||
{
|
{
|
||||||
engine->DoPulse();
|
WatchCDState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDPlayer::WatchCDState(void)
|
||||||
|
{
|
||||||
|
// One watcher function to rule them all
|
||||||
|
|
||||||
|
// first, watch the one setting independent of having a CD: volume
|
||||||
|
uint8 drivevolume = fCDDrive.GetVolume();
|
||||||
|
if(fVolume == drivevolume)
|
||||||
|
{
|
||||||
|
fVolume=drivevolume;
|
||||||
|
fVolumeSlider->SetValue(fVolume);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second, establish whether or not we have a CD in the drive
|
||||||
|
CDState playstate = fCDDrive.GetState();
|
||||||
|
|
||||||
|
if(playstate == kNoCD)
|
||||||
|
{
|
||||||
|
// Yes, we have no bananas!
|
||||||
|
|
||||||
|
if(fWindowState != kNoCD)
|
||||||
|
{
|
||||||
|
// We have just discovered that we have no bananas
|
||||||
|
fWindowState = kNoCD;
|
||||||
|
|
||||||
|
// Because we are changing play states, we will need to update the GUI
|
||||||
|
|
||||||
|
fDiscID=-1;
|
||||||
|
fCDTitle->SetText("No CD");
|
||||||
|
|
||||||
|
fCurrentTrack->SetText("");
|
||||||
|
fCurrentTrack->SetHighColor(fStopColor);
|
||||||
|
fCurrentTrack->Invalidate();
|
||||||
|
fTrackMenu->SetItemCount(0);
|
||||||
|
fTrackTime->SetText("Track --:-- / --:--");
|
||||||
|
fDiscTime->SetText("Disc --:-- / --:--");
|
||||||
|
fPlayList.SetTrackCount(0);
|
||||||
|
fPlayList.SetStartingTrack(1);
|
||||||
|
fPlayList.SetCurrentTrack(1);
|
||||||
|
|
||||||
|
if(fPlay->GetState()==1)
|
||||||
|
fPlay->SetState(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No change in the app's play state, so do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------
|
||||||
|
// Now otherwise handle the play state
|
||||||
|
if(playstate == kStopped)
|
||||||
|
{
|
||||||
|
if(fWindowState == kPlaying)
|
||||||
|
{
|
||||||
|
// This means that the drive finished playing the song, so get the next one
|
||||||
|
// from the list and play it
|
||||||
|
int16 next = fPlayList.GetNextTrack();
|
||||||
|
if(next > 0)
|
||||||
|
fCDDrive.Play(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fPlay->GetState()==1)
|
||||||
|
{
|
||||||
|
fPlay->SetState(0);
|
||||||
|
fCurrentTrack->SetHighColor(fStopColor);
|
||||||
|
fCurrentTrack->Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(playstate == kPlaying)
|
||||||
|
{
|
||||||
|
if(fPlay->GetState()==0)
|
||||||
|
fPlay->SetState(1);
|
||||||
|
fCurrentTrack->SetHighColor(fPlayColor);
|
||||||
|
fCurrentTrack->Invalidate();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(playstate == kPaused)
|
||||||
|
{
|
||||||
|
fPlay->SetState(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------
|
||||||
|
// If we got this far, then there must be a CD in the drive. The next order on the agenda
|
||||||
|
// is to find out which CD it is
|
||||||
|
int32 discid = fCDDrive.GetDiscID();
|
||||||
|
bool update_track_gui=false;
|
||||||
|
|
||||||
|
if(discid != fDiscID)
|
||||||
|
{
|
||||||
|
update_track_gui = true;
|
||||||
|
|
||||||
|
// Apparently the disc has changed since we last looked.
|
||||||
|
if(fCDQuery.CurrentDiscID()!=discid)
|
||||||
|
{
|
||||||
|
fCDQuery.SetToCD(fCDDrive.GetDrivePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fCDQuery.Ready())
|
||||||
|
{
|
||||||
|
fDiscID = discid;
|
||||||
|
|
||||||
|
// Note that we only update the CD title for now. We still need a track number
|
||||||
|
// in order to update the display for the selected track
|
||||||
|
if(fCDQuery.GetTitles(&fCDName, &fTrackNames, 1000000))
|
||||||
|
{
|
||||||
|
fCDTitle->SetText(fCDName.String());
|
||||||
|
fUseTrackNames=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fCDName="Audio CD";
|
||||||
|
fCDTitle->SetText("Audio CD");
|
||||||
|
fUseTrackNames=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------
|
||||||
|
// Now that we know which CD it is, update the track info
|
||||||
|
int16 drivecount = fCDDrive.CountTracks();
|
||||||
|
int16 drivetrack = fCDDrive.GetTrack();
|
||||||
|
|
||||||
|
int16 playlisttrack = fPlayList.GetCurrentTrack();
|
||||||
|
int16 playlistcount = fPlayList.TrackCount();
|
||||||
|
|
||||||
|
if(playstate == kPlaying)
|
||||||
|
{
|
||||||
|
// The main thing is that we need to make sure that the playlist and the drive's track
|
||||||
|
// stay in sync. The CD's track may have been changed by an outside source, so if
|
||||||
|
// the drive is playing, check for playlist sync.
|
||||||
|
if(playlisttrack != drivetrack)
|
||||||
|
{
|
||||||
|
playlisttrack = drivetrack;
|
||||||
|
fPlayList.SetTrackCount(drivecount);
|
||||||
|
fPlayList.SetCurrentTrack(drivetrack);
|
||||||
|
}
|
||||||
|
update_track_gui=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(playlistcount != drivecount)
|
||||||
|
{
|
||||||
|
// This happens only when CDs are changed
|
||||||
|
if(drivecount<0)
|
||||||
|
{
|
||||||
|
// There is no CD in the drive. The playlist needs to have its track
|
||||||
|
// count set to 0 and it also needs to be rewound.
|
||||||
|
fPlayList.SetStartingTrack(1);
|
||||||
|
fPlayList.SetTrackCount(0);
|
||||||
|
playlisttrack=1;
|
||||||
|
playlistcount=0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Two possible cases here: playlist is empty or playlist has a different
|
||||||
|
// number of tracks. In either case, the playlist needs to be reinitialized
|
||||||
|
// to the current track data
|
||||||
|
fPlayList.SetStartingTrack(1);
|
||||||
|
fPlayList.SetTrackCount(drivecount);
|
||||||
|
playlisttrack=fPlayList.GetCurrentTrack();
|
||||||
|
playlistcount=drivecount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// CD has not changed, so check for change in tracks
|
||||||
|
if(playlisttrack != drivetrack)
|
||||||
|
{
|
||||||
|
update_track_gui=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// do nothing. Everything is hunky-dory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(update_track_gui)
|
||||||
|
{
|
||||||
|
BString currentTrackName;
|
||||||
|
|
||||||
|
if(playlisttrack >= 0)
|
||||||
|
{
|
||||||
|
int16 whichtrack = playlisttrack;
|
||||||
|
|
||||||
|
if(whichtrack == 0)
|
||||||
|
whichtrack++;
|
||||||
|
|
||||||
|
if(fUseTrackNames && fTrackNames.size()>0)
|
||||||
|
currentTrackName << "Track " << whichtrack << ": " << fTrackNames[ whichtrack - 1];
|
||||||
|
else
|
||||||
|
currentTrackName << "Track " << whichtrack;
|
||||||
|
|
||||||
|
fCurrentTrack->SetText(currentTrackName.String());
|
||||||
|
|
||||||
|
fTrackMenu->SetItemCount(playlistcount);
|
||||||
|
fTrackMenu->SetValue(playlisttrack-1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fCurrentTrack->SetText("");
|
||||||
|
fTrackMenu->SetItemCount(0);
|
||||||
|
fTrackMenu->SetValue(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------
|
||||||
|
// Now update the time info
|
||||||
|
cdaudio_time tracktime;
|
||||||
|
cdaudio_time disctime;
|
||||||
|
cdaudio_time tracktotal;
|
||||||
|
cdaudio_time disctotal;
|
||||||
|
char timestring[1024];
|
||||||
|
|
||||||
|
if(fCDDrive.GetTime(tracktime, disctime))
|
||||||
|
{
|
||||||
|
fCDDrive.GetTimeForDisc(disctotal);
|
||||||
|
sprintf(timestring,"Disc %ld:%.2ld / %ld:%.2ld",disctime.minutes,disctime.seconds,
|
||||||
|
disctotal.minutes,disctotal.seconds);
|
||||||
|
fDiscTime->SetText(timestring);
|
||||||
|
|
||||||
|
fCDDrive.GetTimeForTrack(playlisttrack,tracktotal);
|
||||||
|
sprintf(timestring,"Track %ld:%.2ld / %ld:%.2ld",tracktime.minutes,tracktime.seconds,
|
||||||
|
tracktotal.minutes,tracktotal.seconds);
|
||||||
|
fTrackTime->SetText(timestring);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fTrackTime->SetText("Track --:-- / --:--");
|
||||||
|
fDiscTime->SetText("Disc --:-- / --:--");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CDPlayerWindow : public BWindow
|
class CDPlayerWindow : public BWindow
|
||||||
@@ -631,7 +782,7 @@ public:
|
|||||||
|
|
||||||
CDPlayerWindow::CDPlayerWindow(void)
|
CDPlayerWindow::CDPlayerWindow(void)
|
||||||
: BWindow(BRect (100, 100, 610, 200), "CD Player", B_TITLED_WINDOW, B_NOT_V_RESIZABLE |
|
: BWindow(BRect (100, 100, 610, 200), "CD Player", B_TITLED_WINDOW, B_NOT_V_RESIZABLE |
|
||||||
B_NOT_ZOOMABLE)
|
B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS)
|
||||||
{
|
{
|
||||||
float wmin,wmax,hmin,hmax;
|
float wmin,wmax,hmin,hmax;
|
||||||
|
|
||||||
|
|||||||
@@ -16,15 +16,16 @@
|
|||||||
#include <TextControl.h>
|
#include <TextControl.h>
|
||||||
#include <StringView.h>
|
#include <StringView.h>
|
||||||
|
|
||||||
#include "Observer.h"
|
|
||||||
#include "CDEngine.h"
|
|
||||||
#include "TrackMenu.h"
|
#include "TrackMenu.h"
|
||||||
|
#include "CDAudioDevice.h"
|
||||||
|
#include "CDDBSupport.h"
|
||||||
|
#include "PlayList.h"
|
||||||
|
|
||||||
class DrawButton;
|
class DrawButton;
|
||||||
class DoubleShotDrawButton;
|
class DoubleShotDrawButton;
|
||||||
class TwoStateDrawButton;
|
class TwoStateDrawButton;
|
||||||
|
|
||||||
class CDPlayer : public BView, private Observer
|
class CDPlayer : public BView
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CDPlayer(BRect frame, const char *name,
|
CDPlayer(BRect frame, const char *name,
|
||||||
@@ -40,19 +41,11 @@ public:
|
|||||||
virtual void FrameResized(float new_width, float new_height);
|
virtual void FrameResized(float new_width, float new_height);
|
||||||
virtual void MessageReceived(BMessage *);
|
virtual void MessageReceived(BMessage *);
|
||||||
|
|
||||||
// observing overrides
|
|
||||||
virtual BHandler *RecipientHandler() const { return (BHandler *)this; }
|
|
||||||
|
|
||||||
virtual void NoticeChange(Notifier *);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void HandlePlayState(void);
|
void WatchCDState(void);
|
||||||
void UpdateCDInfo(void);
|
|
||||||
void UpdateTimeInfo(void);
|
void UpdateTimeInfo(void);
|
||||||
void AdjustButtonStates(void);
|
void AdjustButtonStates(void);
|
||||||
|
|
||||||
CDEngine *engine;
|
|
||||||
|
|
||||||
DrawButton *fStop,
|
DrawButton *fStop,
|
||||||
*fNextTrack,
|
*fNextTrack,
|
||||||
*fPrevTrack,
|
*fPrevTrack,
|
||||||
@@ -67,7 +60,7 @@ private:
|
|||||||
*fRepeat,
|
*fRepeat,
|
||||||
*fPlay;
|
*fPlay;
|
||||||
|
|
||||||
BSlider *fVolume;
|
BSlider *fVolumeSlider;
|
||||||
|
|
||||||
BStringView *fCDTitle,
|
BStringView *fCDTitle,
|
||||||
*fCurrentTrack,
|
*fCurrentTrack,
|
||||||
@@ -84,6 +77,16 @@ private:
|
|||||||
|
|
||||||
rgb_color fStopColor;
|
rgb_color fStopColor;
|
||||||
rgb_color fPlayColor;
|
rgb_color fPlayColor;
|
||||||
|
|
||||||
|
CDAudioDevice fCDDrive;
|
||||||
|
PlayList fPlayList;
|
||||||
|
CDState fWindowState;
|
||||||
|
int32 fDiscID;
|
||||||
|
CDDBQuery fCDQuery;
|
||||||
|
uint8 fVolume;
|
||||||
|
bool fUseTrackNames;
|
||||||
|
vector<BString> fTrackNames;
|
||||||
|
BString fCDName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
|
||||||
This file may be used under the terms of the Be Sample Code License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This defines code for sending funciton objects in messages
|
|
||||||
|
|
||||||
#ifndef _BE_H
|
|
||||||
#include <Debug.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "FunctionObjectMessage.h"
|
|
||||||
|
|
||||||
|
|
||||||
BMessage *
|
|
||||||
FunctorFactoryCommon::NewMessage(const FunctionObject *functor)
|
|
||||||
{
|
|
||||||
BMessage *result = new BMessage('fCmG');
|
|
||||||
ASSERT(result);
|
|
||||||
|
|
||||||
long error = result->AddData("functor", B_RAW_TYPE,
|
|
||||||
functor, functor->Size());
|
|
||||||
|
|
||||||
if (error != B_NO_ERROR) {
|
|
||||||
delete result;
|
|
||||||
result = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
FunctorFactoryCommon::DispatchIfFunctionObject(BMessage *message)
|
|
||||||
{
|
|
||||||
if (message->what != 'fCmG')
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// find the functor
|
|
||||||
long size;
|
|
||||||
FunctionObject *functor;
|
|
||||||
status_t error = message->FindData("functor", B_RAW_TYPE, (const void**)&functor, &size);
|
|
||||||
if (error != B_NO_ERROR)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ASSERT(functor);
|
|
||||||
// functor found, call it
|
|
||||||
(*functor)();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
|
||||||
This file may be used under the terms of the Be Sample Code License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This defines some function object glue code
|
|
||||||
|
|
||||||
// See the Be Newsletter article about using Function Objects in the Be messaging
|
|
||||||
// model for more information
|
|
||||||
|
|
||||||
#ifndef __FUNCTION_OBJECT_MESSAGE__
|
|
||||||
#define __FUNCTION_OBJECT_MESSAGE__
|
|
||||||
|
|
||||||
#ifndef _BE_H
|
|
||||||
#include <Message.h>
|
|
||||||
#include <MessageFilter.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class FunctionObject {
|
|
||||||
public:
|
|
||||||
virtual void operator()() = 0;
|
|
||||||
virtual ~FunctionObject() {}
|
|
||||||
virtual ulong Size() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class FT, class T>
|
|
||||||
class PlainMemberFunctionObject : public FunctionObject {
|
|
||||||
public:
|
|
||||||
PlainMemberFunctionObject(FT callThis, T *onThis)
|
|
||||||
: function(callThis),
|
|
||||||
target(onThis)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
virtual ~PlainMemberFunctionObject() {}
|
|
||||||
|
|
||||||
virtual void operator()()
|
|
||||||
{ (target->*function)(); }
|
|
||||||
|
|
||||||
virtual ulong Size() const { return sizeof(*this); }
|
|
||||||
private:
|
|
||||||
FT function;
|
|
||||||
T *target;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class FT, class T, class P>
|
|
||||||
class SingleParamMemberFunctionObject : public FunctionObject {
|
|
||||||
public:
|
|
||||||
SingleParamMemberFunctionObject(FT callThis, T *onThis, P withThis)
|
|
||||||
: function(callThis),
|
|
||||||
target(onThis),
|
|
||||||
parameter(withThis)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
virtual ~SingleParamMemberFunctionObject() {}
|
|
||||||
|
|
||||||
virtual void operator()()
|
|
||||||
{ (target->*function)(parameter); }
|
|
||||||
|
|
||||||
virtual ulong Size() const { return sizeof(*this); }
|
|
||||||
private:
|
|
||||||
FT function;
|
|
||||||
T *target;
|
|
||||||
P parameter;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FunctorFactoryCommon {
|
|
||||||
public:
|
|
||||||
static bool DispatchIfFunctionObject(BMessage *);
|
|
||||||
protected:
|
|
||||||
static BMessage *NewMessage(const FunctionObject *);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -4,15 +4,11 @@ AddResources CDPlayer : CDPlayer.rdef ;
|
|||||||
App CDPlayer :
|
App CDPlayer :
|
||||||
CDAudioDevice.cpp
|
CDAudioDevice.cpp
|
||||||
CDDBSupport.cpp
|
CDDBSupport.cpp
|
||||||
CDEngine.cpp
|
|
||||||
CDPlayer.cpp
|
CDPlayer.cpp
|
||||||
DoubleShotDrawButton.cpp
|
DoubleShotDrawButton.cpp
|
||||||
DrawButton.cpp
|
DrawButton.cpp
|
||||||
FunctionObjectMessage.cpp
|
|
||||||
Observer.cpp
|
|
||||||
PlayList.cpp
|
PlayList.cpp
|
||||||
TrackMenu.cpp
|
TrackMenu.cpp
|
||||||
TwoStateDrawButton.cpp
|
TwoStateDrawButton.cpp
|
||||||
TypedList.cpp
|
|
||||||
;
|
;
|
||||||
LinkSharedOSLibs CDPlayer : be net netapi translation ;
|
LinkSharedOSLibs CDPlayer : be net netapi translation ;
|
||||||
|
|||||||
@@ -1,180 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
|
||||||
This file may be used under the terms of the Be Sample Code License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This defines the Observer and Notifier classes
|
|
||||||
|
|
||||||
#include <Message.h>
|
|
||||||
#include <Looper.h>
|
|
||||||
#include <Debug.h>
|
|
||||||
#include "Observer.h"
|
|
||||||
|
|
||||||
Observer::Observer(Notifier *target)
|
|
||||||
: observedList(4, true)
|
|
||||||
{
|
|
||||||
if (target)
|
|
||||||
StartObserving(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
Observer::~Observer()
|
|
||||||
{
|
|
||||||
StopObserving();
|
|
||||||
// tell everyone to stop sending us notices
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Observer::StartObserving(Notifier *target)
|
|
||||||
{
|
|
||||||
ASSERT(target->RecipientHandler());
|
|
||||||
ASSERT(RecipientHandler()->Looper());
|
|
||||||
|
|
||||||
// send a message to the notifier to start sending us notices
|
|
||||||
if (target->RecipientHandler()->Looper()) {
|
|
||||||
BMessage *message = new BMessage(kStartObserving);
|
|
||||||
message->AddPointer("observer", this);
|
|
||||||
message->AddPointer("observed", target);
|
|
||||||
|
|
||||||
// send the message to the looper associated with the
|
|
||||||
// notifier
|
|
||||||
target->RecipientHandler()->Looper()->PostMessage(message,
|
|
||||||
target->RecipientHandler());
|
|
||||||
NotifierListEntry *entry = new NotifierListEntry;
|
|
||||||
|
|
||||||
entry->observed = target;
|
|
||||||
entry->handler = target->RecipientHandler();
|
|
||||||
entry->looper = target->RecipientHandler()->Looper();
|
|
||||||
|
|
||||||
observedList.AddItem(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Observer::SendStopObserving(NotifierListEntry *target)
|
|
||||||
{
|
|
||||||
// send a message to the notifier to start sending us notices
|
|
||||||
if (target->looper) {
|
|
||||||
BMessage *message = new BMessage(kEndObserving);
|
|
||||||
message->AddPointer("observer", this);
|
|
||||||
message->AddPointer("observed", target->observed);
|
|
||||||
target->looper->PostMessage(message, target->handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NotifierListEntry *
|
|
||||||
StopObservingOne(NotifierListEntry *observed, void *castToObserver)
|
|
||||||
{
|
|
||||||
((Observer *)castToObserver)->SendStopObserving(observed);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Observer::StopObserving()
|
|
||||||
{
|
|
||||||
// send a message to all the notifiers to start sending us notices
|
|
||||||
observedList.EachElement(StopObservingOne, this);
|
|
||||||
observedList.MakeEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
Observer::HandleObservingMessages(const BMessage *message)
|
|
||||||
{
|
|
||||||
switch (message->what) {
|
|
||||||
case kNoticeChange:
|
|
||||||
{
|
|
||||||
// look for notice messages from notifiers
|
|
||||||
Notifier *observed = NULL;
|
|
||||||
Observer *observer = NULL;
|
|
||||||
message->FindPointer("observed", (void**)&observed);
|
|
||||||
message->FindPointer("observer", (void**)&observer);
|
|
||||||
ASSERT(observed);
|
|
||||||
ASSERT(observer);
|
|
||||||
if (!observed || !observer)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ASSERT(dynamic_cast<Observer *>(observer));
|
|
||||||
|
|
||||||
// this is a notice for us, call the NoticeChange function
|
|
||||||
observer->NoticeChange(observed);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ObserverListEntry *
|
|
||||||
NotifyOne(ObserverListEntry *observer, void *castToObserved)
|
|
||||||
{
|
|
||||||
if (observer->looper) {
|
|
||||||
BMessage *message = new BMessage(kNoticeChange);
|
|
||||||
message->AddPointer("observed", castToObserved);
|
|
||||||
message->AddPointer("observer", observer->observer);
|
|
||||||
observer->looper->PostMessage(message, observer->handler);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Notifier::Notify()
|
|
||||||
{
|
|
||||||
// send notices to all the observers
|
|
||||||
observerList.EachElement(NotifyOne, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ObserverListEntry *
|
|
||||||
FindItemWithObserver(ObserverListEntry *item, void *castToObserver)
|
|
||||||
{
|
|
||||||
if (item->observer == castToObserver)
|
|
||||||
return item;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Notifier::AddObserver(Observer *observer)
|
|
||||||
{
|
|
||||||
ObserverListEntry *item = new ObserverListEntry;
|
|
||||||
item->observer = observer;
|
|
||||||
item->handler = observer->RecipientHandler();
|
|
||||||
item->looper = observer->RecipientHandler()->Looper();
|
|
||||||
ASSERT(item->looper);
|
|
||||||
observerList.AddUnique(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Notifier::RemoveObserver(Observer *observer)
|
|
||||||
{
|
|
||||||
ObserverListEntry *item = observerList.EachElement(
|
|
||||||
FindItemWithObserver, observer);
|
|
||||||
|
|
||||||
observerList.RemoveItem(item);
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
Notifier::HandleObservingMessages(const BMessage *message)
|
|
||||||
{
|
|
||||||
switch (message->what) {
|
|
||||||
case kStartObserving:
|
|
||||||
case kEndObserving:
|
|
||||||
{
|
|
||||||
// handle messages about stopping and starting observing
|
|
||||||
Observer *observer = 0;
|
|
||||||
Notifier *observed = 0;
|
|
||||||
message->FindPointer("observer", (void**)&observer);
|
|
||||||
message->FindPointer("observed", (void**)&observed);
|
|
||||||
ASSERT(observer);
|
|
||||||
ASSERT(observed);
|
|
||||||
if (!observer || !observed)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (message->what == kStartObserving)
|
|
||||||
observed->AddObserver(observer);
|
|
||||||
else
|
|
||||||
observed->RemoveObserver(observer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
|
||||||
This file may be used under the terms of the Be Sample Code License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This defines the Observer and Notifier classes
|
|
||||||
|
|
||||||
// The idea of observing is make it easier to support a client-server
|
|
||||||
// setup where a client want's to react to changes in the server state,
|
|
||||||
// for instance a view displaying a track number needs to change whenever
|
|
||||||
// a track changes. Normally this is done by the client periodically checking
|
|
||||||
// the server from within a Pulse call or a simillar mechanism. With Observer
|
|
||||||
// and Notifier, the Observer (client) starts observing a Notifier (server)
|
|
||||||
// and then just sits back and wait to get a notice, whenever the Notifier
|
|
||||||
// changes.
|
|
||||||
|
|
||||||
#ifndef __OBSERVER__
|
|
||||||
#define __OBSERVER__
|
|
||||||
|
|
||||||
#include "TypedList.h"
|
|
||||||
#include <Handler.h>
|
|
||||||
|
|
||||||
const uint32 kNoticeChange = 'notc';
|
|
||||||
const uint32 kStartObserving = 'stob';
|
|
||||||
const uint32 kEndObserving = 'edob';
|
|
||||||
|
|
||||||
class Notifier;
|
|
||||||
|
|
||||||
class NotifierListEntry {
|
|
||||||
public:
|
|
||||||
Notifier *observed;
|
|
||||||
BHandler *handler;
|
|
||||||
BLooper *looper;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Observer {
|
|
||||||
public:
|
|
||||||
Observer(Notifier *target = NULL);
|
|
||||||
virtual ~Observer();
|
|
||||||
|
|
||||||
void StartObserving(Notifier *);
|
|
||||||
// start observing a speficied notifier
|
|
||||||
void StopObserving(Notifier *);
|
|
||||||
// stop observing a speficied notifier
|
|
||||||
void StopObserving();
|
|
||||||
// stop observing all the observed notifiers
|
|
||||||
|
|
||||||
virtual void NoticeChange(Notifier *) = 0;
|
|
||||||
// override this to get your job done, your class will get called
|
|
||||||
// whenever the Notifier changes
|
|
||||||
|
|
||||||
static bool HandleObservingMessages(const BMessage *message);
|
|
||||||
// call this from subclasses MessageReceived
|
|
||||||
virtual BHandler *RecipientHandler() const = 0;
|
|
||||||
// hook this up to return subclasses looper
|
|
||||||
private:
|
|
||||||
void SendStopObserving(NotifierListEntry *);
|
|
||||||
|
|
||||||
// keep a list of all the observed notifiers
|
|
||||||
TypedList<NotifierListEntry *> observedList;
|
|
||||||
|
|
||||||
friend NotifierListEntry *StopObservingOne(NotifierListEntry *, void *);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ObserverListEntry {
|
|
||||||
public:
|
|
||||||
Observer *observer;
|
|
||||||
BHandler *handler;
|
|
||||||
BLooper *looper;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Notifier {
|
|
||||||
public:
|
|
||||||
Notifier()
|
|
||||||
{}
|
|
||||||
virtual ~Notifier()
|
|
||||||
{}
|
|
||||||
|
|
||||||
virtual void Notify();
|
|
||||||
// call this when the notifier object changes to send notices
|
|
||||||
// to all the observers
|
|
||||||
|
|
||||||
static bool HandleObservingMessages(const BMessage *message);
|
|
||||||
// call this from subclasses MessageReceived
|
|
||||||
virtual BHandler *RecipientHandler() const = 0;
|
|
||||||
// hook this up to return subclasses looper
|
|
||||||
|
|
||||||
// keep a list of all the observers so that we can send them notices
|
|
||||||
void AddObserver(Observer *);
|
|
||||||
void RemoveObserver(Observer *);
|
|
||||||
|
|
||||||
private:
|
|
||||||
TypedList<ObserverListEntry *> observerList;
|
|
||||||
|
|
||||||
friend class Observer;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define DEBUG_PLAYLIST
|
//#define DEBUG_PLAYLIST
|
||||||
|
|
||||||
#ifdef DEBUG_PLAYLIST
|
#ifdef DEBUG_PLAYLIST
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -47,7 +47,7 @@ PlayList::SetTrackCount(const int16 &count)
|
|||||||
|
|
||||||
STRACE(("PlayList::SetTrackCount(%d)\n",count));
|
STRACE(("PlayList::SetTrackCount(%d)\n",count));
|
||||||
|
|
||||||
if(count < 0)
|
if(count <= 0)
|
||||||
{
|
{
|
||||||
fTrackCount = 0;
|
fTrackCount = 0;
|
||||||
fTrackIndex = 0;
|
fTrackIndex = 0;
|
||||||
@@ -71,13 +71,7 @@ PlayList::SetStartingTrack(const int16 &start)
|
|||||||
|
|
||||||
STRACE(("PlayList::SetStartingTrack(%d)\n",start));
|
STRACE(("PlayList::SetStartingTrack(%d)\n",start));
|
||||||
|
|
||||||
if(start >= TrackCount())
|
fStartingTrack = start;
|
||||||
fStartingTrack = TrackCount() - 1;
|
|
||||||
else
|
|
||||||
if(start < 1)
|
|
||||||
fStartingTrack = 1;
|
|
||||||
else
|
|
||||||
fStartingTrack = start;
|
|
||||||
|
|
||||||
fLocker.Unlock();
|
fLocker.Unlock();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,6 @@ void
|
|||||||
TrackMenu::MouseDown(BPoint point)
|
TrackMenu::MouseDown(BPoint point)
|
||||||
{
|
{
|
||||||
BPoint pt(point);
|
BPoint pt(point);
|
||||||
|
|
||||||
int32 saveditem = fCurrentItem;
|
int32 saveditem = fCurrentItem;
|
||||||
int32 item = ItemAt(pt);
|
int32 item = ItemAt(pt);
|
||||||
|
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
|
||||||
This file may be used under the terms of the Be Sample Code License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TypedList is a type-safe template version of BList
|
|
||||||
|
|
||||||
#include <Debug.h>
|
|
||||||
#include "TypedList.h"
|
|
||||||
|
|
||||||
void *
|
|
||||||
_PointerList::EachElement(GenericEachFunction func, void *passThru)
|
|
||||||
{
|
|
||||||
// iterates through all elements, calling func on each
|
|
||||||
// if each function returns a nonzero value, terminates early
|
|
||||||
void *result = NULL;
|
|
||||||
int32 numElements = CountItems();
|
|
||||||
|
|
||||||
for (int32 index = 0; index < numElements; index++)
|
|
||||||
if ((result = func(ItemAtFast(index), passThru)) != NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
_PointerList::_PointerList(const _PointerList &list)
|
|
||||||
: BList(list),
|
|
||||||
owning(list.owning)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
_PointerList::_PointerList(int32 itemsPerBlock = 20, bool owningList)
|
|
||||||
: BList(itemsPerBlock),
|
|
||||||
owning(owningList)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
_PointerList::~_PointerList()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
_PointerList::Owning() const
|
|
||||||
{
|
|
||||||
return owning;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
_PointerList::AddUnique(void *newItem)
|
|
||||||
{
|
|
||||||
if (IndexOf(newItem) >= 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return AddItem(newItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct OneMatchParams {
|
|
||||||
void *matchThis;
|
|
||||||
_PointerList::GenericCompareFunction matchFunction;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static void *
|
|
||||||
MatchOne(void *item, void *castToParams)
|
|
||||||
{
|
|
||||||
OneMatchParams *params = (OneMatchParams *)castToParams;
|
|
||||||
if (params->matchFunction(item, params->matchThis) == 0)
|
|
||||||
// got a match, terminate search
|
|
||||||
return item;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
_PointerList::AddUnique(void *newItem, GenericCompareFunction function)
|
|
||||||
{
|
|
||||||
OneMatchParams params;
|
|
||||||
params.matchThis = newItem;
|
|
||||||
params.matchFunction = function;
|
|
||||||
|
|
||||||
if (EachElement(MatchOne, ¶ms))
|
|
||||||
// already in list
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return AddItem(newItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,326 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
|
||||||
This file may be used under the terms of the Be Sample Code License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TypedList is a garden-variety of a type-safe template version of BList
|
|
||||||
|
|
||||||
#ifndef __LIST_TEMPLATE__
|
|
||||||
#define __LIST_TEMPLATE__
|
|
||||||
|
|
||||||
#ifndef _BE_H
|
|
||||||
#include <List.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <Debug.h>
|
|
||||||
|
|
||||||
class _PointerList : public BList {
|
|
||||||
public:
|
|
||||||
_PointerList(const _PointerList &list);
|
|
||||||
_PointerList(int32 itemsPerBlock = 20, bool owning = false);
|
|
||||||
virtual ~_PointerList();
|
|
||||||
|
|
||||||
typedef void *(* GenericEachFunction)(void *, void *);
|
|
||||||
typedef int (* GenericCompareFunction)(const void *, const void *);
|
|
||||||
void *EachElement(GenericEachFunction, void *);
|
|
||||||
|
|
||||||
bool AddUnique(void *);
|
|
||||||
// return true if item added or already in the list
|
|
||||||
bool AddUnique(void *, GenericCompareFunction);
|
|
||||||
|
|
||||||
bool Owning() const;
|
|
||||||
private:
|
|
||||||
const bool owning;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TypedList -
|
|
||||||
// to be used as a list of pointers to objects; this class should contain
|
|
||||||
// pretty much no code, just stubs that do proper type conversion
|
|
||||||
// it uses BetterEachBList for all of it's functionality and provides a
|
|
||||||
// typed interface
|
|
||||||
template<class T>
|
|
||||||
class TypedList : public _PointerList {
|
|
||||||
public:
|
|
||||||
TypedList(int32 itemsPerBlock = 20, bool owning = false);
|
|
||||||
TypedList(const TypedList&);
|
|
||||||
virtual ~TypedList();
|
|
||||||
|
|
||||||
TypedList &operator=(const TypedList &);
|
|
||||||
|
|
||||||
// iteration and sorting
|
|
||||||
typedef T (* EachFunction)(T, void *);
|
|
||||||
typedef const T (* ConstEachFunction)(const T, void *);
|
|
||||||
typedef int (* CompareFunction)(const T *, const T *);
|
|
||||||
|
|
||||||
// adding and removing
|
|
||||||
bool AddItem(T);
|
|
||||||
bool AddItem(T, int32);
|
|
||||||
bool AddList(TypedList *);
|
|
||||||
bool AddList(TypedList *, int32);
|
|
||||||
bool AddUnique(T);
|
|
||||||
bool AddUnique(T, CompareFunction);
|
|
||||||
|
|
||||||
bool RemoveItem(T);
|
|
||||||
T RemoveItem(int32);
|
|
||||||
T RemoveItemAt(int32);
|
|
||||||
// same as RemoveItem(int32), RemoveItem does not work when T is a scalar
|
|
||||||
|
|
||||||
void MakeEmpty();
|
|
||||||
|
|
||||||
// item access
|
|
||||||
T ItemAt(int32) const;
|
|
||||||
T ItemAtFast(int32) const;
|
|
||||||
// does not do an index range check
|
|
||||||
|
|
||||||
T FirstItem() const;
|
|
||||||
T LastItem() const;
|
|
||||||
|
|
||||||
T Items() const;
|
|
||||||
|
|
||||||
// misc. getters
|
|
||||||
int32 IndexOf(const T) const;
|
|
||||||
bool HasItem(const T) const;
|
|
||||||
bool IsEmpty() const;
|
|
||||||
int32 CountItems() const;
|
|
||||||
|
|
||||||
|
|
||||||
T EachElement(EachFunction, void *);
|
|
||||||
const T EachElement(ConstEachFunction, void *) const;
|
|
||||||
// Do for each are obsoleted by this list, possibly add
|
|
||||||
// them for convenience
|
|
||||||
void SortItems(CompareFunction);
|
|
||||||
bool ReplaceItem(int32 index, T item);
|
|
||||||
bool SwapItems(int32 a, int32 b);
|
|
||||||
bool MoveItem(int32 from, int32 to);
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class ParseArray;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
TypedList<T>::TypedList(int32 itemsPerBlock, bool owning)
|
|
||||||
: _PointerList(itemsPerBlock, owning)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
TypedList<T>::TypedList(const TypedList<T> &list)
|
|
||||||
: _PointerList(list)
|
|
||||||
{
|
|
||||||
ASSERT(!list.Owning());
|
|
||||||
// copying owned lists does not work yet
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
TypedList<T>::~TypedList()
|
|
||||||
{
|
|
||||||
if (Owning())
|
|
||||||
// have to nuke elements first
|
|
||||||
MakeEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
TypedList<T> &
|
|
||||||
TypedList<T>::operator=(const TypedList<T> &from)
|
|
||||||
{
|
|
||||||
ASSERT(!from.Owning());
|
|
||||||
// copying owned lists does not work yet
|
|
||||||
|
|
||||||
return (TypedList<T> &)BList::operator=(from);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool
|
|
||||||
TypedList<T>::AddItem(T item)
|
|
||||||
{
|
|
||||||
return _PointerList::AddItem(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool
|
|
||||||
TypedList<T>::AddItem(T item, int32 atIndex)
|
|
||||||
{
|
|
||||||
return _PointerList::AddItem(item, atIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool
|
|
||||||
TypedList<T>::AddList(TypedList<T> *newItems)
|
|
||||||
{
|
|
||||||
return _PointerList::AddList(newItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool
|
|
||||||
TypedList<T>::AddList(TypedList<T> *newItems, int32 atIndex)
|
|
||||||
{
|
|
||||||
return _PointerList::AddList(newItems, atIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool
|
|
||||||
TypedList<T>::AddUnique(T item)
|
|
||||||
{
|
|
||||||
return _PointerList::AddUnique(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool
|
|
||||||
TypedList<T>::AddUnique(T item, CompareFunction function)
|
|
||||||
{
|
|
||||||
return _PointerList::AddUnique(item, (GenericCompareFunction)function);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool
|
|
||||||
TypedList<T>::RemoveItem(T item)
|
|
||||||
{
|
|
||||||
bool result = _PointerList::RemoveItem(item);
|
|
||||||
|
|
||||||
if (result && Owning()) {
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T
|
|
||||||
TypedList<T>::RemoveItem(int32 index)
|
|
||||||
{
|
|
||||||
return (T)_PointerList::RemoveItem(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T
|
|
||||||
TypedList<T>::RemoveItemAt(int32 index)
|
|
||||||
{
|
|
||||||
return (T)_PointerList::RemoveItem(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T
|
|
||||||
TypedList<T>::ItemAt(int32 index) const
|
|
||||||
{
|
|
||||||
return (T)_PointerList::ItemAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T
|
|
||||||
TypedList<T>::ItemAtFast(int32 index) const
|
|
||||||
{
|
|
||||||
return (T)_PointerList::ItemAtFast(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
int32
|
|
||||||
TypedList<T>::IndexOf(const T item) const
|
|
||||||
{
|
|
||||||
return _PointerList::IndexOf(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T
|
|
||||||
TypedList<T>::FirstItem() const
|
|
||||||
{
|
|
||||||
return (T)_PointerList::FirstItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T
|
|
||||||
TypedList<T>::LastItem() const
|
|
||||||
{
|
|
||||||
return (T)_PointerList::LastItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool
|
|
||||||
TypedList<T>::HasItem(const T item) const
|
|
||||||
{
|
|
||||||
return _PointerList::HasItem(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool
|
|
||||||
TypedList<T>::IsEmpty() const
|
|
||||||
{
|
|
||||||
return _PointerList::IsEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
int32
|
|
||||||
TypedList<T>::CountItems() const
|
|
||||||
{
|
|
||||||
return _PointerList::CountItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void
|
|
||||||
TypedList<T>::MakeEmpty()
|
|
||||||
{
|
|
||||||
if (Owning()) {
|
|
||||||
int32 numElements = CountItems();
|
|
||||||
|
|
||||||
for (int32 count = 0; count < numElements; count++)
|
|
||||||
// this is probably not the most efficient, but
|
|
||||||
// is relatively indepenent of BList implementation
|
|
||||||
// details
|
|
||||||
RemoveItem(LastItem());
|
|
||||||
}
|
|
||||||
_PointerList::MakeEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T
|
|
||||||
TypedList<T>::EachElement(EachFunction func, void *params)
|
|
||||||
{
|
|
||||||
return (T)_PointerList::EachElement((GenericEachFunction)func, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
const T
|
|
||||||
TypedList<T>::EachElement(ConstEachFunction func, void *params) const
|
|
||||||
{
|
|
||||||
return (const T)
|
|
||||||
const_cast<TypedList<T> *>(this)->_PointerList::EachElement(
|
|
||||||
(GenericEachFunction)func, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T
|
|
||||||
TypedList<T>::Items() const
|
|
||||||
{
|
|
||||||
return (T)_PointerList::Items();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void
|
|
||||||
TypedList<T>::SortItems(CompareFunction function)
|
|
||||||
{
|
|
||||||
ASSERT(sizeof(T) == sizeof(void *));
|
|
||||||
_PointerList::SortItems((GenericCompareFunction)function);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool TypedList<T>::ReplaceItem(int32 index, T item)
|
|
||||||
{
|
|
||||||
return _PointerList::ReplaceItem(index, (void *)item);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool TypedList<T>::SwapItems(int32 a, int32 b)
|
|
||||||
{
|
|
||||||
return _PointerList::SwapItems(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool TypedList<T>::MoveItem(int32 from, int32 to)
|
|
||||||
{
|
|
||||||
return _PointerList::MoveItem(from, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Reference in New Issue
Block a user