219 lines
7.3 KiB
Rust
219 lines
7.3 KiB
Rust
use crate::{
|
|
command::CommandRowState,
|
|
daemon::{CommandState, Handle},
|
|
};
|
|
use futures_util::stream::StreamExt;
|
|
use gtk::{prelude::*, subclass::prelude::*};
|
|
use marble::widgets::Dialog;
|
|
use std::{cell::RefCell, rc::Rc};
|
|
use streamdeck_common::{Command, Input};
|
|
|
|
glib::wrapper! {
|
|
pub struct CommandRow(ObjectSubclass<imp::CommandRow>)
|
|
@extends gtk::ListBoxRow, gtk::Bin, gtk::Container, gtk::Widget;
|
|
}
|
|
|
|
impl CommandRow {
|
|
pub(crate) fn new(serial_number: &str, command_state: CommandState) -> Self {
|
|
let this = glib::Object::new(&[]).expect("Failed to create Command Row");
|
|
|
|
let inner = imp::CommandRow::from_instance(&this);
|
|
inner.serial_number.set(serial_number.to_owned()).unwrap();
|
|
|
|
let row_title = inner.row_title.get().unwrap();
|
|
if row_title.label() == "" {
|
|
row_title.set_label(&command_state.name());
|
|
}
|
|
|
|
let command_grid = inner.command_grid.get().unwrap();
|
|
|
|
let row_state = CommandRowState::build(&command_state.command(), command_grid);
|
|
inner.row_state.set(row_state).unwrap();
|
|
|
|
inner.input_key.set(command_state.keys()).unwrap();
|
|
inner
|
|
.command
|
|
.set(Rc::new(RefCell::new(command_state.command())))
|
|
.unwrap();
|
|
|
|
let stream = command_state.clone().name_stream();
|
|
let weak = this.downgrade();
|
|
glib::MainContext::default().spawn_local(async move {
|
|
futures_util::pin_mut!(stream);
|
|
|
|
while let Some(name) = stream.next().await {
|
|
if let Some(this) = weak.upgrade() {
|
|
this.set_name(&name);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
let stream = command_state.command_stream();
|
|
let weak = this.downgrade();
|
|
glib::MainContext::default().spawn_local(async move {
|
|
futures_util::pin_mut!(stream);
|
|
|
|
while let Some(command) = stream.next().await {
|
|
if let Some(this) = weak.upgrade() {
|
|
this.set_command(command);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
this.show_all();
|
|
this
|
|
}
|
|
|
|
pub(crate) fn set_command(&self, command: Command) {
|
|
let inner = imp::CommandRow::from_instance(self);
|
|
let row_state = inner.row_state.get().unwrap();
|
|
row_state.update_command(&command);
|
|
}
|
|
|
|
pub(crate) fn set_name(&self, name: &str) {
|
|
let this = imp::CommandRow::from_instance(self);
|
|
let row_title = this.row_title.get().unwrap();
|
|
row_title.set_label(name);
|
|
}
|
|
|
|
pub(crate) fn serial_number(&self) -> String {
|
|
let this = imp::CommandRow::from_instance(self);
|
|
let serial_number = this.serial_number.get().unwrap();
|
|
serial_number.clone()
|
|
}
|
|
|
|
pub(crate) fn input_keys(&self) -> Input {
|
|
let this = imp::CommandRow::from_instance(self);
|
|
let input_keys = this.input_key.get().unwrap();
|
|
input_keys.clone()
|
|
}
|
|
|
|
fn present_dialog(&self) {
|
|
let this = imp::CommandRow::from_instance(self);
|
|
let mut dialog_opt = this.dialog.borrow_mut();
|
|
|
|
let dialog: Dialog = if let Some(dialog) = &*dialog_opt {
|
|
dialog.clone()
|
|
} else {
|
|
let command_state = if let Some(deck_state) =
|
|
Handle::current().state().deck_state(&self.serial_number())
|
|
{
|
|
if let Some(command_state) = deck_state.command_state(self.input_keys()) {
|
|
command_state
|
|
} else {
|
|
return;
|
|
}
|
|
} else {
|
|
return;
|
|
};
|
|
|
|
let dialog =
|
|
crate::dialogs::edit_command_dialog::build(&self.serial_number(), command_state);
|
|
|
|
dialog.set_transient_for(
|
|
self.toplevel()
|
|
.and_then(|widget| widget.downcast::<crate::main_window::MainWindow>().ok())
|
|
.as_ref(),
|
|
);
|
|
|
|
*dialog_opt = Some(dialog.clone());
|
|
|
|
dialog.connect_response(glib::clone!(@weak self as obj => move |_, response_type| {
|
|
if response_type == gtk::ResponseType::Reject {
|
|
if let Some(main_window) = obj.toplevel().and_then(|widget| widget.downcast::<crate::main_window::MainWindow>().ok()) {
|
|
main_window.to_obs();
|
|
}
|
|
}
|
|
|
|
let this = imp::CommandRow::from_instance(&obj);
|
|
let mut dialog_opt = this.dialog.borrow_mut();
|
|
if let Some(dialog) = dialog_opt.take() {
|
|
dialog.close();
|
|
}
|
|
}));
|
|
|
|
dialog
|
|
};
|
|
|
|
dialog.present();
|
|
}
|
|
}
|
|
|
|
mod imp {
|
|
use crate::command::CommandRowState;
|
|
use gtk::{prelude::*, subclass::prelude::*};
|
|
use marble::widgets::Dialog;
|
|
use once_cell::unsync::OnceCell;
|
|
use std::{cell::RefCell, rc::Rc};
|
|
use streamdeck_common::{Command, Input};
|
|
|
|
#[derive(Debug, Default)]
|
|
pub struct CommandRow {
|
|
pub(super) row_title: OnceCell<gtk::Label>,
|
|
pub(super) command_grid: OnceCell<gtk::Grid>,
|
|
pub(super) serial_number: OnceCell<String>,
|
|
pub(super) input_key: OnceCell<Input>,
|
|
pub(super) command: OnceCell<Rc<RefCell<Command>>>,
|
|
pub(super) row_state: OnceCell<CommandRowState>,
|
|
pub(super) dialog: RefCell<Option<Dialog>>,
|
|
}
|
|
|
|
#[glib::object_subclass]
|
|
impl ObjectSubclass for CommandRow {
|
|
const NAME: &'static str = "CommandRow";
|
|
type Type = super::CommandRow;
|
|
type ParentType = gtk::ListBoxRow;
|
|
}
|
|
|
|
impl ObjectImpl for CommandRow {
|
|
fn constructed(&self, obj: &Self::Type) {
|
|
let row_title = gtk::Label::new(None);
|
|
row_title.set_halign(gtk::Align::Start);
|
|
row_title.set_valign(gtk::Align::Center);
|
|
|
|
let command_grid = gtk::Grid::new();
|
|
command_grid.set_halign(gtk::Align::Start);
|
|
command_grid.set_valign(gtk::Align::Center);
|
|
command_grid.set_orientation(gtk::Orientation::Horizontal);
|
|
command_grid.set_margin(0);
|
|
command_grid.set_margin_start(3);
|
|
command_grid.set_column_spacing(3);
|
|
|
|
let row_edit =
|
|
gtk::Button::from_icon_name(Some("document-edit"), gtk::IconSize::Button);
|
|
row_edit.set_tooltip_text(Some("Edit"));
|
|
row_edit.set_halign(gtk::Align::End);
|
|
row_edit.set_valign(gtk::Align::Center);
|
|
row_edit.set_expand(true);
|
|
|
|
let row_grid = gtk::Grid::new();
|
|
row_grid.set_orientation(gtk::Orientation::Horizontal);
|
|
row_grid.set_margin(6);
|
|
row_grid.set_margin_start(3);
|
|
row_grid.set_column_spacing(12);
|
|
|
|
row_grid.add(&row_title);
|
|
row_grid.add(&command_grid);
|
|
row_grid.add(&row_edit);
|
|
|
|
obj.add(&row_grid);
|
|
obj.show_all();
|
|
|
|
self.row_title.set(row_title).unwrap();
|
|
self.command_grid.set(command_grid).unwrap();
|
|
|
|
row_edit.connect_clicked(glib::clone!(@weak obj => move |_| {
|
|
obj.present_dialog();
|
|
}));
|
|
}
|
|
}
|
|
impl WidgetImpl for CommandRow {}
|
|
impl ContainerImpl for CommandRow {}
|
|
impl BinImpl for CommandRow {}
|
|
impl ListBoxRowImpl for CommandRow {}
|
|
}
|