wip translated ui playbar class

This commit is contained in:
Erica Z 2024-10-30 12:45:50 +01:00
parent b94d41542f
commit 6f3b3537ad
9 changed files with 264 additions and 22 deletions

View file

@ -28,6 +28,8 @@ extern "C" {}
fn main() -> glib::ExitCode { fn main() -> glib::ExitCode {
gio::resources_register_include!("audrey.gresource").expect("could not register resources"); gio::resources_register_include!("audrey.gresource").expect("could not register resources");
ui::Playbar::ensure_type();
gtk::disable_setlocale(); gtk::disable_setlocale();
bindtextdomain("audrey", meson_config::LOCALEDIR).expect("failed to bind text domain"); bindtextdomain("audrey", meson_config::LOCALEDIR).expect("failed to bind text domain");
bind_textdomain_codeset("audrey", "UTF-8").expect("failed to bind textdomaincodeset"); bind_textdomain_codeset("audrey", "UTF-8").expect("failed to bind textdomaincodeset");

View file

@ -5,7 +5,7 @@ audrey_sources = [
'playbin.vala', 'playbin.vala',
'subsonic.vala', 'subsonic.vala',
'ui/play_queue.vala', 'ui/play_queue.vala',
'ui/playbar.vala', 'ui/playbar.vapi',
'ui/setup.vala', 'ui/setup.vala',
'ui/window.vala', 'ui/window.vala',
] ]

View file

@ -1,6 +1,9 @@
mod song; mod song;
pub use song::Song; pub use song::Song;
mod state;
pub use state::State;
mod ffi { mod ffi {
use gtk::glib; use gtk::glib;

View file

@ -13,6 +13,15 @@ mod ffi {
extern "C" { extern "C" {
pub fn audrey_playbin_song_get_type() -> glib::ffi::GType; pub fn audrey_playbin_song_get_type() -> glib::ffi::GType;
pub fn audrey_playbin_song_get_title(
self_: *mut AudreyPlaybinSong,
) -> *const std::ffi::c_char;
pub fn audrey_playbin_song_get_artist(
self_: *mut AudreyPlaybinSong,
) -> *const std::ffi::c_char;
pub fn audrey_playbin_song_get_album(
self_: *mut AudreyPlaybinSong,
) -> *const std::ffi::c_char;
} }
} }
@ -25,3 +34,35 @@ glib::wrapper! {
type_ => || ffi::audrey_playbin_song_get_type(), type_ => || ffi::audrey_playbin_song_get_type(),
} }
} }
impl Song {
pub fn get_title(&self) -> std::borrow::Cow<'_, str> {
use glib::translate::ToGlibPtr;
// TODO: memory management....
String::from_utf8_lossy(unsafe {
std::ffi::CStr::from_ptr(ffi::audrey_playbin_song_get_title(self.to_glib_none().0))
.to_bytes()
})
}
pub fn get_artist(&self) -> std::borrow::Cow<'_, str> {
use glib::translate::ToGlibPtr;
// TODO: memory management....
String::from_utf8_lossy(unsafe {
std::ffi::CStr::from_ptr(ffi::audrey_playbin_song_get_artist(self.to_glib_none().0))
.to_bytes()
})
}
pub fn get_album(&self) -> std::borrow::Cow<'_, str> {
use glib::translate::ToGlibPtr;
// TODO: memory management....
String::from_utf8_lossy(unsafe {
std::ffi::CStr::from_ptr(ffi::audrey_playbin_song_get_album(self.to_glib_none().0))
.to_bytes()
})
}
}

38
src/playbin/state.rs Normal file
View file

@ -0,0 +1,38 @@
mod ffi {
use gtk::glib;
extern "C" {
pub fn audrey_playbin_state_get_type() -> glib::ffi::GType;
}
}
use gtk::glib;
use glib::prelude::*;
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum State {
Stopped,
Paused,
Playing,
}
unsafe impl<'a> glib::value::FromValue<'a> for State {
type Checker = glib::value::GenericValueTypeChecker<Self>;
unsafe fn from_value(value: &'a glib::Value) -> Self {
use glib::translate::ToGlibPtr;
match glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0) {
0 => Self::Stopped,
1 => Self::Paused,
2 => Self::Playing,
_ => unreachable!(),
}
}
}
impl StaticType for State {
fn static_type() -> glib::Type {
unsafe { glib::translate::from_glib(ffi::audrey_playbin_state_get_type()) }
}
}

