Add a position-seeker replicant (PositionView)
This commit is contained in:
parent
00f9ecb0cb
commit
44eda8ab54
1
Makefile
1
Makefile
|
@ -36,6 +36,7 @@ SRCS = src/App.cpp \
|
||||||
src/LyricsView.cpp \
|
src/LyricsView.cpp \
|
||||||
src/MainWindow.cpp \
|
src/MainWindow.cpp \
|
||||||
src/MediaPlayer.cpp \
|
src/MediaPlayer.cpp \
|
||||||
|
src/PositionView.cpp \
|
||||||
src/ReplicantView.cpp \
|
src/ReplicantView.cpp \
|
||||||
src/Song.cpp \
|
src/Song.cpp \
|
||||||
src/Util.cpp \
|
src/Util.cpp \
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "CoverView.h"
|
#include "CoverView.h"
|
||||||
#include "LyricsView.h"
|
#include "LyricsView.h"
|
||||||
|
#include "PositionView.h"
|
||||||
#include "VolumeView.h"
|
#include "VolumeView.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ MainWindow::_InitInterface()
|
||||||
BView* controlsView = new BView("Controls", B_WILL_DRAW);
|
BView* controlsView = new BView("Controls", B_WILL_DRAW);
|
||||||
BLayoutBuilder::Group<>(controlsView, B_VERTICAL)
|
BLayoutBuilder::Group<>(controlsView, B_VERTICAL)
|
||||||
.Add(new VolumeView(BRect(BPoint(0,0), BSize(100.0, 20.0))))
|
.Add(new VolumeView(BRect(BPoint(0,0), BSize(100.0, 20.0))))
|
||||||
|
.Add(new PositionView(BRect(BPoint(0,0), BSize(100.0, 20.0))))
|
||||||
.AddGlue()
|
.AddGlue()
|
||||||
.End();
|
.End();
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,15 @@ MediaPlayer::IsPlaying()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int64
|
||||||
|
MediaPlayer::Duration()
|
||||||
|
{
|
||||||
|
BMessage send, reply;
|
||||||
|
_ScriptingCall("Duration", &send, &reply, MP_CURRENT_TRACK);
|
||||||
|
return reply.GetInt64("result", -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int64
|
int64
|
||||||
MediaPlayer::Position()
|
MediaPlayer::Position()
|
||||||
{
|
{
|
||||||
|
@ -63,6 +72,15 @@ MediaPlayer::Position()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaPlayer::SetPosition(int64 position)
|
||||||
|
{
|
||||||
|
BMessage send(B_SET_PROPERTY), reply;
|
||||||
|
send.AddInt64("data", position);
|
||||||
|
_ScriptingCall("Position", &send, &reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
float
|
float
|
||||||
MediaPlayer::Volume()
|
MediaPlayer::Volume()
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,7 +29,9 @@ public:
|
||||||
|
|
||||||
|
|
||||||
bool IsPlaying();
|
bool IsPlaying();
|
||||||
|
int64 Duration();
|
||||||
int64 Position();
|
int64 Position();
|
||||||
|
void SetPosition(int64 position);
|
||||||
float Volume();
|
float Volume();
|
||||||
void SetVolume(float volume);
|
void SetVolume(float volume);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022, Jaidyn Levesque <jadedctrl@teknik.io>
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PositionView.h"
|
||||||
|
|
||||||
|
#include <ControlLook.h>
|
||||||
|
|
||||||
|
#include "MediaPlayer.h"
|
||||||
|
|
||||||
|
|
||||||
|
const char* kPositionDesc = "PositionView is a replicant that shows the position of currently playing item.";
|
||||||
|
|
||||||
|
// The same color MediaPlayer uses, interface/SeekSlider
|
||||||
|
static const rgb_color kThumbRed = (rgb_color){ 255, 52, 52, 255 };
|
||||||
|
|
||||||
|
static const uint32 POSITION_CHANGED = 'vvch';
|
||||||
|
|
||||||
|
|
||||||
|
SeekSlider::SeekSlider(BRect frame, const char* name, BMessage* message, int32 minValue,
|
||||||
|
int32 maxValue, orientation posture, uint32 resizingMode, uint32 flags)
|
||||||
|
:
|
||||||
|
BSlider(frame, name, NULL, message, minValue, maxValue, posture, B_TRIANGLE_THUMB, resizingMode,
|
||||||
|
flags)
|
||||||
|
{
|
||||||
|
rgb_color fillColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
|
||||||
|
B_DARKEN_3_TINT);
|
||||||
|
UseFillColor(true, &fillColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SeekSlider::DrawThumb()
|
||||||
|
{
|
||||||
|
if (!IsEnabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
BRect frame = ThumbFrame();
|
||||||
|
be_control_look->DrawSliderTriangle(this, frame, frame, kThumbRed, 0,
|
||||||
|
B_HORIZONTAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PositionView::PositionView(BRect frame)
|
||||||
|
:
|
||||||
|
ReplicantView(frame, "Position", B_FOLLOW_RIGHT, B_FOLLOW_LEFT_RIGHT,
|
||||||
|
B_WILL_DRAW | B_DRAW_ON_CHILDREN | B_NAVIGABLE | B_FRAME_EVENTS)
|
||||||
|
{
|
||||||
|
fDescription.SetTo(kPositionDesc);
|
||||||
|
|
||||||
|
_InitInterface();
|
||||||
|
Pulse();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PositionView::PositionView(BMessage* data)
|
||||||
|
:
|
||||||
|
ReplicantView(data)
|
||||||
|
{
|
||||||
|
fDescription.SetTo(kPositionDesc);
|
||||||
|
|
||||||
|
// For some reason, the BSlider gets archived with a wacko frame― better to just nuke it.
|
||||||
|
fSlider = dynamic_cast<SeekSlider*>(FindView("seekSlider"));
|
||||||
|
delete fSlider;
|
||||||
|
|
||||||
|
_InitInterface();
|
||||||
|
Pulse();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
PositionView::Archive(BMessage* data, bool deep) const
|
||||||
|
{
|
||||||
|
status_t status = ReplicantView::Archive(data, deep);
|
||||||
|
|
||||||
|
data->AddString("class", "PositionView");
|
||||||
|
data->AddString("add_on", APP_SIGNATURE);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PositionView*
|
||||||
|
PositionView::Instantiate(BMessage* data)
|
||||||
|
{
|
||||||
|
if (!validate_instantiation(data, "PositionView"))
|
||||||
|
return NULL;
|
||||||
|
return new PositionView(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionView::AttachedToWindow()
|
||||||
|
{
|
||||||
|
fSlider->SetTarget(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionView::MessageReceived(BMessage* msg)
|
||||||
|
{
|
||||||
|
switch (msg->what) {
|
||||||
|
case POSITION_CHANGED:
|
||||||
|
fMediaPlayer->SetPosition(_SliderToPosition(fSlider->Position(),
|
||||||
|
fMediaPlayer->Duration()));
|
||||||
|
break;
|
||||||
|
case B_MOUSE_WHEEL_CHANGED:
|
||||||
|
{
|
||||||
|
float scroll = 0.0f;
|
||||||
|
if ((msg->FindFloat("be:wheel_delta_x", &scroll) == B_OK && scroll != 0.0f)
|
||||||
|
|| (msg->FindFloat("be:wheel_delta_y", &scroll) == B_OK && scroll != 0.0f))
|
||||||
|
fSlider->SetPosition(fSlider->Position() + scroll * -0.03);
|
||||||
|
fMediaPlayer->SetPosition(_SliderToPosition(fSlider->Position(),
|
||||||
|
fMediaPlayer->Duration()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ReplicantView::MessageReceived(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionView::Pulse()
|
||||||
|
{
|
||||||
|
int64 position = fMediaPlayer->Position();
|
||||||
|
int64 duration = fMediaPlayer->Duration();
|
||||||
|
if (duration > 0) {
|
||||||
|
SetInactive(false);
|
||||||
|
fSlider->SetPosition(_PositionToSlider(position, duration));
|
||||||
|
} else
|
||||||
|
SetInactive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionView::SetInactive(bool inactive)
|
||||||
|
{
|
||||||
|
fSlider->SetEnabled(!inactive);
|
||||||
|
|
||||||
|
if (inactive && fTransparentInactivity && !fSlider->IsHidden())
|
||||||
|
fSlider->Hide();
|
||||||
|
else if ((!inactive || !fTransparentInactivity) && fSlider->IsHidden())
|
||||||
|
fSlider->Show();
|
||||||
|
|
||||||
|
ReplicantView::SetInactive(inactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PositionView::_InitInterface()
|
||||||
|
{
|
||||||
|
SetViewColor(B_TRANSPARENT_COLOR);
|
||||||
|
|
||||||
|
fSlider = new SeekSlider(BRect(), "seekSlider", NULL, 0, 1000, B_HORIZONTAL,
|
||||||
|
B_FOLLOW_LEFT_RIGHT);
|
||||||
|
fSlider->SetModificationMessage(new BMessage(POSITION_CHANGED));
|
||||||
|
fSlider->SetViewColor(B_TRANSPARENT_COLOR);
|
||||||
|
AddChild(fSlider);
|
||||||
|
|
||||||
|
float height = 20.0;
|
||||||
|
fSlider->GetPreferredSize(NULL, &height);
|
||||||
|
SetExplicitMaxSize(BSize(B_SIZE_UNSET, height + 16));
|
||||||
|
fSlider->ResizeTo(Frame().Size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int64
|
||||||
|
PositionView::_SliderToPosition(float sliderPos, int64 duration)
|
||||||
|
{
|
||||||
|
return duration * sliderPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float
|
||||||
|
PositionView::_PositionToSlider(int64 position, int64 duration)
|
||||||
|
{
|
||||||
|
return (double)position / (double)duration;
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022, Jaidyn Levesque <jadedctrl@teknik.io>
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT license.
|
||||||
|
*/
|
||||||
|
#ifndef POSITIONVIEW_H
|
||||||
|
#define POSITIONVIEW_H
|
||||||
|
|
||||||
|
#include <Slider.h>
|
||||||
|
|
||||||
|
#include "ReplicantView.h"
|
||||||
|
|
||||||
|
|
||||||
|
class SeekSlider : public BSlider {
|
||||||
|
public:
|
||||||
|
SeekSlider(BRect frame, const char* name, BMessage* message, int32 minValue,
|
||||||
|
int32 maxValue, orientation posture,
|
||||||
|
uint32 resizingMode = B_FOLLOW_LEFT_TOP,
|
||||||
|
uint32 flags = B_NAVIGABLE | B_WILL_DRAW | B_FRAME_EVENTS);
|
||||||
|
|
||||||
|
virtual void DrawThumb();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class PositionView : public ReplicantView {
|
||||||
|
public:
|
||||||
|
PositionView(BRect frame);
|
||||||
|
PositionView(BMessage* archive);
|
||||||
|
|
||||||
|
virtual status_t Archive(BMessage* data, bool deep = true) const;
|
||||||
|
static PositionView* Instantiate(BMessage* data);
|
||||||
|
|
||||||
|
void AttachedToWindow();
|
||||||
|
|
||||||
|
virtual void MessageReceived(BMessage* msg);
|
||||||
|
virtual void Pulse();
|
||||||
|
|
||||||
|
virtual void SetInactive(bool inactive);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _InitInterface();
|
||||||
|
int64 _SliderToPosition(float volume, int64 duration);
|
||||||
|
float _PositionToSlider(int64 position, int64 duration);
|
||||||
|
|
||||||
|
SeekSlider* fSlider;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // POSITIONVIEW_H
|
Ŝarĝante…
Reference in New Issue