Skip to content

Commit

Permalink
Add slider in video player to control playback pos
Browse files Browse the repository at this point in the history
  • Loading branch information
gandous committed May 31, 2022
1 parent 0ab50b0 commit b648502
Show file tree
Hide file tree
Showing 16 changed files with 251 additions and 11 deletions.
13 changes: 12 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@
"forward_list": "cpp",
"iomanip": "cpp",
"sstream": "cpp",
"valarray": "cpp"
"valarray": "cpp",
"complex": "cpp",
"bitset": "cpp",
"condition_variable": "cpp",
"set": "cpp",
"mutex": "cpp",
"semaphore": "cpp",
"stop_token": "cpp",
"thread": "cpp",
"cfenv": "cpp",
"typeindex": "cpp",
"variant": "cpp"
}
}
3 changes: 2 additions & 1 deletion lib/gana/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ void App::set_focused_node(Node *node)
node->set_focus(true);
_focused_node = node;
signal_node_focus.emit(_focused_node);
node->on_focus();
if (node != nullptr)
node->on_focus();
}

Node *App::get_focused_node()
Expand Down
25 changes: 25 additions & 0 deletions lib/gana/type/Event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,26 @@ Event::~Event()
{}

bool Event::is_touch() const
{
return (is_touch_up());
}

bool Event::is_touch_up() const
{
if ((type == sf::Event::MouseButtonReleased && mouseButton.button == sf::Mouse::Left) || type == sf::Event::TouchEnded)
return (true);
else
return (false);
}

bool Event::is_touch_down() const
{
if ((type == sf::Event::MouseButtonPressed && mouseButton.button == sf::Mouse::Left) || type == sf::Event::TouchBegan)
return (true);
else
return (false);
}

bool Event::accept_pressed() const
{
if ((type == sf::Event::KeyPressed && key.code == sf::Keyboard::Enter) || (type == sf::Event::JoystickButtonReleased && joystickButton.button == SwitchPadButton::A))
Expand All @@ -34,4 +47,16 @@ bool Event::cancel_pressed() const
return (false);
}

Vector2f Event::get_position() const
{
if (type == sf::Event::MouseButtonPressed || type == sf::Event::MouseButtonReleased) {
return (Vector2f(mouseButton.x, mouseButton.y));
} else if (type == sf::Event::MouseMoved) {
return (Vector2f(mouseMove.x, mouseMove.y));
} else if (type == sf::Event::TouchBegan || type == sf::Event::TouchEnded || type == sf::Event::TouchMoved) {
return (Vector2f(touch.x, touch.y));
}
return (Vector2f());
}

}
8 changes: 7 additions & 1 deletion lib/gana/type/Event.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#define EVENT_HPP_

#include <SFML/Window/Event.hpp>
#include "Vector2.hpp"

namespace gana {

Expand All @@ -12,12 +13,17 @@ class Event: public sf::Event {
~Event();

bool handle;
// Return true if the event is a left click or a touch
// Return true if the event is a left click or a touch and key is released
bool is_touch() const;
// Return true if the event is a left click or a touch and key is pressed
bool is_touch_down() const;
// Return true if the event is a left click or a touch and key is released
bool is_touch_up() const;
// Switch button A is pressed or Enter key pressed
bool accept_pressed() const;
// Switch button B is pressed or Escape key pressed
bool cancel_pressed() const;
Vector2f get_position() const;
private:
};

Expand Down
1 change: 1 addition & 0 deletions lib/gana/type/Vector2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Vector2 {

Vector2 normalize();
float length();
float distance(const Vector2<T> &point);
std::string to_string() const;
Vector2<T> &operator*(T nb);
Vector2<T> operator*(const Vector2<T> &vec) const;
Expand Down
18 changes: 12 additions & 6 deletions lib/gana/type/Vector2.inl
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,23 @@ inline Vector2<T> Vector2<T>::normalize()
}

template<typename T>
inline std::string Vector2<T>::to_string() const
inline float Vector2<T>::length()
{
std::ostringstream str;
str << "Vector2(" << x << ", " << y << ")";
return (str.str());
return (std::sqrt(this->x * this->x + this->y * this->y));
}

template<typename T>
inline float Vector2<T>::length()
inline float Vector2<T>::distance(const Vector2<T> &point)
{
return (std::sqrt(this->x * this->x + this->y * this->y));
return (std::sqrt(std::pow(this->x - point.x, 2) + std::pow(this->y - point.y, 2)));
}

template<typename T>
inline std::string Vector2<T>::to_string() const
{
std::ostringstream str;
str << "Vector2(" << x << ", " << y << ")";
return (str.str());
}

template<typename T>
Expand Down
13 changes: 13 additions & 0 deletions lib/gana/ui/MPVPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ bool MPVPlayer::is_seeking()
return (seeking == 1);
}