View file

@ -1,6 +1,6 @@
mod ffi { mod ffi {
use std::ffi::*;
use gtk::glib; use gtk::glib;
use std::ffi::*;
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -19,7 +19,8 @@ mod ffi {
} }
extern "C" { extern "C" {
pub fn audrey_subsonic_song_copy(ptr: *const AudreySubsonicSong) -> *mut AudreySubsonicSong; pub fn audrey_subsonic_song_copy(ptr: *const AudreySubsonicSong)
-> *mut AudreySubsonicSong;
pub fn audrey_subsonic_song_free(ptr: *mut AudreySubsonicSong); pub fn audrey_subsonic_song_free(ptr: *mut AudreySubsonicSong);
pub fn audrey_subsonic_song_get_type() -> glib::ffi::GType; pub fn audrey_subsonic_song_get_type() -> glib::ffi::GType;
} }

1
src/ui/playbar.h Normal file
View file

@ -0,0 +1 @@
typedef struct _AudreyUiPlaybar AudreyUiPlaybar;

View file

@ -1,29 +1,178 @@
mod ffi { mod imp {
use gtk::glib; use adw::prelude::*;
use adw::subclass::prelude::*;
use glib::subclass::InitializingObject;
use gtk::{gdk, glib};
use std::cell::{Cell, RefCell};
#[repr(C)] #[derive(glib::Properties, gtk::CompositeTemplate, Default)]
pub struct AudreyUiPlaybar { #[properties(wrapper_type = super::Playbar)]
parent_instance: adw::ffi::AdwBin, #[template(resource = "/eu/callcc/audrey/playbar.ui")]
pub struct Playbar {
#[property(get, set)]
song: RefCell<Option<crate::playbin::Song>>,
#[property(get, set)]
playing_cover_art: RefCell<Option<gdk::Paintable>>,
#[property(get, set)]
playbin: RefCell<Option<crate::Playbin>>, // TODO: weak
#[property(get, set, default = true)]
show_cover_art: Cell<bool>,
#[property(get, set)]
volume: Cell<i32>,
} }
#[repr(C)] #[glib::object_subclass]
pub struct AudreyUiPlaybarClass { impl ObjectSubclass for Playbar {
parent_class: adw::ffi::AdwBinClass, const NAME: &'static str = "AudreyUiPlaybar";
type Type = super::Playbar;
type ParentType = adw::Bin;
fn class_init(klass: &mut Self::Class) {
klass.bind_template();
klass.bind_template_callbacks();
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
} }
extern "C" { #[glib::derived_properties]
pub fn audrey_ui_playbar_get_type() -> glib::ffi::GType; impl ObjectImpl for Playbar {}
impl WidgetImpl for Playbar {}
impl BinImpl for Playbar {}
#[gtk::template_callbacks]
impl Playbar {
#[template_callback]
fn song_title(&self, song: Option<&crate::playbin::Song>) -> String {
match song {
None => "".to_owned(),
Some(song) => song.get_title().to_string(),
}
}
#[template_callback]
fn song_artist(&self, song: Option<&crate::playbin::Song>) -> String {
match song {
None => "".to_owned(),
Some(song) => song.get_artist().to_string(),
}
}
#[template_callback]
fn song_album(&self, song: Option<&crate::playbin::Song>) -> String {
match song {
None => "".to_owned(),
Some(song) => song.get_album().to_string(),
}
}
#[template_callback]
fn format_timestamp(&self, s: f64) -> String {
format!("{:02}:{:02}", (s as i64) / 64, (s as i64) % 60)
}
#[template_callback]
fn playbin_active(&self, state: crate::playbin::State) -> bool {
state != crate::playbin::State::Stopped
}
#[template_callback]
fn can_press_play(&self, state: crate::playbin::State, n_items: u32) -> bool {
!(state == crate::playbin::State::Stopped && n_items == 0)
}
#[template_callback]
fn play_pause_icon_name(&self, state: crate::playbin::State) -> &'static str {
match state {
crate::playbin::State::Playing => "media-playback-pause",
_ => "media-playback-start",
}
}
#[template_callback]
fn mute_button_icon_name(&self, mute: bool) -> &'static str {
if mute { "audio-volume-muted" } else { "audio-volume-high" }
}
#[template_callback]
fn on_play_position_seek(&self, _range: &gtk::Range, _scroll_type: gtk::ScrollType, _value: f64) -> bool {
/*
if (range.adjustment.lower < range.adjustment.upper) {
this.playbin.seek ((int64) value);
}
return false;
*/
todo!()
}
#[template_callback]
fn on_skip_forward_clicked(&self) {
// this.playbin.go_to_next_track ();
todo!()
}
#[template_callback]
fn on_skip_backward_clicked(&self) {
// this.playbin.go_to_prev_track ();
todo!()
}
#[template_callback]
fn seek_backward(&self) {
// 10 seconds
// double new_position = playbin.position - 10.0;
// if (new_position < 0.0) new_position = 0.0;
// this.playbin.seek (new_position);
todo!()
}
#[template_callback]
fn seek_forward(&self) {
// 10 seconds
// double new_position = playbin.position + 10.0;
// if (new_position > this.playbin.duration) new_position = this.playbin.duration;
// this.playbin.seek (new_position);
todo!()
}
#[template_callback]
fn on_play_pause_clicked(&self) {
// if (this.playbin.state == PlaybinState.PLAYING) {
// this.playbin.pause();
// } else {
// this.playbin.play();
// }
todo!()
}
#[template_callback]
fn on_mute_toggle(&self) {
//this.playbin.mute = !this.playbin.mute;
todo!()
}
} }
} }
use gtk::glib; use gtk::glib;
glib::wrapper! { glib::wrapper! {
pub struct Playbar(Object<ffi::AudreyUiPlaybar, ffi::AudreyUiPlaybarClass>) pub struct Playbar(ObjectSubclass<imp::Playbar>)
@extends adw::Bin, gtk::Widget, @extends adw::Bin, gtk::Widget,
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget; @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
}
match fn { mod ffi {
type_ => || ffi::audrey_ui_playbar_get_type(), use glib::translate::IntoGlib;
use gtk::glib;
use gtk::prelude::*;
#[no_mangle]
pub extern "C" fn audrey_ui_playbar_get_type() -> glib::ffi::GType {
super::Playbar::static_type().into_glib()
} }
} }

