Add a position-seeker replicant (PositionView)

This commit is contained in:
Jaidyn Ann 2022-06-07 06:23:02 -05:00
parent 00f9ecb0cb
commit 44eda8ab54
6 changed files with 249 additions and 0 deletions

View File

@ -36,6 +36,7 @@ SRCS = src/App.cpp \
src/LyricsView.cpp \
src/MainWindow.cpp \
src/MediaPlayer.cpp \
src/PositionView.cpp \
src/ReplicantView.cpp \
src/Song.cpp \
src/Util.cpp \

View File

@ -11,6 +11,7 @@
#include "CoverView.h"
#include "LyricsView.h"
#include "PositionView.h"
#include "VolumeView.h"
@ -32,6 +33,7 @@ MainWindow::_InitInterface()
BView* controlsView = new BView("Controls", B_WILL_DRAW);
BLayoutBuilder::Group<>(controlsView, B_VERTICAL)
.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()
.End();

View File

@ -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
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
MediaPlayer::Volume()
{

View File

@ -29,7 +29,9 @@ public:
bool IsPlaying();
int64 Duration();
int64 Position();
void SetPosition(int64 position);
float Volume();
void SetVolume(float volume);

179
src/PositionView.cpp Normal file
View File

@ -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;
}

47
src/PositionView.h Normal file
View File

@ -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