1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
use crate::Component; pub(crate) mod component; mod gobject; mod handler; mod property; pub use component::{PropTransform, VComponent}; pub use gobject::VObject; pub use handler::VHandler; pub use property::VProperty; /// A node in the virtual component tree representing a [`Component`][Component] or a Gtk widget. /// /// Don't attempt to construct these directly. Use the [`gtk!`][gtk!] macro instead. /// /// [gtk!]: macro.gtk.html /// [Component]: trait.Component.html pub enum VNode<Model: Component> { Object(VObject<Model>), Component(VComponent<Model>), } impl<Model: Component> VNode<Model> { pub(crate) fn get_child_props(&self) -> &[VProperty] { match self { VNode::Object(object) => &object.child_props, VNode::Component(comp) => &comp.child_props, } } pub(crate) fn get_child_prop(&self, name: &str) -> Option<&VProperty> { let props = self.get_child_props(); for prop in props { if prop.name == name { return Some(prop); } } None } } /// An iterator over zero or one [`VNode`][VNode]s. /// /// A [`VNode`][VNode] implements [`IntoIterator`][IntoIterator] to build a `VNodeIterator`, so /// you can return a single [`VNode`][VNode] in a code block in the [`gtk!`][gtk!] macro without /// needing to convert it. /// /// If you need to return an empty list of [`VNode`][VNode]s, use [`VNode::empty()`][empty]. /// /// This iterator mainly exists to enable the pattern of conditionally returning a node from an /// if expression, because the empty iterator and the single node iterator both have the same type, /// unlike if you attempted to return [`std::iter::once()`][iter::once] and /// [`std::iter::empty()`][iter::empty], which would result in a type error. /// /// # Examples /// /// ```rust,no_run /// # use vgtk::{gtk, VNode}; /// # use vgtk::lib::gtk::{Label, LabelExt, Box, BoxExt, Orientation}; /// # fn should_render_label() -> bool { true } /// # fn view() -> VNode<()> { /// let render_label: bool = should_render_label(); /// gtk! { /// <Box::new(Orientation::Vertical, 10)> /// { /// if render_label { /// (gtk! { <Label label="It's a me, Label!" /> }).into_iter() /// } else { /// VNode::empty() /// } /// } /// </Box> /// } /// # } /// ``` /// /// [gtk!]: macro.gtk.html /// [VNode]: enum.VNode.html /// [empty]: enum.VNode.html#method.empty /// [IntoIterator]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html /// [iter::once]: https://doc.rust-lang.org/std/iter/fn.once.html /// [iter::empty]: https://doc.rust-lang.org/std/iter/fn.empty.html pub struct VNodeIterator<Model: Component> { node: Option<VNode<Model>>, } impl<Model: Component> Iterator for VNodeIterator<Model> { type Item = VNode<Model>; fn next(&mut self) -> Option<Self::Item> { self.node.take() } } impl<Model: Component> IntoIterator for VNode<Model> { type Item = VNode<Model>; type IntoIter = VNodeIterator<Model>; fn into_iter(self) -> Self::IntoIter { VNodeIterator { node: Some(self) } } } impl<Model: Component> VNode<Model> { /// Make an empty iterator of [`VNode`][VNode]s. /// /// Use this inside a code block in the [`gtk!`][gtk!] macro to return an empty list /// of child nodes. /// /// [gtk!]: macro.gtk.html /// [VNode]: enum.VNode.html pub fn empty() -> VNodeIterator<Model> { VNodeIterator { node: None } } }