|
1 | 1 | use std::mem;
|
2 | 2 | use std::ffi::{CStr, CString};
|
3 | 3 | use libc::c_int;
|
4 |
| -use ui_sys::{self, uiBox, uiControl, uiGroup}; |
| 4 | +use ui_sys::{self, uiBox, uiControl, uiTab, uiGroup}; |
5 | 5 | use super::Control;
|
6 | 6 | use ui::UI;
|
| 7 | +use error::UIError; |
7 | 8 |
|
8 | 9 | /// Defines the ways in which the children of boxes can be layed out.
|
9 | 10 | pub enum LayoutStrategy {
|
@@ -96,3 +97,123 @@ impl HorizontalBox {
|
96 | 97 | set_padded(self.uiBox, padded, _ctx)
|
97 | 98 | }
|
98 | 99 | }
|
| 100 | + |
| 101 | +define_control! { |
| 102 | + /// A group of tabs, each of which shows a different sub-control. |
| 103 | + rust_type: TabGroup, |
| 104 | + sys_type: uiTab |
| 105 | +} |
| 106 | + |
| 107 | +define_control! { |
| 108 | + /// A group collects controls together, with (optionally) a margin and/or title. |
| 109 | + rust_type: Group, |
| 110 | + sys_type: uiGroup |
| 111 | +} |
| 112 | + |
| 113 | +impl Group { |
| 114 | + /// Create a new group with the given title. |
| 115 | + pub fn new(_ctx: &UI, title: &str) -> Group { |
| 116 | + let group = unsafe { |
| 117 | + let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); |
| 118 | + Group::from_raw(ui_sys::uiNewGroup(c_string.as_ptr())) |
| 119 | + }; |
| 120 | + group.set_margined(_ctx, true); |
| 121 | + group |
| 122 | + } |
| 123 | + |
| 124 | + /// Get a copy of the current group title. |
| 125 | + pub fn title(&self, _ctx: &UI) -> String { |
| 126 | + unsafe { |
| 127 | + CStr::from_ptr(ui_sys::uiGroupTitle(self.uiGroup)) |
| 128 | + .to_string_lossy() |
| 129 | + .into_owned() |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + /// Get a reference to the existing group title. |
| 134 | + pub fn title_ref(&self, _ctx: &UI) -> &CStr { |
| 135 | + unsafe { CStr::from_ptr(ui_sys::uiGroupTitle(self.uiGroup)) } |
| 136 | + } |
| 137 | + |
| 138 | + // Set the group's title. |
| 139 | + pub fn set_title(&self, _ctx: &UI, title: &str) { |
| 140 | + unsafe { |
| 141 | + let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); |
| 142 | + ui_sys::uiGroupSetTitle(self.uiGroup, c_string.as_ptr()) |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + // Set the group's child widget. |
| 147 | + pub fn set_child<T: Into<Control>>(&self, _ctx: &UI, child: T) { |
| 148 | + unsafe { ui_sys::uiGroupSetChild(self.uiGroup, child.into().ui_control) } |
| 149 | + } |
| 150 | + |
| 151 | + // Check whether or not the group draws a margin. |
| 152 | + pub fn margined(&self, _ctx: &UI) -> bool { |
| 153 | + unsafe { ui_sys::uiGroupMargined(self.uiGroup) != 0 } |
| 154 | + } |
| 155 | + |
| 156 | + // Set whether or not the group draws a margin. |
| 157 | + pub fn set_margined(&self, _ctx: &UI, margined: bool) { |
| 158 | + unsafe { ui_sys::uiGroupSetMargined(self.uiGroup, margined as c_int) } |
| 159 | + } |
| 160 | +} |
| 161 | + |
| 162 | +impl TabGroup { |
| 163 | + /// Create a new, empty group of tabs. |
| 164 | + pub fn new(_ctx: &UI) -> TabGroup { |
| 165 | + unsafe { TabGroup::from_raw(ui_sys::uiNewTab()) } |
| 166 | + } |
| 167 | + |
| 168 | + /// Add the given control as a new tab in the tab group with the given name. |
| 169 | + /// |
| 170 | + /// Returns the number of tabs in the group after adding the new tab. |
| 171 | + pub fn append<T: Into<Control>>(&self, _ctx: &UI, name: &str, control: T) -> u64 { |
| 172 | + let control = control.into(); |
| 173 | + unsafe { |
| 174 | + let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); |
| 175 | + ui_sys::uiTabAppend(self.uiTab, c_string.as_ptr(), control.ui_control); |
| 176 | + ui_sys::uiTabNumPages(self.uiTab) as u64 |
| 177 | + } |
| 178 | + } |
| 179 | + |
| 180 | + /// Add the given control before the given index in the tab group, as a new tab with a given name. |
| 181 | + /// |
| 182 | + /// Returns the number of tabs in the group after adding the new tab. |
| 183 | + pub fn insert_at<T: Into<Control>>(&self, _ctx: &UI, name: &str, before: u64, control: T) -> u64 { |
| 184 | + unsafe { |
| 185 | + let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); |
| 186 | + ui_sys::uiTabInsertAt(self.uiTab, c_string.as_ptr(), before, control.into().ui_control); |
| 187 | + ui_sys::uiTabNumPages(self.uiTab) as u64 |
| 188 | + } |
| 189 | + } |
| 190 | + |
| 191 | + /// Remove the control at the given index in the tab group. |
| 192 | + /// |
| 193 | + /// Returns the number of tabs in the group after removing the tab, or an error if that index was out of bounds. |
| 194 | + /// |
| 195 | + /// NOTE: This will leak the deleted control! We have no way of actually getting it |
| 196 | + /// to decrement its reference count per `libui`'s UI as of today, unless we maintain a |
| 197 | + /// separate list of children ourselves… |
| 198 | + pub fn delete(&self, _ctx: &UI, index: u64) -> Result<u64, UIError> { |
| 199 | + let n = unsafe { ui_sys::uiTabNumPages(self.uiTab) as u64 }; |
| 200 | + if index < n { |
| 201 | + unsafe { ui_sys::uiTabDelete(self.uiTab, index) }; |
| 202 | + Ok(n) |
| 203 | + } else { |
| 204 | + Err(UIError::TabGroupIndexOutOfBounds { index: index, n: n } ) |
| 205 | + } |
| 206 | + } |
| 207 | + |
| 208 | + /// Determine whether or not the tab group provides margins around its children. |
| 209 | + pub fn margined(&self, _ctx: &UI, page: u64) -> bool { |
| 210 | + unsafe { ui_sys::uiTabMargined(self.uiTab, page) != 0 } |
| 211 | + } |
| 212 | + |
| 213 | + /// Set whether or not the tab group provides margins around its children. |
| 214 | + pub fn set_margined(&self, _ctx: &UI, page: u64, margined: bool) { |
| 215 | + unsafe { ui_sys::uiTabSetMargined(self.uiTab, page, margined as c_int) } |
| 216 | + } |
| 217 | + |
| 218 | + |
| 219 | +} |
0 commit comments