Combo box and as_vec() (#41)
Add `as_vec` for PrimitiveValues and implement the `combo-box` widget
This commit is contained in:
parent
4b86f84479
commit
24e3a36c52
2 changed files with 90 additions and 0 deletions
|
@ -40,6 +40,7 @@ impl_try_from!(PrimitiveValue {
|
||||||
for String => |x| x.as_string();
|
for String => |x| x.as_string();
|
||||||
for f64 => |x| x.as_f64();
|
for f64 => |x| x.as_f64();
|
||||||
for bool => |x| x.as_bool();
|
for bool => |x| x.as_bool();
|
||||||
|
for Vec<String> => |x| x.as_vec();
|
||||||
});
|
});
|
||||||
|
|
||||||
impl From<bool> for PrimitiveValue {
|
impl From<bool> for PrimitiveValue {
|
||||||
|
@ -91,4 +92,68 @@ impl PrimitiveValue {
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|e| anyhow!("couldn't convert {:?} to bool: {}", &self, e))
|
.map_err(|e| anyhow!("couldn't convert {:?} to bool: {}", &self, e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_vec(&self) -> Result<Vec<String>> {
|
||||||
|
parse_vec(self.0.to_owned()).map_err(|e| anyhow!("Couldn't convert {:#?} to a vec: {}", &self, e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn parse_vec(a: String) -> Result<Vec<String>> {
|
||||||
|
match a.strip_prefix('[').and_then(|x| x.strip_suffix(']')) {
|
||||||
|
Some(content) => {
|
||||||
|
let mut items: Vec<String> = content.split(',').map(|x: &str| x.to_string()).collect();
|
||||||
|
let mut removed = 0;
|
||||||
|
for times_ran in 0..items.len() {
|
||||||
|
// escapes `,` if there's a `\` before em
|
||||||
|
if items[times_ran - removed].ends_with("\\") {
|
||||||
|
items[times_ran - removed].pop();
|
||||||
|
let it = items.remove((times_ran + 1) - removed);
|
||||||
|
items[times_ran - removed] += ",";
|
||||||
|
items[times_ran - removed] += ⁢
|
||||||
|
removed += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(items)
|
||||||
|
}
|
||||||
|
None => Err(anyhow!("Is your array built like this: '[these,are,items]'?")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
#[test]
|
||||||
|
fn test_parse_vec() {
|
||||||
|
assert_eq!(
|
||||||
|
vec![""],
|
||||||
|
parse_vec("[]".to_string()).unwrap(),
|
||||||
|
"should be able to parse empty lists"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec!["hi"],
|
||||||
|
parse_vec("[hi]".to_string()).unwrap(),
|
||||||
|
"should be able to parse single element list"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec!["hi", "ho", "hu"],
|
||||||
|
parse_vec("[hi,ho,hu]".to_string()).unwrap(),
|
||||||
|
"should be able to parse three element list"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec!["hi,ho"],
|
||||||
|
parse_vec("[hi\\,ho]".to_string()).unwrap(),
|
||||||
|
"should be able to parse list with escaped comma"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec!["hi,ho", "hu"],
|
||||||
|
parse_vec("[hi\\,ho,hu]".to_string()).unwrap(),
|
||||||
|
"should be able to parse two element list with escaped comma"
|
||||||
|
);
|
||||||
|
assert!(parse_vec("".to_string()).is_err(), "Should fail when parsing empty string");
|
||||||
|
assert!(
|
||||||
|
parse_vec("[a,b".to_string()).is_err(),
|
||||||
|
"Should fail when parsing unclosed list"
|
||||||
|
);
|
||||||
|
assert!(parse_vec("a]".to_string()).is_err(), "Should fail when parsing unopened list");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ pub(super) fn widget_to_gtk_widget(bargs: &mut BuilderArgs) -> Result<Option<gtk
|
||||||
"color-button" => build_gtk_color_button(bargs)?.upcast(),
|
"color-button" => build_gtk_color_button(bargs)?.upcast(),
|
||||||
"expander" => build_gtk_expander(bargs)?.upcast(),
|
"expander" => build_gtk_expander(bargs)?.upcast(),
|
||||||
"color-chooser" => build_gtk_color_chooser(bargs)?.upcast(),
|
"color-chooser" => build_gtk_color_chooser(bargs)?.upcast(),
|
||||||
|
"combo-box" => build_gtk_combo_box(bargs)?.upcast(),
|
||||||
_ => return Ok(None),
|
_ => return Ok(None),
|
||||||
};
|
};
|
||||||
Ok(Some(gtk_widget))
|
Ok(Some(gtk_widget))
|
||||||
|
@ -146,6 +147,30 @@ pub(super) fn resolve_orientable_attrs(bargs: &mut BuilderArgs, gtk_widget: >k
|
||||||
|
|
||||||
// concrete widgets
|
// concrete widgets
|
||||||
|
|
||||||
|
/// @widget combo-box
|
||||||
|
fn build_gtk_combo_box(bargs: &mut BuilderArgs) -> Result<gtk::ComboBoxText> {
|
||||||
|
let gtk_widget = gtk::ComboBoxText::new();
|
||||||
|
let on_change_handler_id: Rc<RefCell<Option<glib::SignalHandlerId>>> = Rc::new(RefCell::new(None));
|
||||||
|
resolve_block!(bargs, gtk_widget, {
|
||||||
|
// @prop items
|
||||||
|
prop(items: as_vec) {
|
||||||
|
gtk_widget.remove_all();
|
||||||
|
for i in items {
|
||||||
|
gtk_widget.append_text(&i);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// @prop onchange - runs the code when a item was selected, replacing {} with the item as a string
|
||||||
|
prop(onchange: as_string) {
|
||||||
|
let old_id = on_change_handler_id.replace(Some(
|
||||||
|
gtk_widget.connect_changed(move |gtk_widget| {
|
||||||
|
run_command(&onchange, gtk_widget.get_active_text().unwrap_or("".into()));
|
||||||
|
})
|
||||||
|
));
|
||||||
|
old_id.map(|id| gtk_widget.disconnect(id));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Ok(gtk_widget)
|
||||||
|
}
|
||||||
/// @widget expander widget
|
/// @widget expander widget
|
||||||
fn build_gtk_expander(bargs: &mut BuilderArgs) -> Result<gtk::Expander> {
|
fn build_gtk_expander(bargs: &mut BuilderArgs) -> Result<gtk::Expander> {
|
||||||
let gtk_widget = gtk::Expander::new(None);
|
let gtk_widget = gtk::Expander::new(None);
|
||||||
|
|
Loading…
Add table
Reference in a new issue