Skip to content

Commit 50131ca

Browse files
committed
Port additional functionality, finishing basic example.
1 parent 98c1e69 commit 50131ca

File tree

5 files changed

+190
-7
lines changed

5 files changed

+190
-7
lines changed

iui/examples/basic.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
11
extern crate iui;
22
use iui::prelude::*;
3-
use iui::controls::{Button, VerticalBox};
3+
use iui::controls::{Label, Button, VerticalBox, Group};
44

55
fn main() {
66
// Initialize the UI library
77
let ui = UI::init().expect("Couldn't initialize UI library");
88
// Create a window into which controls can be placed
99
let win = Window::new(&ui, "Test App", 200, 200, WindowType::NoMenubar);
1010

11-
// Create a vertical layout to hold the buttons
11+
// Create a vertical layout to hold the controls
1212
let vbox = VerticalBox::new(&ui);
1313
vbox.set_padded(&ui, true);
1414

15-
let button = iui::controls::Button::new(&ui, "Button");
16-
let quit_button = iui::controls::Button::new(&ui, "Quit");
15+
let group_vbox = VerticalBox::new(&ui);
16+
let group = Group::new(&ui, "Group");
1717

18-
vbox.append(&ui, button, LayoutStrategy::Compact);
19-
vbox.append(&ui, quit_button, LayoutStrategy::Compact);
18+
// Create two buttons to place in the window
19+
let button = Button::new(&ui, "Button");
20+
let quit_button = Button::new(&ui, "Quit");
21+
22+
// Create a new label. Note that labels don't auto-wrap!
23+
let mut label_text = String::new();
24+
label_text.push_str("There is a ton of text in this label.\n");
25+
label_text.push_str("Pretty much every unicode character is supported.\n");
26+
label_text.push_str("🎉 用户界面 사용자 인터페이스");
27+
let label = Label::new(&ui, &label_text);
28+
29+
vbox.append(&ui, label, LayoutStrategy::Stretchy);
30+
group_vbox.append(&ui, button, LayoutStrategy::Compact);
31+
group_vbox.append(&ui, quit_button, LayoutStrategy::Compact);
32+
group.set_child(&ui, group_vbox);
33+
vbox.append(&ui, group, LayoutStrategy::Compact);
2034

2135
// Actually put the button in the window
2236
win.set_child(&ui, vbox);

iui/src/controls/basic.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,35 @@ impl Button {
6868
}
6969
}
7070
}
71+
72+
impl Label {
73+
/// Create a new label with the given string as its text.
74+
pub fn new(_ctx: &UI, text: &str) -> Label {
75+
unsafe {
76+
let c_string = CString::new(text.as_bytes().to_vec()).unwrap();
77+
Label::from_raw(ui_sys::uiNewLabel(c_string.as_ptr()))
78+
}
79+
}
80+
81+
/// Get a copy of the existing text on the label.
82+
pub fn text(&self, _ctx: &UI) -> String {
83+
unsafe {
84+
CStr::from_ptr(ui_sys::uiLabelText(self.uiLabel))
85+
.to_string_lossy()
86+
.into_owned()
87+
}
88+
}
89+
90+
/// Get a reference to the existing text on the label.
91+
pub fn text_ref(&self, _ctx: &UI) -> &CStr {
92+
unsafe { CStr::from_ptr(ui_sys::uiLabelText(self.uiLabel)) }
93+
}
94+
95+
/// Set the text on the label.
96+
pub fn set_text(&self, _ctx: &UI, text: &str) {
97+
unsafe {
98+
let c_string = CString::new(text.as_bytes().to_vec()).unwrap();
99+
ui_sys::uiLabelSetText(self.uiLabel, c_string.as_ptr())
100+
}
101+
}
102+
}

iui/src/controls/layout.rs

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use std::mem;
22
use std::ffi::{CStr, CString};
33
use libc::c_int;
4-
use ui_sys::{self, uiBox, uiControl, uiGroup};
4+
use ui_sys::{self, uiBox, uiControl, uiTab, uiGroup};
55
use super::Control;
66
use ui::UI;
7+
use error::UIError;
78

89
/// Defines the ways in which the children of boxes can be layed out.
910
pub enum LayoutStrategy {
@@ -96,3 +97,123 @@ impl HorizontalBox {
9697
set_padded(self.uiBox, padded, _ctx)
9798
}
9899
}
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+
}

iui/src/controls/window.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ impl Window {
5454
ui.quit();
5555
});
5656

57+
// Windows, by default, draw margins
58+
window.set_margined(_ctx, true);
59+
5760
window
5861
}
5962

@@ -107,6 +110,16 @@ impl Window {
107110
}
108111
}
109112

113+
/// Check whether or not this window has margins around the edges.
114+
pub fn margined(&self, _ctx: &UI) -> bool {
115+
unsafe { ui_sys::uiWindowMargined(self.uiWindow) != 0 }
116+
}
117+
118+
/// Set whether or not the window has margins around the edges.
119+
pub fn set_margined(&self, _ctx: &UI, margined: bool) {
120+
unsafe { ui_sys::uiWindowSetMargined(self.uiWindow, margined as c_int) }
121+
}
122+
110123
/// Sets the window's child widget. The window can only have one child widget at a time.
111124
pub fn set_child<T: Into<Control>>(&self, _ctx: &UI, child: T) {
112125
unsafe { ui_sys::uiWindowSetChild(self.uiWindow, child.into().as_ui_control()) }

iui/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@ pub enum UIError {
1010
/// one already existed.
1111
#[fail(display = "cannot initialize multiple instances of the libui toolkit")]
1212
MultipleInitError(),
13+
/// Signifies that an attempt was made to remove a tab from a tab group that was out of bounds.
14+
#[fail(display = "cannot remove index {} from tab group: there are only {} tabs in the group", index, n)]
15+
TabGroupIndexOutOfBounds { index: u64, n: u64 },
1316
}

0 commit comments

Comments
 (0)