From ada307aac2119eae7327c8c3eadbb6795c5ce16c Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Tue, 22 Sep 2020 20:59:56 +0200 Subject: [PATCH] cleanup widget definition code --- rustfmt.toml | 4 + src/config/element.rs | 22 +-- src/config/mod.rs | 7 +- src/eww_state.rs | 8 +- src/main.rs | 29 ++-- src/value.rs | 10 +- src/widgets.rs | 225 ------------------------------ src/widgets/mod.rs | 148 ++++++++++++++++++++ src/widgets/widget_definitions.rs | 108 ++++++++++++++ 9 files changed, 290 insertions(+), 271 deletions(-) create mode 100644 rustfmt.toml delete mode 100644 src/widgets.rs create mode 100644 src/widgets/mod.rs create mode 100644 src/widgets/widget_definitions.rs diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..7e7e554 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,4 @@ +unstable_features=true +fn_single_line=false +max_width=130 + diff --git a/src/config/element.rs b/src/config/element.rs index 80c032e..b26fb15 100644 --- a/src/config/element.rs +++ b/src/config/element.rs @@ -98,10 +98,9 @@ impl WidgetUse { } pub fn get_attr(&self, key: &str) -> Result<&AttrValue> { - self.attrs.get(key).context(format!( - "attribute '{}' missing from widgetuse of '{}'", - key, &self.name - )) + self.attrs + .get(key) + .context(format!("attribute '{}' missing from widgetuse of '{}'", key, &self.name)) } } @@ -145,14 +144,7 @@ mod test { attrs: hashmap! { "value".to_string() => AttrValue::Concrete(PrimitiveValue::String("test".to_string()))}, }; assert_eq!( - WidgetUse::parse_hocon_hash( - parse_hocon(input_complex) - .unwrap() - .as_hash() - .unwrap() - .clone() - ) - .unwrap(), + WidgetUse::parse_hocon_hash(parse_hocon(input_complex).unwrap().as_hash().unwrap().clone()).unwrap(), expected ); } @@ -168,11 +160,7 @@ mod test { size: None, }; assert_eq!( - WidgetDefinition::parse_hocon( - "widget_name".to_string(), - &parse_hocon(input_complex).unwrap() - ) - .unwrap(), + WidgetDefinition::parse_hocon("widget_name".to_string(), &parse_hocon(input_complex).unwrap()).unwrap(), expected ); } diff --git a/src/config/mod.rs b/src/config/mod.rs index 8c6270b..a71c299 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -83,9 +83,7 @@ pub struct EwwWindowDefinition { impl EwwWindowDefinition { pub fn from_hocon(hocon: &Hocon) -> Result { - let data = hocon - .as_hash() - .context("window config has to be a map structure")?; + let data = hocon.as_hash().context("window config has to be a map structure")?; let position: Option<_> = try { ( data.get("pos")?.as_hash().ok()?.get("x")?.as_i64()? as i32, @@ -99,8 +97,7 @@ impl EwwWindowDefinition { ) }; - let element = - ElementUse::parse_hocon(data.get("widget").context("no widget use given")?.clone())?; + let element = ElementUse::parse_hocon(data.get("widget").context("no widget use given")?.clone())?; Ok(EwwWindowDefinition { position: position.context("pos.x and pos.y need to be set")?, diff --git a/src/eww_state.rs b/src/eww_state.rs index ba09958..a36844f 100644 --- a/src/eww_state.rs +++ b/src/eww_state.rs @@ -34,6 +34,7 @@ impl EwwState { ) -> bool { match value { AttrValue::VarRef(name) => { + // get value from globals if let Some(value) = self.state.get(name).cloned() { self.on_change_handlers .entry(name.to_string()) @@ -41,6 +42,7 @@ impl EwwState { .push(Box::new(set_value.clone())); self.resolve(local_env, &value.into(), set_value) } else if let Some(value) = local_env.get(name).cloned() { + // get value from local self.resolve(local_env, &value, set_value) } else { false @@ -53,11 +55,7 @@ impl EwwState { } } - pub fn resolve_into< - TE: std::fmt::Debug, - V: TryFrom, - F: Fn(V) + 'static + Clone, - >( + pub fn resolve_into, F: Fn(V) + 'static + Clone>( &mut self, local_env: &HashMap, value: &AttrValue, diff --git a/src/main.rs b/src/main.rs index 1ef577b..0d668ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,12 +34,22 @@ const EXAMPLE_CONFIG: &str = r#"{ layout: { class: "container", children: [ - "hi", - { button: { children: "click me you" } } - { slider: { value: "$$some_value", min: 0, max: 100, onchange: "notify-send 'changed' {}" } } - { slider: { value: "$$some_value", orientation: "vertical" } } - "hu" - { image: { path: "/home/leon/Bilder/ElCoward.png" } } + { layout: { + orientation: "v" + children: [ + "fancy button" + { button: { children: "reeee" } } + ] + } } + { layout: { + children: [ + "hi", + { button: { children: "click me you" } } + { slider: { value: "$$some_value", min: 0, max: 100, onchange: "notify-send 'changed' {}" } } + { slider: { value: "$$some_value", orientation: "vertical" } } + "hu" + ] + } } ] } } @@ -103,12 +113,7 @@ fn try_main() -> Result<()> { .get_display() .get_default_screen() .get_rgba_visual() - .or_else(|| { - app_window - .get_display() - .get_default_screen() - .get_system_visual() - }) + .or_else(|| app_window.get_display().get_default_screen().get_system_visual()) .as_ref(), ); diff --git a/src/value.rs b/src/value.rs index b5cab24..ace7228 100644 --- a/src/value.rs +++ b/src/value.rs @@ -20,6 +20,7 @@ impl TryFrom for String { } } } + impl TryFrom for f64 { type Error = anyhow::Error; fn try_from(x: PrimitiveValue) -> Result { @@ -65,10 +66,7 @@ impl std::convert::TryFrom<&Hocon> for PrimitiveValue { fn try_from(value: &Hocon) -> Result { Ok(match value { Hocon::String(s) if s.starts_with("$$") => { - return Err(anyhow!( - "Tried to use variable reference {} as primitive value", - s - )) + return Err(anyhow!("Tried to use variable reference {} as primitive value", s)) } Hocon::String(s) => PrimitiveValue::String(s.to_string()), Hocon::Integer(n) => PrimitiveValue::Number(*n as f64), @@ -116,9 +114,7 @@ impl std::convert::TryFrom<&Hocon> for AttrValue { type Error = anyhow::Error; fn try_from(value: &Hocon) -> Result { Ok(match value { - Hocon::String(s) if s.starts_with("$$") => { - AttrValue::VarRef(s.trim_start_matches("$$").to_string()) - } + Hocon::String(s) if s.starts_with("$$") => AttrValue::VarRef(s.trim_start_matches("$$").to_string()), Hocon::String(s) => AttrValue::Concrete(PrimitiveValue::String(s.clone())), Hocon::Integer(n) => AttrValue::Concrete(PrimitiveValue::Number(*n as f64)), Hocon::Real(n) => AttrValue::Concrete(PrimitiveValue::Number(*n as f64)), diff --git a/src/widgets.rs b/src/widgets.rs deleted file mode 100644 index 9c5fc7c..0000000 --- a/src/widgets.rs +++ /dev/null @@ -1,225 +0,0 @@ -use crate::config::element; -use crate::eww_state::*; -use crate::value::{AttrValue, PrimitiveValue}; -use anyhow::*; -use gtk::prelude::*; -use gtk::ImageExt; -use std::path::Path; -use std::{collections::HashMap, process::Command}; - -const CMD_STRING_PLACEHODLER: &str = "{}"; - -macro_rules! log_errors { - ($body:expr) => {{ - let result = try { $body }; - if let Err(e) = result { - eprintln!("WARN: {}", e); - } - }}; -} - -macro_rules! resolve { - ($args:ident, $gtk_widget:ident, { - $( - $func:ident => $attr:literal $( = $default:literal)? $( = req $(@$required:tt)?)? => |$arg:ident| $body:expr - ),+ $(,)? - }) => { - $( - resolve!($args, $gtk_widget, $func => $attr $( [ $default ] )* $($($required)*)* => |$arg| $body); - )+ - }; - - ($args:ident, $gtk_widget:ident, { - $($func:ident => { - $($attr:literal $(= $default:literal)? $(= req $(@$required:tt)?)? => |$arg:ident| $body:expr),+ $(,)? - }),+ $(,)? - }) => { - $($( - resolve!($args, $gtk_widget, $func => $attr $( [ $default ] )* $($($required)*)* => |$arg| $body); - )+)+ - }; - - // optional - ($args:ident, $gtk_widget:ident, $func:ident => $attr:literal => |$arg:ident| $body:expr) => { - if let Some(attr_value) = $args.widget.attrs.get($attr) { - $args.eww_state.$func($args.local_env, attr_value, { - let $gtk_widget = $gtk_widget.clone(); - move |$arg| { $body; } - }); - } - }; - - // required - ($args:ident, $gtk_widget:ident, $func:ident => $attr:literal req => |$arg:ident| $body:expr) => { - $args.eww_state.$func($args.local_env, $args.widget.get_attr($attr)?, { - let $gtk_widget = $gtk_widget.clone(); - move |$arg| { $body; } - }); - }; - - // with default - ($args:ident, $gtk_widget:ident, $func:ident => $attr:literal [$default:expr] => |$arg:ident| $body:expr) => { - $args.eww_state.$func($args.local_env, $args.widget.attrs.get($attr).unwrap_or(&AttrValue::Concrete(PrimitiveValue::from($default))), { - let $gtk_widget = $gtk_widget.clone(); - move |$arg| { $body; } - }); - }; -} - -fn run_command(cmd: &str, arg: T) { - let cmd = cmd.replace(CMD_STRING_PLACEHODLER, &format!("{}", arg)); - if let Err(e) = Command::new("bash").arg("-c").arg(cmd).output() { - eprintln!("{}", e); - } -} - -pub fn element_to_gtk_thing( - widget_definitions: &HashMap, - eww_state: &mut EwwState, - local_env: &HashMap, - element: &element::ElementUse, -) -> Result { - match element { - element::ElementUse::Text(text) => Ok(gtk::Label::new(Some(&text)).upcast()), - element::ElementUse::Widget(widget) => { - let gtk_container = - build_gtk_widget_or_container(widget_definitions, eww_state, local_env, widget)?; - - let gtk_widget = if let Some(gtk_container) = gtk_container { - gtk_container - } else if let Some(def) = widget_definitions.get(widget.name.as_str()) { - let mut local_env = local_env.clone(); - local_env.extend(widget.attrs.clone()); - element_to_gtk_thing(widget_definitions, eww_state, &local_env, &def.structure)? - } else { - return Err(anyhow!("unknown widget: '{}'", &widget.name)); - }; - - if let Ok(css_class) = widget - .get_attr("class") - .and_then(|x| AttrValue::as_string(x)) - { - gtk_widget.get_style_context().add_class(css_class); - } - - Ok(gtk_widget) - } - } -} - -struct BuilderArgs<'a, 'b, 'c> { - eww_state: &'a mut EwwState, - local_env: &'b HashMap, - widget: &'c element::WidgetUse, -} - -pub fn build_gtk_widget_or_container( - widget_definitions: &HashMap, - eww_state: &mut EwwState, - local_env: &HashMap, - widget: &element::WidgetUse, -) -> Result> { - let mut builder_args = BuilderArgs { - eww_state, - local_env: &local_env, - widget: &widget, - }; - if let Some(gtk_widget) = build_gtk_container(&mut builder_args)? { - for child in &widget.children { - let child_widget = - &element_to_gtk_thing(widget_definitions, eww_state, local_env, child) - .with_context(|| { - format!( - "error while building child '{:?}' of '{}'", - &child, - >k_widget.get_widget_name() - ) - })?; - gtk_widget.add(child_widget); - } - Ok(Some(gtk_widget.upcast())) - } else { - build_gtk_widget(&mut builder_args).context("error building gtk widget") - } -} - -// widget definitions - -fn build_gtk_widget(builder_args: &mut BuilderArgs) -> Result> { - let gtk_widget = match builder_args.widget.name.as_str() { - "slider" => build_gtk_scale(builder_args)?.upcast(), - "image" => build_gtk_image(builder_args)?.upcast(), - _ => return Ok(None), - }; - Ok(Some(gtk_widget)) -} - -fn build_gtk_container(builder_args: &mut BuilderArgs) -> Result> { - let gtk_widget = match builder_args.widget.name.as_str() { - "layout" => build_gtk_layout(builder_args)?.upcast(), - "button" => build_gtk_button(builder_args)?.upcast(), - _ => return Ok(None), - }; - Ok(Some(gtk_widget)) -} - -// concrete widgets - -fn build_gtk_scale(builder_args: &mut BuilderArgs) -> Result { - let gtk_widget = gtk::Scale::new( - gtk::Orientation::Horizontal, - Some(>k::Adjustment::new(0.0, 0.0, 100.0, 1.0, 1.0, 1.0)), - ); - - resolve!(builder_args, gtk_widget, { - resolve_f64 => { - "value" = req => |v| gtk_widget.set_value(v), - "min" => |v| gtk_widget.get_adjustment().set_lower(v), - "max" => |v| gtk_widget.get_adjustment().set_upper(v), - }, - resolve_str => { - "orientation" => |v| gtk_widget.set_orientation(parse_orientation(&v)), - "onchange" => |cmd| { - gtk_widget.connect_value_changed(move |gtk_widget| { - run_command(&cmd, gtk_widget.get_value()); - }); - } - } - }); - Ok(gtk_widget) -} - -fn build_gtk_button(builder_args: &mut BuilderArgs) -> Result { - let gtk_widget = gtk::Button::new(); - resolve!(builder_args, gtk_widget, { - resolve_bool => "active" = true => |v| gtk_widget.set_sensitive(v), - resolve_str => "onclick" => |v| gtk_widget.connect_clicked(move |_| run_command(&v, "")) - - }); - Ok(gtk_widget) -} - -fn build_gtk_image(builder_args: &mut BuilderArgs) -> Result { - let gtk_widget = gtk::Image::new(); - resolve!(builder_args, gtk_widget, { - resolve_str => "path" = req => |v| gtk_widget.set_from_file(Path::new(&v)) - }); - Ok(gtk_widget) -} - -fn build_gtk_layout(builder_args: &mut BuilderArgs) -> Result { - let gtk_widget = gtk::Box::new(gtk::Orientation::Horizontal, 0); - resolve!(builder_args, gtk_widget, { - resolve_f64 => "spacing" = 10.0 => |v| gtk_widget.set_spacing(v as i32), - resolve_str => "orientation" => |v| gtk_widget.set_orientation(parse_orientation(&v)), - - }); - Ok(gtk_widget) -} - -fn parse_orientation(o: &str) -> gtk::Orientation { - match o { - "vertical" => gtk::Orientation::Vertical, - _ => gtk::Orientation::Horizontal, - } -} diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs new file mode 100644 index 0000000..d6241b2 --- /dev/null +++ b/src/widgets/mod.rs @@ -0,0 +1,148 @@ +use crate::config::element; +use crate::eww_state::*; +use crate::value::AttrValue; +use anyhow::*; +use gtk::prelude::*; +use std::{collections::HashMap, process::Command}; +use widget_definitions::*; + +pub mod widget_definitions; + +const CMD_STRING_PLACEHODLER: &str = "{}"; + +pub fn run_command(cmd: &str, arg: T) { + let cmd = cmd.replace(CMD_STRING_PLACEHODLER, &format!("{}", arg)); + if let Err(e) = Command::new("bash").arg("-c").arg(cmd).output() { + eprintln!("{}", e); + } +} + +struct BuilderArgs<'a, 'b, 'c> { + eww_state: &'a mut EwwState, + local_env: &'b HashMap, + widget: &'c element::WidgetUse, +} + +pub fn element_to_gtk_thing( + widget_definitions: &HashMap, + eww_state: &mut EwwState, + local_env: &HashMap, + element: &element::ElementUse, +) -> Result { + match element { + element::ElementUse::Text(text) => Ok(gtk::Label::new(Some(&text)).upcast()), + element::ElementUse::Widget(widget) => { + let gtk_container = build_gtk_widget(widget_definitions, eww_state, local_env, widget)?; + + let gtk_widget = if let Some(gtk_container) = gtk_container { + gtk_container + } else if let Some(def) = widget_definitions.get(widget.name.as_str()) { + let mut local_env = local_env.clone(); + local_env.extend(widget.attrs.clone()); + element_to_gtk_thing(widget_definitions, eww_state, &local_env, &def.structure)? + } else { + return Err(anyhow!("unknown widget: '{}'", &widget.name)); + }; + + Ok(gtk_widget) + } + } +} + +pub fn build_gtk_widget( + widget_definitions: &HashMap, + eww_state: &mut EwwState, + local_env: &HashMap, + widget: &element::WidgetUse, +) -> Result> { + let mut bargs = BuilderArgs { + eww_state, + local_env, + widget, + }; + let gtk_widget = match widget_to_gtk_widget(&mut bargs) { + Ok(Some(gtk_widget)) => gtk_widget, + result => return result, + }; + + if let Some(gtk_widget) = gtk_widget.dynamic_cast_ref::() { + resolve_container_attrs(&mut bargs, >k_widget); + for child in &widget.children { + let child_widget = element_to_gtk_thing(widget_definitions, bargs.eww_state, local_env, child); + let child_widget = child_widget.with_context(|| { + format!( + "error while building child '{:?}' of '{}'", + &child, + >k_widget.get_widget_name() + ) + })?; + gtk_widget.add(&child_widget); + } + } + gtk_widget.dynamic_cast_ref().map(|w| resolve_range_attrs(&mut bargs, &w)); + gtk_widget + .dynamic_cast_ref() + .map(|w| resolve_orientable_attrs(&mut bargs, &w)); + resolve_widget_attrs(&mut bargs, >k_widget); + + Ok(Some(gtk_widget)) +} + +#[macro_export] +macro_rules! resolve { + ($args:ident, $gtk_widget:ident, { + $( + $func:ident => $attr:literal $( = $default:literal)? $( = req $(@$required:tt)?)? => |$arg:ident| $body:expr + ),+ $(,)? + }) => { + $( + resolve!($args, $gtk_widget, $func => $attr $( [ $default ] )* $($($required)*)* => |$arg| $body); + )+ + }; + + ($args:ident, $gtk_widget:ident, { + $($func:ident => { + $($attr:literal $(= $default:literal)? $(= req $(@$required:tt)?)? => |$arg:ident| $body:expr),+ $(,)? + }),+ $(,)? + }) => { + $($( + resolve!($args, $gtk_widget, $func => $attr $( [ $default ] )* $($($required)*)* => |$arg| $body); + )+)+ + }; + + // optional + ($args:ident, $gtk_widget:ident, $func:ident => $attr:literal => |$arg:ident| $body:expr) => { + if let Some(attr_value) = $args.widget.attrs.get($attr) { + $args.eww_state.$func($args.local_env, attr_value, { + let $gtk_widget = $gtk_widget.clone(); + move |$arg| { $body; } + }); + } + }; + + // required + ($args:ident, $gtk_widget:ident, $func:ident => $attr:literal req => |$arg:ident| $body:expr) => { + $args.eww_state.$func($args.local_env, $args.widget.get_attr($attr)?, { + let $gtk_widget = $gtk_widget.clone(); + move |$arg| { $body; } + }); + }; + + // with default + ($args:ident, $gtk_widget:ident, $func:ident => $attr:literal [$default:expr] => |$arg:ident| $body:expr) => { + $args.eww_state.$func($args.local_env, $args.widget.attrs.get($attr).unwrap_or(&AttrValue::Concrete(PrimitiveValue::from($default))), { + let $gtk_widget = $gtk_widget.clone(); + move |$arg| { $body; } + }); + }; +} + +#[allow(unused)] +macro_rules! log_errors { + ($body:expr) => {{ + let result = try { $body }; + if let Err(e) = result { + eprintln!("WARN: {}", e); + } + }}; +} diff --git a/src/widgets/widget_definitions.rs b/src/widgets/widget_definitions.rs new file mode 100644 index 0000000..4f0218e --- /dev/null +++ b/src/widgets/widget_definitions.rs @@ -0,0 +1,108 @@ +use super::{run_command, BuilderArgs}; +use crate::resolve; +use crate::value::{AttrValue, PrimitiveValue}; +use anyhow::*; +use gtk::prelude::*; +use gtk::ImageExt; +use std::path::Path; + +// TODO figure out how to +// https://developer.gnome.org/gtk3/stable/GtkFixed.html + +// general attributes + +/// attributes that apply to all widgets +pub(super) fn resolve_widget_attrs(bargs: &mut BuilderArgs, gtk_widget: >k::Widget) { + resolve!(bargs, gtk_widget, { + resolve_str => "class" => |v| gtk_widget.get_style_context().add_class(&v), + resolve_bool => "active" = true => |v| gtk_widget.set_sensitive(v), + }); +} + +/// attributes that apply to all container widgets +pub(super) fn resolve_container_attrs(bargs: &mut BuilderArgs, gtk_widget: >k::Container) { + resolve!(bargs, gtk_widget, { + resolve_bool => "vexpand" = true => |v| gtk_widget.set_vexpand(v), + resolve_bool => "hexpand" = true => |v| gtk_widget.set_hexpand(v), + }); +} + +pub(super) fn resolve_range_attrs(bargs: &mut BuilderArgs, gtk_widget: >k::Range) { + resolve!(bargs, gtk_widget, { + resolve_f64 => "value" = req => |v| gtk_widget.set_value(v), + resolve_f64 => "min" => |v| gtk_widget.get_adjustment().set_lower(v), + resolve_f64 => "max" => |v| gtk_widget.get_adjustment().set_upper(v), + resolve_str => "orientation" => |v| gtk_widget.set_orientation(parse_orientation(&v)), + resolve_str => "onchange" => |cmd| { + gtk_widget.connect_value_changed(move |gtk_widget| { + run_command(&cmd, gtk_widget.get_value()); + }); + } + }); +} + +pub(super) fn resolve_orientable_attrs(bargs: &mut BuilderArgs, gtk_widget: >k::Range) { + resolve!(bargs, gtk_widget, { + resolve_str => "orientation" => |v| gtk_widget.set_orientation(parse_orientation(&v)), + }); +} + +// widget definitions + +pub(super) fn widget_to_gtk_widget(bargs: &mut BuilderArgs) -> Result> { + let gtk_widget = match bargs.widget.name.as_str() { + "slider" => build_gtk_scale(bargs)?.upcast(), + "image" => build_gtk_image(bargs)?.upcast(), + "layout" => build_gtk_layout(bargs)?.upcast(), + "button" => build_gtk_button(bargs)?.upcast(), + _ => return Ok(None), + }; + Ok(Some(gtk_widget)) +} + +// concrete widgets + +fn build_gtk_scale(bargs: &mut BuilderArgs) -> Result { + let gtk_widget = gtk::Scale::new( + gtk::Orientation::Horizontal, + Some(>k::Adjustment::new(0.0, 0.0, 100.0, 1.0, 1.0, 1.0)), + ); + resolve!(bargs, gtk_widget, { + resolve_bool => "flipped" => |v| gtk_widget.set_inverted(v) + }); + Ok(gtk_widget) +} + +fn build_gtk_button(bargs: &mut BuilderArgs) -> Result { + let gtk_widget = gtk::Button::new(); + resolve!(bargs, gtk_widget, { + resolve_str => "onclick" => |v| gtk_widget.connect_clicked(move |_| run_command(&v, "")) + + }); + Ok(gtk_widget) +} + +fn build_gtk_image(bargs: &mut BuilderArgs) -> Result { + let gtk_widget = gtk::Image::new(); + resolve!(bargs, gtk_widget, { + resolve_str => "path" = req => |v| gtk_widget.set_from_file(Path::new(&v)) + }); + Ok(gtk_widget) +} + +fn build_gtk_layout(bargs: &mut BuilderArgs) -> Result { + let gtk_widget = gtk::Box::new(gtk::Orientation::Horizontal, 0); + resolve!(bargs, gtk_widget, { + resolve_f64 => "spacing" = 10.0 => |v| gtk_widget.set_spacing(v as i32), + resolve_str => "orientation" => |v| gtk_widget.set_orientation(parse_orientation(&v)), + + }); + Ok(gtk_widget) +} + +fn parse_orientation(o: &str) -> gtk::Orientation { + match o { + "vertical" | "v" => gtk::Orientation::Vertical, + _ => gtk::Orientation::Horizontal, + } +}