bool MPVPlayer::is_core_idle()
{
int64_t core_idle;
mpv_get_property(_handle, "core-idle", MPV_FORMAT_INT64, &core_idle);
return (core_idle == 1);
}

int64_t MPVPlayer::get_time_pos()
{
Expand All @@ -75,6 +81,11 @@ int64_t MPVPlayer::get_time_pos()
return (data);
}

void MPVPlayer::set_time_pos(int64_t pos)
{
mpv_set_property(_handle, "time-pos", MPV_FORMAT_INT64, &pos);
}

int64_t MPVPlayer::get_duration()
{
int64_t data;
Expand Down Expand Up @@ -156,6 +167,8 @@ void MPVPlayer::event()
}
} else {
Logger::info("MPV event: %s", mpv_event_name(mp_event->event_id));
if (mp_event->event_id == MPV_EVENT_FILE_LOADED)
signal_file_loaded.emit();
}
}
_mpv_event = false;
Expand Down
5 changes: 5 additions & 0 deletions lib/gana/ui/MPVPlayer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <mpv/client.h>
#include <mpv/render.h>
#include "ui/Node.hpp"
#include "type/Signal.hpp"

#define DEBUG_MPV 0

Expand All @@ -17,8 +18,12 @@ class MPVPlayer: public Node {

void set_source(const std::string &src);
bool is_seeking();
bool is_core_idle();
int64_t get_time_pos();
void set_time_pos(int64_t pos);
int64_t get_duration();

Signal<> signal_file_loaded;
protected:
void process();
void enter_tree();
Expand Down
Binary file added romfs/icon/pause-24.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added romfs/icon/pause-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions src/network/item/duration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
static const std::size_t TICK_PER_HOUR = 36000000000;
static const std::size_t TICK_PER_MINUTE = 600000000;
static const std::size_t TICK_PER_SECOND = 10000000;
static const std::size_t MPV_TICK_PER_HOUR = 3600;
static const std::size_t MPV_TICK_PER_MINUTE = 60;

std::string tick_to_duration(Tick tick)
{
Expand All @@ -18,3 +20,16 @@ std::string tick_to_duration(Tick tick)
str << minute << "m";
return (str.str());
}

std::string mpv_tick_to_duration(uint64_t tick)
{
std::ostringstream str;
int hour = tick / MPV_TICK_PER_HOUR;
int minute = tick / MPV_TICK_PER_MINUTE;

if (hour > 0) {
str << hour << ":";
}
str << minute << ":" << (tick % MPV_TICK_PER_MINUTE);
return (str.str());
}
1 change: 1 addition & 0 deletions src/network/item/duration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
#include "item_type.hpp"

std::string tick_to_duration(Tick tick);
std::string mpv_tick_to_duration(uint64_t tick);

#endif /* DURATION_HPP_ */
49 changes: 47 additions & 2 deletions src/ui/player/Player.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,62 @@

#include "network/item/duration.hpp"
#include "Player.hpp"

static const float MIN_TIME_WIDTH = 100;

Player::Player(gana::NavigationManager &nav, std::shared_ptr<JellyfinClient> client, const Item &item)
{
_player.set_source(client->get_stream_url(item.get_id()));
_player.signal_file_loaded.connect(*this, &Player::on_file_loaded);
add_child(&_player);
set_process();

_ctn.add_spacer(8, true);

_lbl_current_time.set_text("-");
_lbl_current_time.set_min_size(gana::Vector2f(MIN_TIME_WIDTH, 0));
_lbl_current_time.set_text_align(gana::BaseLabel::TextAlign::CENTER);
_ctn_duration_bar.add_child(&_lbl_current_time);

_slider_bar.signal_value_changed.connect(*this, &Player::on_slider_value_changed);
_slider_bar.set_expand();
_ctn_duration_bar.add_child(&_slider_bar);

_lbl_duration.set_text("-");
_lbl_duration.set_min_size(gana::Vector2f(MIN_TIME_WIDTH, 0));
_lbl_duration.set_text_align(gana::BaseLabel::TextAlign::CENTER);
_ctn_duration_bar.add_child(&_lbl_duration);

_ctn_duration_bar.set_hsizing(gana::Node::Sizing::FILL);
_ctn_duration_bar.set_margin(16, 0, 16, 0);
_ctn.add_child(&_ctn_duration_bar);

_ctn.set_anchor(gana::Node::Anchor::FULL_RECT);
add_child(&_ctn);

set_anchor(gana::Node::Anchor::FULL_RECT);
}

Player::~Player()
{}

void Player::process()
{
gana::Logger::info("time pos %d/%d", _player.get_time_pos(), _player.get_duration());
uint64_t time = _player.get_time_pos();
_slider_bar.set_value(time);
_lbl_current_time.set_text(mpv_tick_to_duration(time));
}

void Player::on_file_loaded()
{
set_process();
uint64_t time = _player.get_time_pos();
_slider_bar.set_max_value(_player.get_duration());
_slider_bar.set_value(time);
_lbl_current_time.set_text(mpv_tick_to_duration(time));
_lbl_duration.set_text(mpv_tick_to_duration(_player.get_duration()));
}

void Player::on_slider_value_changed(uint value)
{
_player.set_time_pos(value);
}
11 changes: 11 additions & 0 deletions src/ui/player/Player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
#include "gana/ui/Node.hpp"
#include "gana/ui/NavigationManager.hpp"
#include "gana/ui/MPVPlayer.hpp"
#include "gana/ui/Label.hpp"
#include "gana/ui/box_container/VBoxContainer.hpp"
#include "gana/ui/box_container/HBoxContainer.hpp"
#include "network/JellyfinClient.hpp"
#include "Slider.hpp"

class Player: public gana::Node {
public:
Expand All @@ -16,7 +20,14 @@ class Player: public gana::Node {
protected:
void process();
private:
void on_file_loaded();
void on_slider_value_changed(uint value);
gana::MPVPlayer _player;
gana::VBoxContainer _ctn;
gana::HBoxContainer _ctn_duration_bar;
gana::Label _lbl_current_time;
gana::Label _lbl_duration;
Slider _slider_bar;
};

#endif /* PLAYER_HPP_ */
73 changes: 73 additions & 0 deletions src/ui/player/Slider.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@

#include "gana/theme/color.hpp"
#include "gana/App.hpp"
#include "Slider.hpp"

static const gana::Vector2f MIN_SIZE = gana::Vector2f(20, 20);
static const int BAR_HEIGTH = 12;

Slider::Slider(): _value(0), _max_value(0), _percentage(0)
{
set_min_size(MIN_SIZE);
}

Slider::~Slider()
{}

void Slider::draw(NVGcontext *ctx)
{
float y = get_draw_positon().y + (get_draw_size().y - BAR_HEIGTH) / 2;
nvgBeginPath(ctx);
nvgRoundedRect(ctx, get_draw_positon().x, y, get_draw_size().x, BAR_HEIGTH, BAR_HEIGTH / 2);
nvgFillColor(ctx, gana::Color(40, 40, 40, 225).nvg_color());
nvgFill(ctx);
nvgBeginPath(ctx);
nvgRoundedRect(ctx, get_draw_positon().x, y, get_draw_size().x * _percentage, BAR_HEIGTH, BAR_HEIGTH / 2);
nvgFillColor(ctx, gana::theme::PRIMARY.nvg_color());
nvgFill(ctx);

nvgBeginPath(ctx);
nvgCircle(ctx, _center_sliding_point.x, _center_sliding_point.y, MIN_SIZE.y / 2);
nvgFillColor(ctx, gana::Color(255, 40, 40).nvg_color());
nvgFill(ctx);
}

void Slider::process_event(gana::Event &evt)
{
if (evt.is_touch_down() && evt.get_position().distance(_center_sliding_point) < MIN_SIZE.y) {
_app->set_focused_node(this);
evt.handle = true;
} else if (has_focus() && (evt.type == sf::Event::TouchMoved || evt.type == sf::Event::MouseMoved)) {
if (evt.get_position().x > get_draw_positon().x && evt.get_position().x < get_draw_positon().x + get_draw_size().x) {
_percentage = (evt.get_position().x - get_draw_positon().x) / get_draw_size().x;
_value = _max_value * _percentage;
update_percentage();
}
} else if (has_focus()) {
signal_value_changed.emit(_value);
_app->set_focused_node(nullptr);
}
}

void Slider::set_max_value(uint value)
{
if (has_focus())
return;
_max_value = value;
update_percentage();
}

void Slider::set_value(uint value)
{
if (has_focus())
return;
_value = value;
update_percentage();
}

void Slider::update_percentage()
{
_percentage = (float)_value / (float)_max_value;
_center_sliding_point.x = get_draw_positon().x + get_draw_size().x * _percentage;
_center_sliding_point.y = get_draw_positon().y + MIN_SIZE.y / 2;
}
Loading

0 comments on commit b648502

Please sign in to comment.