diff --git a/src/apps/cdplayer/CDEngine.cpp b/src/apps/cdplayer/CDEngine.cpp index 9ca3def651..af327d3655 100644 --- a/src/apps/cdplayer/CDEngine.cpp +++ b/src/apps/cdplayer/CDEngine.cpp @@ -454,7 +454,10 @@ CDEngine::StopSkipping() void CDEngine::SelectTrack(int32 trackNumber) { - sCDDevice.Play(trackNumber); + sPlayList.SetCurrentTrack(trackNumber); + if(playState.GetState() == kPlaying) + sCDDevice.Play(trackNumber); + trackState.UpdateNow(); } void diff --git a/src/apps/cdplayer/CDPlayer.cpp b/src/apps/cdplayer/CDPlayer.cpp index 209be4232e..a5fc0c1fe1 100644 --- a/src/apps/cdplayer/CDPlayer.cpp +++ b/src/apps/cdplayer/CDPlayer.cpp @@ -33,6 +33,7 @@ enum { M_STOP='mstp', M_PLAY, + M_SELECT_TRACK, M_NEXT_TRACK, M_PREV_TRACK, M_FFWD, @@ -74,7 +75,12 @@ void CDPlayer::BuildGUI(void) fPlayColor.blue = 40; fPlayColor.alpha = 255; - BRect r(5,5,230,25); + BRect r; + r.left = 5; + r.top = 5; + r.right = (Bounds().Width()/2) - 7; + r.bottom = 25; + // Assemble the CD Title box fCDBox = new BBox(r,"TrackBox"); @@ -89,6 +95,10 @@ void CDPlayer::BuildGUI(void) fCDTitle->SetHighColor(200,200,200); fCDTitle->SetFont(be_bold_font); + r.OffsetBy(0, r.Height() + 5); + fTrackMenu = new TrackMenu(r, "TrackMenu", new BMessage(M_SELECT_TRACK)); + AddChild(fTrackMenu); + r.Set(fCDTitle->Frame().right + 15,5,Bounds().right - 5,25); fTrackBox = new BBox(r,"TrackBox",B_FOLLOW_TOP); AddChild(fTrackBox); @@ -105,7 +115,7 @@ void CDPlayer::BuildGUI(void) r.OffsetBy(0, r.Height() + 5); fTimeBox = new BBox(r,"TimeBox",B_FOLLOW_LEFT_RIGHT); AddChild(fTimeBox); - + view = new BView( fTimeBox->Bounds().InsetByCopy(2,2), "view",B_FOLLOW_ALL,B_WILL_DRAW); view->SetViewColor(0,7,34); fTimeBox->AddChild(view); @@ -259,6 +269,11 @@ CDPlayer::MessageReceived(BMessage *msg) } break; } + case M_SELECT_TRACK: + { + engine->SelectTrack(fTrackMenu->Value()+1); + break; + } case M_NEXT_TRACK: { engine->SkipOneForward(); @@ -339,7 +354,11 @@ CDPlayer::NoticeChange(Notifier *notifier) else if(trs) { - // TODO: Update track count indicator once there is one + if(fTrackMenu->CountItems() != engine->TrackStateWatcher()->GetNumTracks()) + fTrackMenu->SetItemCount(engine->TrackStateWatcher()->GetNumTracks()); + + fTrackMenu->SetValue(engine->TrackStateWatcher()->GetTrack()-1); + UpdateCDInfo(); } else @@ -566,6 +585,7 @@ CDPlayer::AttachedToWindow() fSave->SetTarget(this); fShuffle->SetTarget(this); fRepeat->SetTarget(this); + fTrackMenu->SetTarget(this); } void @@ -580,6 +600,8 @@ CDPlayer::FrameResized(float new_width, float new_height) float half = (new_width / 2); fCDBox->ResizeTo( half - 7, fCDBox->Bounds().Height() ); + fTrackMenu->ResizeTo( half - 7, fTrackMenu->Bounds().Height() ); + fTrackMenu->Invalidate(); fTrackBox->MoveTo(half + 8, fTrackBox->Frame().top); fTrackBox->ResizeTo( Bounds().right - (half + 8) - 5, fTrackBox->Bounds().Height() ); diff --git a/src/apps/cdplayer/CDPlayer.h b/src/apps/cdplayer/CDPlayer.h index 4bd67ae1d3..3d913dc505 100644 --- a/src/apps/cdplayer/CDPlayer.h +++ b/src/apps/cdplayer/CDPlayer.h @@ -18,6 +18,7 @@ #include "Observer.h" #include "CDEngine.h" +#include "TrackMenu.h" class DrawButton; class TwoStateDrawButton; @@ -75,6 +76,8 @@ private: BBox *fCDBox, *fTrackBox, *fTimeBox; + + TrackMenu *fTrackMenu; CDState fCDState; diff --git a/src/apps/cdplayer/Jamfile b/src/apps/cdplayer/Jamfile index 3de58c1ff3..14361ec87e 100644 --- a/src/apps/cdplayer/Jamfile +++ b/src/apps/cdplayer/Jamfile @@ -10,6 +10,7 @@ App CDPlayer : FunctionObjectMessage.cpp Observer.cpp PlayList.cpp + TrackMenu.cpp TwoStateDrawButton.cpp TypedList.cpp ; diff --git a/src/apps/cdplayer/TrackMenu.cpp b/src/apps/cdplayer/TrackMenu.cpp new file mode 100644 index 0000000000..5bc1ee603d --- /dev/null +++ b/src/apps/cdplayer/TrackMenu.cpp @@ -0,0 +1,286 @@ +#include +#include +#include +#include +#include +#include "TrackMenu.h" +#include + +TrackMenu::TrackMenu(const BRect &frame, const char *name, BMessage *msg, + const int32 &resize, const int32 &flags) + : BView(frame,name,resize,flags), + BInvoker(msg,NULL), + fCurrentItem(-1), + fCount(0), + fIsTracking(false) +{ + SetViewColor(20,20,20); + + fItemRect.Set(1,1,1 + StringWidth("00") + 3, Bounds().bottom - 1); + + BFont font; + font.SetSize(11); + font.SetSpacing(B_STRING_SPACING); + SetFont(&font); + + font_height fh; + GetFontHeight(&fh); + + fFontHeight = fh.ascent + fh.descent + fh.leading; +} + +TrackMenu::~TrackMenu(void) +{ +} + +void +TrackMenu::AttachedToWindow(void) +{ + if (!Messenger().IsValid()) + SetTarget(Window()); + + BView::AttachedToWindow(); +} + +void +TrackMenu::MessageReceived(BMessage *msg) +{ + switch(msg->what) + { + default: + { + BView::MessageReceived(msg); + break; + } + } +} + +void +TrackMenu::SetItemCount(const int32 &count) +{ + if(count < 0) + { + fCount = 0; + fCurrentItem = -1; + Invalidate(); + return; + } + + fCount = count; + + if(fCurrentItem > fCount - 1) + fCurrentItem = fCount - 1; + else + if(fCurrentItem < 0) + fCurrentItem = 0; + + Invalidate(); +} + +void +TrackMenu::SetValue(const int32 &value) +{ + if(value < 0 || value > fCount) + return; + + if(value != Value()) + { + fCurrentItem = value; + Invalidate(); + } +} + +int32 +TrackMenu::ItemAt(const BPoint &pt) +{ + // TODO: Optimize. This is simple, but costly in performance + BRect r(fItemRect); + for(int32 i=0; i= 0) + { + fCurrentItem = item; + Invalidate(); + + // Shamelessly stolen from BButton. :D + if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) + { + SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); + fIsTracking = true; + + } else + { + uint32 buttons; + + do + { + Window()->UpdateIfNeeded(); + + snooze(40000); + + GetMouse(&pt, &buttons, true); + + int32 mouseitem = ItemAt(pt); + if(mouseitem > -1) + { + fCurrentItem = mouseitem; + Draw(Bounds()); + } + + } while (buttons != 0); + + if(fCurrentItem != saveditem) + Invoke(); + } + } +} + +void +TrackMenu::MouseUp(BPoint pt) +{ + if(!fIsTracking) + return; + + int32 item = ItemAt(pt); + + if(item >= 0) + Invoke(); + + fIsTracking = false; +} + +void +TrackMenu::MouseMoved(BPoint pt, uint32 transit, const BMessage *msg) +{ + if(!fIsTracking) + return; + + int32 item = ItemAt(pt); + + if(item >= 0) + { + fCurrentItem = item; + Invalidate(); + } +} + +void +TrackMenu::Draw(BRect update) +{ + rgb_color dark = {20,20,20,255}; + rgb_color light = {200,200,200,255}; + BPoint pt1,pt2; + + // Draw the frame + SetHighColor(dark); + pt1.Set(0,0); + pt2 = Bounds().RightTop(); + StrokeLine(pt1,pt2); + + pt2.Set(0,Bounds().bottom); + StrokeLine(pt1,pt2); + + SetHighColor(255,255,255); + pt1 = Bounds().RightBottom(); + pt2.Set(Bounds().right, 1); + StrokeLine(pt1,pt2); + + pt2.Set(1,Bounds().bottom); + StrokeLine(pt1,pt2); + + // Draw the items + BRect r(fItemRect); + + for(int32 i=0; i Bounds().right - 2) + { + ConstrainClippingRegion(NULL); + break; + } + + if(r.right > Bounds().right - 2) + { + r.right = Bounds().right - 2; + BRegion reg(r); + ConstrainClippingRegion(®); + } + } +} diff --git a/src/apps/cdplayer/TrackMenu.h b/src/apps/cdplayer/TrackMenu.h new file mode 100644 index 0000000000..c7ee3dbc2e --- /dev/null +++ b/src/apps/cdplayer/TrackMenu.h @@ -0,0 +1,40 @@ +#ifndef TRACKMENU_H +#define TRACKMENU_H + +#include +#include + +class TrackMenu : public BView, public BInvoker +{ +public: + TrackMenu(const BRect &frame, const char *name, BMessage *msg, + const int32 &resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, + const int32 &flags = B_WILL_DRAW); + ~TrackMenu(void); + + void AttachedToWindow(void); + void MessageReceived(BMessage *msg); + void Draw(BRect update); + void MouseDown(BPoint pt); + void MouseUp(BPoint pt); + void MouseMoved(BPoint pt, uint32 transit, const BMessage *msg); + + int32 CountItems(void) const { return fCount; } + void SetItemCount(const int32 &count); + + int32 Value(void) const { return fCurrentItem; } + void SetValue(const int32 &value); + +private: + int32 ItemAt(const BPoint &pt); + + int32 fCurrentItem; + int32 fCount; + BRect fItemRect; + + bool fIsTracking; + + float fFontHeight; +}; + +#endif