eww/src/config/window_definition.rs
2021-03-08 22:28:29 +01:00

139 lines
4.4 KiB
Rust

use crate::{ensure_xml_tag_is, value::NumWithUnit, widgets::widget_node};
use anyhow::*;
use derive_more::*;
use serde::{Deserialize, Serialize};
use smart_default::SmartDefault;
use std::collections::HashMap;
use super::*;
/// Full window-definition containing the fully expanded widget tree.
/// **Use this** rather than `[RawEwwWindowDefinition]`.
#[derive(Debug, Clone)]
pub struct EwwWindowDefinition {
pub name: WindowName,
pub geometry: EwwWindowGeometry,
pub stacking: WindowStacking,
pub screen_number: Option<i32>,
pub widget: Box<dyn widget_node::WidgetNode>,
pub struts: StrutDefinition,
pub focusable: bool,
}
impl EwwWindowDefinition {
pub fn generate(defs: &HashMap<String, WidgetDefinition>, window: RawEwwWindowDefinition) -> Result<Self> {
Ok(EwwWindowDefinition {
name: window.name,
geometry: window.geometry,
stacking: window.stacking,
screen_number: window.screen_number,
widget: widget_node::generate_generic_widget_node(defs, &HashMap::new(), window.widget)?,
struts: window.struts,
focusable: window.focusable,
})
}
}
/// Window-definition storing the raw WidgetUse, as received directly from parsing.
#[derive(Debug, Clone, PartialEq)]
pub struct RawEwwWindowDefinition {
pub name: WindowName,
pub geometry: EwwWindowGeometry,
pub stacking: WindowStacking,
pub screen_number: Option<i32>,
pub widget: WidgetUse,
pub struts: StrutDefinition,
pub focusable: bool,
}
impl RawEwwWindowDefinition {
pub fn from_xml_element(xml: &XmlElement) -> Result<Self> {
ensure_xml_tag_is!(xml, "window");
let stacking: WindowStacking = xml.parse_optional_attr("stacking")?.unwrap_or_default();
// TODO maybe rename this to monitor?
let focusable = xml.parse_optional_attr("focusable")?;
let screen_number = xml.parse_optional_attr("screen")?;
let struts: Option<StrutDefinition> =
xml.child("reserve").ok().map(StrutDefinition::from_xml_element).transpose().context("Failed to parse <reserve>")?;
Ok(RawEwwWindowDefinition {
name: WindowName(xml.attr("name")?.to_owned()),
geometry: match xml.child("geometry") {
Ok(node) => EwwWindowGeometry::from_xml_element(node)?,
Err(_) => EwwWindowGeometry::default(),
},
widget: WidgetUse::from_xml_node(xml.child("widget")?.only_child()?)?,
stacking,
screen_number,
focusable: focusable.unwrap_or(false),
struts: struts.unwrap_or_default(),
})
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, smart_default::SmartDefault)]
pub enum Side {
#[default]
Top,
Left,
Right,
Bottom,
}
impl std::str::FromStr for Side {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Side> {
match s {
"l" | "left" => Ok(Side::Left),
"r" | "right" => Ok(Side::Right),
"t" | "top" => Ok(Side::Top),
"b" | "bottom" => Ok(Side::Bottom),
_ => Err(anyhow!("Failed to parse {} as valid side. Must be one of \"left\", \"right\", \"top\", \"bottom\"", s)),
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
pub struct StrutDefinition {
pub side: Side,
pub dist: NumWithUnit,
}
impl StrutDefinition {
pub fn from_xml_element(xml: XmlElement) -> Result<Self> {
Ok(StrutDefinition { side: xml.attr("side")?.parse()?, dist: xml.attr("distance")?.parse()? })
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Display, SmartDefault)]
pub enum WindowStacking {
#[default]
Foreground,
Background,
}
impl std::str::FromStr for WindowStacking {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
let s = s.to_lowercase();
match s.as_str() {
"foreground" | "fg" | "f" => Ok(WindowStacking::Foreground),
"background" | "bg" | "b" => Ok(WindowStacking::Background),
_ => Err(anyhow!("Couldn't parse '{}' as window stacking, must be either foreground, fg, background or bg", s)),
}
}
}
#[repr(transparent)]
#[derive(Clone, Hash, PartialEq, Eq, AsRef, FromStr, Display, Serialize, Deserialize, Default, From, DebugCustom)]
#[debug(fmt = "WindowName(\".0\")")]
pub struct WindowName(String);
impl std::borrow::Borrow<str> for WindowName {
fn borrow(&self) -> &str {
&self.0
}
}