implement attribute type conversions
This commit is contained in:
parent
2155ec0fd8
commit
aefa9016f1
8 changed files with 146 additions and 52 deletions
36
Cargo.lock
generated
36
Cargo.lock
generated
|
@ -156,6 +156,16 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "calloop"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59561a8b3968ba4bda0c46f42e0568507c5d26e94c3b6f2a0c730cbecd83ff3a"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"nix",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.60"
|
version = "1.0.60"
|
||||||
|
@ -312,6 +322,8 @@ name = "eww"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"calloop",
|
||||||
|
"crossbeam-channel",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"extend",
|
"extend",
|
||||||
"gdk",
|
"gdk",
|
||||||
|
@ -320,9 +332,9 @@ dependencies = [
|
||||||
"grass",
|
"grass",
|
||||||
"gtk",
|
"gtk",
|
||||||
"hocon",
|
"hocon",
|
||||||
|
"hotwatch",
|
||||||
"ipc-channel",
|
"ipc-channel",
|
||||||
"maplit",
|
"maplit",
|
||||||
"notify",
|
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -798,6 +810,16 @@ dependencies = [
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hotwatch"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba0add391e9cd7d19c29024617a44df79c867ab003bce7f3224c1636595ec740"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"notify",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
|
@ -1002,6 +1024,18 @@ dependencies = [
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "4.2.3"
|
version = "4.2.3"
|
||||||
|
|
|
@ -23,7 +23,9 @@ ipc-channel="0.14.1"
|
||||||
serde = {version = "1.0", features = ["derive"]}
|
serde = {version = "1.0", features = ["derive"]}
|
||||||
extend = "0.3.0"
|
extend = "0.3.0"
|
||||||
grass = "0.10"
|
grass = "0.10"
|
||||||
notify = "4.0"
|
hotwatch = "0.4"
|
||||||
|
calloop = "0.6"
|
||||||
|
crossbeam-channel = "0.4"
|
||||||
|
|
||||||
#thiserror = "1.0"
|
#thiserror = "1.0"
|
||||||
|
|
||||||
|
|
|
@ -108,5 +108,6 @@ impl EwwWindowDefinition {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_hocon(s: &str) -> Result<Hocon> {
|
pub fn parse_hocon(s: &str) -> Result<Hocon> {
|
||||||
Ok(HoconLoader::new().load_str(s)?.hocon()?)
|
let s = s.trim();
|
||||||
|
Ok(HoconLoader::new().strict().load_str(s)?.hocon()?)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
|
use anyhow::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
use crate::value::{AttrValue, PrimitiveValue};
|
use crate::value::{AttrValue, CommandPollingUse, PrimitiveValue};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct EwwState {
|
pub struct EwwState {
|
||||||
on_change_handlers: HashMap<String, Vec<Box<dyn Fn(PrimitiveValue) + 'static>>>,
|
on_change_handlers: HashMap<String, Vec<Box<dyn Fn(PrimitiveValue) + 'static>>>,
|
||||||
|
polling_commands: Vec<(CommandPollingUse, Box<dyn Fn(PrimitiveValue) + 'static>)>,
|
||||||
state: HashMap<String, PrimitiveValue>,
|
state: HashMap<String, PrimitiveValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +57,13 @@ impl EwwState {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AttrValue::CommandPolling(command_polling_use) => {
|
||||||
|
self.polling_commands
|
||||||
|
.push((command_polling_use.clone(), Box::new(set_value.clone())));
|
||||||
|
// TODO how do i handle commands needing to be run on the first resolve? this is an issue,....
|
||||||
|
//self.resolve(local_env, &value.into(), set_value);
|
||||||
|
true
|
||||||
|
}
|
||||||
AttrValue::Concrete(value) => {
|
AttrValue::Concrete(value) => {
|
||||||
set_value(value.clone());
|
set_value(value.clone());
|
||||||
true
|
true
|
||||||
|
@ -112,3 +122,8 @@ impl EwwState {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run_command(cmd: &str) -> Result<PrimitiveValue> {
|
||||||
|
let output = String::from_utf8(Command::new("/bin/bash").arg("-c").arg(cmd).output()?.stdout)?;
|
||||||
|
Ok(PrimitiveValue::from(output))
|
||||||
|
}
|
||||||
|
|
54
src/main.rs
54
src/main.rs
|
@ -5,11 +5,9 @@ extern crate gtk;
|
||||||
|
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use gdk::*;
|
use gdk::*;
|
||||||
use gio::prelude::*;
|
|
||||||
use grass;
|
use grass;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use ipc_channel::ipc;
|
use ipc_channel::ipc;
|
||||||
use notify::{self, Watcher};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path;
|
use std::path;
|
||||||
|
@ -21,6 +19,7 @@ pub mod value;
|
||||||
pub mod widgets;
|
pub mod widgets;
|
||||||
|
|
||||||
use eww_state::*;
|
use eww_state::*;
|
||||||
|
use hotwatch;
|
||||||
use value::PrimitiveValue;
|
use value::PrimitiveValue;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -98,11 +97,18 @@ fn initialize_server(opts: Opt) -> Result<()> {
|
||||||
.to_path_buf();
|
.to_path_buf();
|
||||||
let scss_file_path = config_dir.join("eww.scss");
|
let scss_file_path = config_dir.join("eww.scss");
|
||||||
|
|
||||||
let (watcher_tx, watcher_rx) = std::sync::mpsc::channel();
|
let (watcher_tx, watcher_rx) = crossbeam_channel::unbounded();
|
||||||
|
|
||||||
let mut file_watcher = notify::watcher(watcher_tx, std::time::Duration::from_millis(100))?;
|
let mut hotwatch = hotwatch::Hotwatch::new()?;
|
||||||
file_watcher.watch(config_file_path.clone(), notify::RecursiveMode::NonRecursive)?;
|
hotwatch.watch(
|
||||||
if let Err(e) = file_watcher.watch(scss_file_path.clone(), notify::RecursiveMode::NonRecursive) {
|
config_file_path.clone(),
|
||||||
|
glib::clone!(@strong watcher_tx => move |evt| watcher_tx.send(evt).unwrap()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if let Err(e) = hotwatch.watch(
|
||||||
|
scss_file_path.clone(),
|
||||||
|
glib::clone!(@strong watcher_tx => move |evt| watcher_tx.send(evt).unwrap()),
|
||||||
|
) {
|
||||||
eprintln!("WARN: error while loading CSS file for hot-reloading: \n{}", e)
|
eprintln!("WARN: error while loading CSS file for hot-reloading: \n{}", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,20 +119,21 @@ fn initialize_server(opts: Opt) -> Result<()> {
|
||||||
let eww_css =
|
let eww_css =
|
||||||
grass::from_string(scss_content, &grass::Options::default()).map_err(|err| anyhow!("SCSS parsing error: {:?}", err))?;
|
grass::from_string(scss_content, &grass::Options::default()).map_err(|err| anyhow!("SCSS parsing error: {:?}", err))?;
|
||||||
|
|
||||||
|
gtk::init()?;
|
||||||
|
|
||||||
let mut app = App {
|
let mut app = App {
|
||||||
eww_state: EwwState::from_default_vars(eww_config.get_default_vars().clone()),
|
eww_state: EwwState::from_default_vars(eww_config.get_default_vars().clone()),
|
||||||
eww_config,
|
eww_config,
|
||||||
eww_css: eww_css.clone(),
|
eww_css: eww_css.clone(),
|
||||||
windows: HashMap::new(),
|
windows: HashMap::new(),
|
||||||
|
css_provider: gtk::CssProvider::new(),
|
||||||
};
|
};
|
||||||
gtk::init()?;
|
|
||||||
|
|
||||||
let css_provider = gtk::CssProvider::new();
|
|
||||||
css_provider.load_from_data(eww_css.as_bytes())?;
|
|
||||||
gdk::Screen::get_default().map(|screen| {
|
gdk::Screen::get_default().map(|screen| {
|
||||||
gtk::StyleContext::add_provider_for_screen(&screen, &css_provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION);
|
gtk::StyleContext::add_provider_for_screen(&screen, &app.css_provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.load_css(&eww_css)?;
|
||||||
app.handle_user_command(opts)?;
|
app.handle_user_command(opts)?;
|
||||||
|
|
||||||
let (send, recv) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
let (send, recv) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
||||||
|
@ -152,15 +159,13 @@ fn initialize_server(opts: Opt) -> Result<()> {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
while let Ok(event) = watcher_rx.recv() {
|
while let Ok(event) = watcher_rx.recv() {
|
||||||
let result: Result<_> = try {
|
let result: Result<_> = try {
|
||||||
dbg!(&event);
|
|
||||||
match event {
|
match event {
|
||||||
notify::DebouncedEvent::Write(updated_path) | notify::DebouncedEvent::NoticeWrite(updated_path)
|
hotwatch::Event::Write(path) | hotwatch::Event::NoticeWrite(path) if path == config_file_path => {
|
||||||
if updated_path == config_file_path =>
|
let config_content = std::fs::read_to_string(path).unwrap_or_default();
|
||||||
{
|
|
||||||
let new_eww_config = config::EwwConfig::from_hocon(&config::parse_hocon(&config_content)?)?;
|
let new_eww_config = config::EwwConfig::from_hocon(&config::parse_hocon(&config_content)?)?;
|
||||||
send.send(EwwEvent::ReloadConfig(new_eww_config))?;
|
send.send(EwwEvent::ReloadConfig(new_eww_config))?;
|
||||||
}
|
}
|
||||||
notify::DebouncedEvent::Write(updated_path) if updated_path == scss_file_path => {
|
hotwatch::Event::Write(path) if path == scss_file_path => {
|
||||||
let scss_content = std::fs::read_to_string(scss_file_path.clone()).unwrap_or_default();
|
let scss_content = std::fs::read_to_string(scss_file_path.clone()).unwrap_or_default();
|
||||||
let eww_css = grass::from_string(scss_content, &grass::Options::default())
|
let eww_css = grass::from_string(scss_content, &grass::Options::default())
|
||||||
.map_err(|err| anyhow!("SCSS parsing error: {:?}", err))?;
|
.map_err(|err| anyhow!("SCSS parsing error: {:?}", err))?;
|
||||||
|
@ -170,8 +175,7 @@ fn initialize_server(opts: Opt) -> Result<()> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
eprintln!("error in server thread: {}", err);
|
eprintln!("error in file watcher thread: {}", err);
|
||||||
std::process::exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -192,6 +196,7 @@ struct App {
|
||||||
eww_config: config::EwwConfig,
|
eww_config: config::EwwConfig,
|
||||||
eww_css: String,
|
eww_css: String,
|
||||||
windows: HashMap<String, gtk::Window>,
|
windows: HashMap<String, gtk::Window>,
|
||||||
|
css_provider: gtk::CssProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
|
@ -231,7 +236,9 @@ impl App {
|
||||||
window.set_type_hint(gdk::WindowTypeHint::Dock);
|
window.set_type_hint(gdk::WindowTypeHint::Dock);
|
||||||
window.set_position(gtk::WindowPosition::Center);
|
window.set_position(gtk::WindowPosition::Center);
|
||||||
window.set_default_size(window_def.size.0, window_def.size.1);
|
window.set_default_size(window_def.size.0, window_def.size.1);
|
||||||
|
window.set_size_request(window_def.size.0, window_def.size.1);
|
||||||
window.set_decorated(false);
|
window.set_decorated(false);
|
||||||
|
window.set_resizable(false);
|
||||||
|
|
||||||
let empty_local_state = HashMap::new();
|
let empty_local_state = HashMap::new();
|
||||||
let root_widget = &widgets::element_to_gtk_thing(
|
let root_widget = &widgets::element_to_gtk_thing(
|
||||||
|
@ -259,18 +266,21 @@ impl App {
|
||||||
|
|
||||||
fn reload_all_windows(&mut self, config: config::EwwConfig) -> Result<()> {
|
fn reload_all_windows(&mut self, config: config::EwwConfig) -> Result<()> {
|
||||||
self.eww_config = config;
|
self.eww_config = config;
|
||||||
|
|
||||||
let windows = self.windows.clone();
|
let windows = self.windows.clone();
|
||||||
for (window_name, window) in windows {
|
for (window_name, window) in windows {
|
||||||
dbg!(&window_name);
|
|
||||||
window.close();
|
window.close();
|
||||||
window.hide();
|
|
||||||
self.open_window(&window_name)?;
|
self.open_window(&window_name)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reload_css(&mut self, css: String) -> Result<()> {
|
fn load_css(&mut self, css: &str) -> Result<()> {
|
||||||
for window in self.windows.values() {}
|
self.css_provider.load_from_data(css.as_bytes())?;
|
||||||
|
//self.css_provider.load_from_data(eww_css.as_bytes())?;
|
||||||
|
//gdk::Screen::get_default().map(|screen| {
|
||||||
|
//gtk::StyleContext::add_provider_for_screen(&screen, &self.css_provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||||
|
//});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +289,7 @@ impl App {
|
||||||
match event {
|
match event {
|
||||||
EwwEvent::UserCommand(command) => self.handle_user_command(command)?,
|
EwwEvent::UserCommand(command) => self.handle_user_command(command)?,
|
||||||
EwwEvent::ReloadConfig(config) => self.reload_all_windows(config)?,
|
EwwEvent::ReloadConfig(config) => self.reload_all_windows(config)?,
|
||||||
EwwEvent::ReloadCss(css) => self.reload_css(css)?,
|
EwwEvent::ReloadCss(css) => self.load_css(&css)?,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
|
|
58
src/value.rs
58
src/value.rs
|
@ -12,6 +12,12 @@ pub enum PrimitiveValue {
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
pub struct PollingCommandValue {
|
||||||
|
command: String,
|
||||||
|
interval: std::time::Duration,
|
||||||
|
}
|
||||||
|
|
||||||
impl std::str::FromStr for PrimitiveValue {
|
impl std::str::FromStr for PrimitiveValue {
|
||||||
type Err = anyhow::Error;
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
|
@ -30,28 +36,21 @@ fn remove_surrounding(s: &str, surround: char) -> &str {
|
||||||
impl TryFrom<PrimitiveValue> for String {
|
impl TryFrom<PrimitiveValue> for String {
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
fn try_from(x: PrimitiveValue) -> Result<Self> {
|
fn try_from(x: PrimitiveValue) -> Result<Self> {
|
||||||
match x {
|
x.as_string()
|
||||||
PrimitiveValue::String(x) => Ok(x),
|
|
||||||
_ => return Err(anyhow!("'{:?}' is not a string", x.clone())),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<PrimitiveValue> for f64 {
|
impl TryFrom<PrimitiveValue> for f64 {
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
fn try_from(x: PrimitiveValue) -> Result<Self> {
|
fn try_from(x: PrimitiveValue) -> Result<Self> {
|
||||||
try_match!(PrimitiveValue::Number(x) = &x)
|
x.as_f64()
|
||||||
.map_err(|_| anyhow!("'{:?}' is not a number", &x))
|
|
||||||
.map(|&x| x)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<PrimitiveValue> for bool {
|
impl TryFrom<PrimitiveValue> for bool {
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
fn try_from(x: PrimitiveValue) -> Result<Self> {
|
fn try_from(x: PrimitiveValue) -> Result<Self> {
|
||||||
try_match!(PrimitiveValue::Boolean(x) = &x)
|
x.as_bool()
|
||||||
.map_err(|_| anyhow!("'{:?}' is not a bool", &x))
|
|
||||||
.map(|&x| x)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,18 +61,30 @@ impl From<&str> for PrimitiveValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrimitiveValue {
|
impl PrimitiveValue {
|
||||||
pub fn as_string(&self) -> Result<&String> {
|
pub fn as_string(&self) -> Result<String> {
|
||||||
try_match!(PrimitiveValue::String(x) = self).map_err(|x| anyhow!("{:?} is not a string", x))
|
match self {
|
||||||
|
PrimitiveValue::String(x) => Ok(x.clone()),
|
||||||
|
PrimitiveValue::Number(x) => Ok(format!("{}", x)),
|
||||||
|
PrimitiveValue::Boolean(x) => Ok(format!("{}", x)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn as_f64(&self) -> Result<f64> {
|
pub fn as_f64(&self) -> Result<f64> {
|
||||||
try_match!(PrimitiveValue::Number(x) = self)
|
match self {
|
||||||
.map_err(|x| anyhow!("{:?} is not an f64", x))
|
PrimitiveValue::Number(x) => Ok(*x),
|
||||||
.map(|&x| x)
|
PrimitiveValue::String(x) => x
|
||||||
|
.parse()
|
||||||
|
.map_err(|e| anyhow!("couldn't convert string {:?} to f64: {}", &self, e)),
|
||||||
|
_ => Err(anyhow!("{:?} is not an f64", &self)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn as_bool(&self) -> Result<bool> {
|
pub fn as_bool(&self) -> Result<bool> {
|
||||||
try_match!(PrimitiveValue::Boolean(x) = self)
|
match self {
|
||||||
.map_err(|x| anyhow!("{:?} is not a bool", x))
|
PrimitiveValue::Boolean(x) => Ok(*x),
|
||||||
.map(|&x| x)
|
PrimitiveValue::String(x) => x
|
||||||
|
.parse()
|
||||||
|
.map_err(|e| anyhow!("couldn't convert string {:?} to bool: {}", &self, e)),
|
||||||
|
_ => Err(anyhow!("{:?} is not a string", &self)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +99,7 @@ impl std::convert::TryFrom<&Hocon> for PrimitiveValue {
|
||||||
Hocon::Integer(n) => PrimitiveValue::Number(*n as f64),
|
Hocon::Integer(n) => PrimitiveValue::Number(*n as f64),
|
||||||
Hocon::Real(n) => PrimitiveValue::Number(*n as f64),
|
Hocon::Real(n) => PrimitiveValue::Number(*n as f64),
|
||||||
Hocon::Boolean(b) => PrimitiveValue::Boolean(*b),
|
Hocon::Boolean(b) => PrimitiveValue::Boolean(*b),
|
||||||
_ => return Err(anyhow!("cannot convert {} to config::PrimitiveValue")),
|
_ => return Err(anyhow!("cannot convert {} to config::ConcreteValue")),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,10 +108,17 @@ impl std::convert::TryFrom<&Hocon> for PrimitiveValue {
|
||||||
pub enum AttrValue {
|
pub enum AttrValue {
|
||||||
Concrete(PrimitiveValue),
|
Concrete(PrimitiveValue),
|
||||||
VarRef(String),
|
VarRef(String),
|
||||||
|
CommandPolling(CommandPollingUse),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct CommandPollingUse {
|
||||||
|
command: String,
|
||||||
|
interval: std::time::Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AttrValue {
|
impl AttrValue {
|
||||||
pub fn as_string(&self) -> Result<&String> {
|
pub fn as_string(&self) -> Result<String> {
|
||||||
try_match!(AttrValue::Concrete(x) = self)
|
try_match!(AttrValue::Concrete(x) = self)
|
||||||
.map_err(|e| anyhow!("{:?} is not a string", e))?
|
.map_err(|e| anyhow!("{:?} is not a string", e))?
|
||||||
.as_string()
|
.as_string()
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub fn element_to_gtk_thing(
|
||||||
element: &element::ElementUse,
|
element: &element::ElementUse,
|
||||||
) -> Result<gtk::Widget> {
|
) -> Result<gtk::Widget> {
|
||||||
match element {
|
match element {
|
||||||
element::ElementUse::Text(text) => Ok(gtk::Label::new(Some(text.as_string()?)).upcast()), // TODO this should use resolve
|
element::ElementUse::Text(text) => Ok(gtk::Label::new(Some(&text.as_string()?)).upcast()), // TODO this should use resolve
|
||||||
element::ElementUse::Widget(widget) => {
|
element::ElementUse::Widget(widget) => {
|
||||||
let gtk_container = build_gtk_widget(widget_definitions, eww_state, local_env, widget)?;
|
let gtk_container = build_gtk_widget(widget_definitions, eww_state, local_env, widget)?;
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@ pub(super) fn resolve_widget_attrs(bargs: &mut BuilderArgs, gtk_widget: >k::Wi
|
||||||
resolve!(bargs, gtk_widget, {
|
resolve!(bargs, gtk_widget, {
|
||||||
resolve_str => "class" => |v| gtk_widget.get_style_context().add_class(&v),
|
resolve_str => "class" => |v| gtk_widget.get_style_context().add_class(&v),
|
||||||
resolve_bool => "active" = true => |v| gtk_widget.set_sensitive(v),
|
resolve_bool => "active" = true => |v| gtk_widget.set_sensitive(v),
|
||||||
|
resolve_str => "valign" => |v| gtk_widget.set_valign(parse_align(&v)),
|
||||||
|
resolve_str => "halign" => |v| gtk_widget.set_halign(parse_align(&v)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,9 +53,9 @@ pub(super) fn resolve_orientable_attrs(bargs: &mut BuilderArgs, gtk_widget: >k
|
||||||
|
|
||||||
pub(super) fn widget_to_gtk_widget(bargs: &mut BuilderArgs) -> Result<Option<gtk::Widget>> {
|
pub(super) fn widget_to_gtk_widget(bargs: &mut BuilderArgs) -> Result<Option<gtk::Widget>> {
|
||||||
let gtk_widget = match bargs.widget.name.as_str() {
|
let gtk_widget = match bargs.widget.name.as_str() {
|
||||||
|
"layout" => build_gtk_layout(bargs)?.upcast(),
|
||||||
"slider" => build_gtk_scale(bargs)?.upcast(),
|
"slider" => build_gtk_scale(bargs)?.upcast(),
|
||||||
"image" => build_gtk_image(bargs)?.upcast(),
|
"image" => build_gtk_image(bargs)?.upcast(),
|
||||||
"layout" => build_gtk_layout(bargs)?.upcast(),
|
|
||||||
"button" => build_gtk_button(bargs)?.upcast(),
|
"button" => build_gtk_button(bargs)?.upcast(),
|
||||||
"label" => build_gtk_label(bargs)?.upcast(),
|
"label" => build_gtk_label(bargs)?.upcast(),
|
||||||
_ => return Ok(None),
|
_ => return Ok(None),
|
||||||
|
@ -69,7 +71,8 @@ fn build_gtk_scale(bargs: &mut BuilderArgs) -> Result<gtk::Scale> {
|
||||||
Some(>k::Adjustment::new(0.0, 0.0, 100.0, 1.0, 1.0, 1.0)),
|
Some(>k::Adjustment::new(0.0, 0.0, 100.0, 1.0, 1.0, 1.0)),
|
||||||
);
|
);
|
||||||
resolve!(bargs, gtk_widget, {
|
resolve!(bargs, gtk_widget, {
|
||||||
resolve_bool => "flipped" => |v| gtk_widget.set_inverted(v)
|
resolve_bool => "flipped" => |v| gtk_widget.set_inverted(v),
|
||||||
|
resolve_bool => "draw-value" = false => |v| gtk_widget.set_draw_value(v),
|
||||||
});
|
});
|
||||||
Ok(gtk_widget)
|
Ok(gtk_widget)
|
||||||
}
|
}
|
||||||
|
@ -94,9 +97,9 @@ fn build_gtk_image(bargs: &mut BuilderArgs) -> Result<gtk::Image> {
|
||||||
fn build_gtk_layout(bargs: &mut BuilderArgs) -> Result<gtk::Box> {
|
fn build_gtk_layout(bargs: &mut BuilderArgs) -> Result<gtk::Box> {
|
||||||
let gtk_widget = gtk::Box::new(gtk::Orientation::Horizontal, 0);
|
let gtk_widget = gtk::Box::new(gtk::Orientation::Horizontal, 0);
|
||||||
resolve!(bargs, gtk_widget, {
|
resolve!(bargs, gtk_widget, {
|
||||||
resolve_f64 => "spacing" = 10.0 => |v| gtk_widget.set_spacing(v as i32),
|
resolve_f64 => "spacing" = 0.0 => |v| gtk_widget.set_spacing(v as i32),
|
||||||
resolve_str => "orientation" => |v| gtk_widget.set_orientation(parse_orientation(&v)),
|
resolve_str => "orientation" => |v| gtk_widget.set_orientation(parse_orientation(&v)),
|
||||||
|
resolve_bool => "homogenous" = true => |v| gtk_widget.set_homogeneous(v),
|
||||||
});
|
});
|
||||||
Ok(gtk_widget)
|
Ok(gtk_widget)
|
||||||
}
|
}
|
||||||
|
@ -115,3 +118,14 @@ fn parse_orientation(o: &str) -> gtk::Orientation {
|
||||||
_ => gtk::Orientation::Horizontal,
|
_ => gtk::Orientation::Horizontal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_align(o: &str) -> gtk::Align {
|
||||||
|
match o {
|
||||||
|
"fill" => gtk::Align::Fill,
|
||||||
|
"baseline" => gtk::Align::Baseline,
|
||||||
|
"center" => gtk::Align::Center,
|
||||||
|
"start" => gtk::Align::Start,
|
||||||
|
"end" => gtk::Align::End,
|
||||||
|
_ => gtk::Align::Start,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue