2023-04-10 00:17:52 +01:00
|
|
|
use super::{try_get_orientation, CustomWidget, CustomWidgetContext, ExecEvent};
|
2023-04-10 13:51:07 +01:00
|
|
|
use crate::modules::custom::set_length;
|
2023-04-09 22:42:35 +01:00
|
|
|
use crate::popup::Popup;
|
|
|
|
use crate::script::{OutputStream, Script, ScriptInput};
|
2023-04-10 13:51:07 +01:00
|
|
|
use crate::{build, send, try_send};
|
2023-04-09 22:42:35 +01:00
|
|
|
use gtk::prelude::*;
|
2023-04-10 13:51:07 +01:00
|
|
|
use gtk::Scale;
|
2023-04-09 22:42:35 +01:00
|
|
|
use serde::Deserialize;
|
|
|
|
use std::cell::Cell;
|
2023-04-22 21:23:33 +01:00
|
|
|
use std::ops::Neg;
|
2023-04-09 22:42:35 +01:00
|
|
|
use tokio::spawn;
|
|
|
|
use tracing::error;
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize, Clone)]
|
|
|
|
pub struct SliderWidget {
|
|
|
|
name: Option<String>,
|
|
|
|
class: Option<String>,
|
|
|
|
orientation: Option<String>,
|
|
|
|
value: Option<ScriptInput>,
|
|
|
|
on_change: Option<String>,
|
|
|
|
#[serde(default = "default_min")]
|
|
|
|
min: f64,
|
|
|
|
#[serde(default = "default_max")]
|
|
|
|
max: f64,
|
2023-04-22 21:23:33 +01:00
|
|
|
step: Option<f64>,
|
2023-04-09 22:42:35 +01:00
|
|
|
length: Option<i32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
const fn default_min() -> f64 {
|
|
|
|
0.0
|
|
|
|
}
|
|
|
|
|
|
|
|
const fn default_max() -> f64 {
|
|
|
|
100.0
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CustomWidget for SliderWidget {
|
|
|
|
type Widget = Scale;
|
|
|
|
|
|
|
|
fn into_widget(self, context: CustomWidgetContext) -> Self::Widget {
|
2023-04-10 13:51:07 +01:00
|
|
|
let scale = build!(self, Self::Widget);
|
2023-04-09 22:42:35 +01:00
|
|
|
|
|
|
|
if let Some(orientation) = self.orientation {
|
2023-04-10 13:51:07 +01:00
|
|
|
scale.set_orientation(
|
|
|
|
try_get_orientation(&orientation).unwrap_or(context.bar_orientation),
|
|
|
|
);
|
2023-04-09 22:42:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(length) = self.length {
|
2023-04-10 13:51:07 +01:00
|
|
|
set_length(&scale, length, context.bar_orientation);
|
2023-04-09 22:42:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
scale.set_range(self.min, self.max);
|
|
|
|
|
|
|
|
if let Some(on_change) = self.on_change {
|
|
|
|
let min = self.min;
|
|
|
|
let max = self.max;
|
2023-04-22 21:23:33 +01:00
|
|
|
let step = self.step;
|
2023-04-09 22:42:35 +01:00
|
|
|
let tx = context.tx.clone();
|
|
|
|
|
|
|
|
// GTK will spam the same value over and over
|
|
|
|
let prev_value = Cell::new(scale.value());
|
|
|
|
|
2023-04-22 21:23:33 +01:00
|
|
|
scale.connect_scroll_event(move |scale, event| {
|
|
|
|
let value = scale.value();
|
|
|
|
let delta = event.delta().1.neg();
|
|
|
|
|
|
|
|
let delta = match (step, delta.is_sign_positive()) {
|
|
|
|
(Some(step), true) => step,
|
|
|
|
(Some(step), false) => -step,
|
|
|
|
(None, _) => delta,
|
|
|
|
};
|
|
|
|
|
|
|
|
scale.set_value(value + delta);
|
|
|
|
Inhibit(false)
|
|
|
|
});
|
|
|
|
|
2023-04-09 22:42:35 +01:00
|
|
|
scale.connect_change_value(move |scale, _, val| {
|
|
|
|
// GTK will send values outside min/max range
|
2023-04-10 20:04:59 +01:00
|
|
|
let val = val.clamp(min, max);
|
2023-04-09 22:42:35 +01:00
|
|
|
|
|
|
|
if val != prev_value.get() {
|
|
|
|
try_send!(
|
|
|
|
tx,
|
|
|
|
ExecEvent {
|
|
|
|
cmd: on_change.clone(),
|
|
|
|
args: Some(vec![val.to_string()]),
|
|
|
|
geometry: Popup::widget_geometry(scale, context.bar_orientation),
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
prev_value.set(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
Inhibit(false)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(value) = self.value {
|
|
|
|
let script = Script::from(value);
|
|
|
|
let scale = scale.clone();
|
|
|
|
|
|
|
|
let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
|
|
|
|
|
|
|
spawn(async move {
|
|
|
|
script
|
|
|
|
.run(None, move |stream, _success| match stream {
|
|
|
|
OutputStream::Stdout(out) => match out.parse() {
|
|
|
|
Ok(value) => send!(tx, value),
|
|
|
|
Err(err) => error!("{err:?}"),
|
|
|
|
},
|
|
|
|
OutputStream::Stderr(err) => error!("{err:?}"),
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
});
|
|
|
|
|
|
|
|
rx.attach(None, move |value| {
|
|
|
|
scale.set_value(value);
|
|
|
|
Continue(true)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
scale
|
|
|
|
}
|
|
|
|
}
|