View file

@ -1,15 +1,21 @@
[GtkTemplate (ui = "/eu/callcc/audrey/playbar.ui")] // [GtkTemplate (ui = "/eu/callcc/audrey/playbar.ui")]
class Audrey.Ui.Playbar : Adw.Bin { [CCode (cheader_filename = "ui/playbar.h")]
public PlaybinSong? song { get; set; } public class Audrey.Ui.Playbar : Adw.Bin {
public PlaybinSong? song {
get;
set;
}
public Gdk.Paintable? playing_cover_art { get; set; } public Gdk.Paintable? playing_cover_art { get; set; }
public weak Playbin playbin { get; set; } public weak Playbin playbin { get; set; }
public bool show_cover_art { get; set; default = true; } public bool show_cover_art { get; set; /*default = true;*/ }
public int volume { public int volume { get; set; }
/*{
get { return playbin == null ? 100 : playbin.volume; } get { return playbin == null ? 100 : playbin.volume; }
set { playbin.volume = value; } set { playbin.volume = value; }
} }*/
/*
[GtkCallback] private string format_timestamp (double s) { [GtkCallback] private string format_timestamp (double s) {
return "%02d:%02d".printf (((int) s)/60, ((int) s)%60); return "%02d:%02d".printf (((int) s)/60, ((int) s)%60);
} }
@ -90,4 +96,5 @@ class Audrey.Ui.Playbar : Adw.Bin {
~Playbar () { ~Playbar () {
debug ("destroying playbar widget"); debug ("destroying playbar widget");
} }
*/
} }