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 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
//! Hierarchy operations on elements. use iup_sys; use libc::c_int; use std::ffi::CString; use std::result::Result; use element::{Element, Handle}; /// Containers are elements that can store childs. pub trait Container : Node { /// Inserts an interface element at the end of the container, after the last element on it. /// /// This function can be used when elements that will compose a container are not known a *priori* /// and should be *dynamically* constructed. /// /// Valid for any element that contains other elements like dialog, frame, hbox, vbox, /// zbox or menu. /// /// The `new_child` can **not** be mapped. It will **not** map the `new_child` into the native /// system. If the parent is already mapped you must explicitly call `Widget::map` for the new child. /// /// The elements are **not** immediately repositioned. Call `Node::refresh` for the container /// (or any other element in the dialog) to update the dialog layout. /// /// If the actual parent is a layout box (`VBox`, `HBox` or `ZBox`) and you try to append a /// child that it is already at the parent child list, then the child is moved to the last /// child position. /// /// Returns the actual parent if the interface element was successfully inserted. Otherwise /// returns the desired `new_child`. Failed can happen for instance if this element is not /// a container for other elements or the `new_child` is already a child (except on layout boxes). /// Notice that the desired parent can contains a set of elements and containers where the /// child will be actually attached so the function returns the actual parent of the element. fn append<E: Node>(&mut self, new_child: E) -> Result<Handle, E> { match unsafe { iup_sys::IupAppend(self.raw(), new_child.raw()) } { ptr if ptr.is_null() => Err(new_child), ptr => Ok(Handle::from_raw(ptr)), } } /// Inserts an interface element before another child of the container. /// /// TODO ref_child NULL doc. See #23. /// /// See `Container::append` for more details on the semantics of this method. fn insert<E1, E2>(&mut self, ref_child: &E1, new_child: E2) -> Result<Handle, E2> where E1: Node, E2: Node { match unsafe { iup_sys::IupInsert(self.raw(), ref_child.raw(), new_child.raw()) } { ptr if ptr.is_null() => Err(new_child), ptr => Ok(Handle::from_raw(ptr)), } } /// Returns the a child of the element given its position. /// /// The position `pos` starts from 0. /// /// This function will return the children of the element in the exact same order in /// which they were assigned. fn child(&self, pos: usize) -> Option<Handle> { match unsafe { iup_sys::IupGetChild(self.raw(), pos as c_int) } { ptr if ptr.is_null() => None, ptr => Some(Handle::from_raw(ptr)), } } /// Returns the position of a child of the given control. /// /// See `Container::child` for additional details on the semantics of child positions. fn child_pos<E: Node>(&self, child: &E) -> Option<usize> { match unsafe { iup_sys::IupGetChildPos(self.raw(), child.raw()) } { -1 => None, id => Some(id as usize), } } /// Returns the number of children of the given element. fn child_count(&self) -> usize { unsafe { iup_sys::IupGetChildCount(self.raw()) as usize } } } /// Nodes are elements that can be part of a hierarchical structure. pub trait Node : Element { /// Detaches an interface element from its parent. /// /// It will automatically call `Widget::unmap` to unmap the element if necessary, /// and then detach the element. /// /// If left detached it is still **necessary to call `Element::destroy`** to destroy the /// detached element. /// /// The elements are **not** immediately repositioned. Call `Node::refresh` for the /// container (or any other element in the dialog) to update the dialog layout. fn detach(&mut self) -> Self { unsafe { iup_sys::IupDetach(self.raw()) }; self.clone() } /// Moves an interface element from one position in the hierarchy tree to another. /// /// TODO ref_child NULL doc. See #23. /// /// See `Container::append` for more details on the semantics of this method. fn reparent<E1, E2>(&mut self, new_parent: E1, ref_child: E2) -> Result<Self, Self> where E1: Container, E2: Node { match unsafe { iup_sys::IupReparent(self.raw(), new_parent.raw(), ref_child.raw()) } { iup_sys::IUP_NOERROR => Ok(*self), iup_sys::IUP_ERROR => Err(*self), _ => unreachable!(), } } /// Returns the parent of a element. fn parent(&self) -> Option<Handle> { match unsafe { iup_sys::IupGetParent(self.raw()) } { ptr if ptr.is_null() => None, ptr => Some(Handle::from_raw(ptr)), } } /// Returns the brother of an element. fn brother(&self) -> Option<Handle> { match unsafe { iup_sys::IupGetBrother(self.raw()) } { ptr if ptr.is_null() => None, ptr => Some(Handle::from_raw(ptr)), } } /// Returns the handle of the dialog that contains that interface element. /// /// Works also for children of a menu that is associated with a dialog. fn dialog(&self) -> Option<Handle> { match unsafe { iup_sys::IupGetDialog(self.raw()) } { ptr if ptr.is_null() => None, ptr => Some(Handle::from_raw(ptr)), } } /// Returns the identifier of the child element that has the NAME attribute equals to the /// given value on the same dialog hierarchy. /// /// Works also for children of a menu that is associated with a dialog. /// /// This function will only found the child if the **NAME attribute** is set at the control. /// /// The function returns immediatelly with the result (not needing to traverse the hierarchy) /// after the child is mapped. fn dialog_child<S: Into<String>>(&self, name: S) -> Option<Handle> { let cname = CString::new(name.into()).unwrap(); match unsafe { iup_sys::IupGetDialogChild(self.raw(), cname.as_ptr()) } { ptr if ptr.is_null() => None, ptr => Some(Handle::from_raw(ptr)), } } /// Updates the size and layout of all controls in the same dialog. /// /// Can be called even if the dialog is not mapped. /// Can be used for any control, but it will always affect the whole dialog, to refresh the /// layout of only a subset of the dialog use `Node::refresh_children`. /// /// This function will **not** change the size of the dialog, except if the SIZE or RASTERSIZE /// attributes of the dialog where changed before the call. Changing the size of elements /// without changing the dialog size may position some controls outside the dialog area at the /// left or bottom borders (the elements will be cropped at the dialog borders by the native system). /// /// `Widget::map` also updates the dialog layout, but only when called for the dialog itself, /// even if the dialog is already mapped. Since `Widget::show`, `DialogElement::showxy` and /// `DialogElement::popup` call `Widget::map`, then they all will always update the dialog /// layout before showing it, even also if the dialog is already visible. fn refresh(&mut self) { unsafe { iup_sys::IupRefresh(self.raw()) }; } /// Updates the size and layout of controls after changing size attributes, /// or attributes that affect the size of the control. /// /// Can be used for any element inside a dialog, only its children will be updated. /// /// The given element must be a container. It must be inside a dialog hierarchy and must be /// mapped. It can not be a dialog. For dialogs use `Node::refresh`. /// /// This function will **not** change the size of the given element, even if the natural size of /// its children would increase its natural size. fn refresh_children(&mut self) { // XXX container specific, maybe move to a container trait unsafe { iup_sys::IupRefreshChildren(self.raw()) }; } /// Mark the element to be redraw when the control returns to the system. fn update(&self) { unsafe { iup_sys::IupUpdate(self.raw()) }; } /// Mark the element children to be redraw when the control returns to the system. fn update_children(&self) { unsafe { iup_sys::IupUpdateChildren(self.raw()) }; } /// Force the element and its children to be redraw immediately. fn redraw(&self, also_redraw_children: bool) { unsafe { iup_sys::IupRedraw(self.raw(), also_redraw_children as c_int) }; } }