Skip to content

Commit 94b7e12

Browse files
committed
Menus
1 parent 311dcda commit 94b7e12

File tree

3 files changed

+132
-11
lines changed

3 files changed

+132
-11
lines changed

iui/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ extern crate ui_sys;
2525
mod ui;
2626
mod error;
2727
mod ffi_tools;
28+
pub mod menus;
2829
pub mod controls;
2930

3031
pub use ui::{UI, EventLoop};

iui/src/menus.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//! Menus that appear at the top of windows, and the items that go in them.
2+
3+
use libc::{c_int, c_void};
4+
use std::ffi::CString;
5+
use std::mem;
6+
use ui_sys::{self, uiMenu, uiMenuItem, uiWindow};
7+
use controls::Window;
8+
use UI;
9+
10+
/// A `MenuItem` represents an item that is shown in a `Menu`. Note that, unlike many controls,
11+
/// the text on `MenuItem`s cannot be changed after creation.
12+
#[derive(Clone)]
13+
pub struct MenuItem {
14+
ui_menu_item: *mut uiMenuItem,
15+
}
16+
17+
/// A `Menu` represents one of the top-level menus at the top of a window. As that bar is unique
18+
/// per application, creating a new `Menu` shows it on all windows that support displaying menus.
19+
#[derive(Clone)]
20+
pub struct Menu {
21+
ui_menu: *mut uiMenu,
22+
}
23+
24+
impl MenuItem {
25+
/// Enables the item, allowing it to be selected. This is the default state of a menu item.
26+
pub fn enable(&self, _ctx: &UI) {
27+
unsafe { ui_sys::uiMenuItemEnable(self.ui_menu_item) }
28+
}
29+
30+
/// Disables the item, preventing it from being selected and providing a visual cue to the
31+
/// user that it cannot be selected.
32+
pub fn disable(&self, _ctx: &UI) {
33+
unsafe { ui_sys::uiMenuItemDisable(self.ui_menu_item) }
34+
}
35+
36+
/// Returns `true` if the menu item is checked, and false if it is not checked (or not checkable).
37+
pub fn checked(&self, _ctx: &UI) -> bool {
38+
unsafe { ui_sys::uiMenuItemChecked(self.ui_menu_item) != 0 }
39+
}
40+
41+
/// Sets the menu item to either checked or unchecked based on the given value.
42+
///
43+
/// Setting the checked value of a non-checkable menu item has no effect.
44+
pub fn set_checked(&self, _ctx: &UI, checked: bool) {
45+
unsafe { ui_sys::uiMenuItemSetChecked(self.ui_menu_item, checked as c_int) }
46+
}
47+
48+
/// Sets the function to be executed when the item is clicked/selected.
49+
pub fn on_clicked<F: FnMut(&MenuItem, &Window)>(&self, _ctx: &UI, callback: F) {
50+
unsafe {
51+
let mut data: Box<Box<FnMut(&MenuItem, &Window)>> = Box::new(Box::new(callback));
52+
ui_sys::uiMenuItemOnClicked(
53+
self.ui_menu_item,
54+
c_callback,
55+
&mut *data as *mut Box<FnMut(&MenuItem, &Window)> as *mut c_void,
56+
);
57+
mem::forget(data);
58+
}
59+
60+
extern "C" fn c_callback(
61+
menu_item: *mut uiMenuItem,
62+
window: *mut uiWindow,
63+
data: *mut c_void,
64+
) {
65+
unsafe {
66+
let menu_item = MenuItem {
67+
ui_menu_item: menu_item,
68+
};
69+
let window = Window::from_raw(window);
70+
mem::transmute::<*mut c_void, &mut Box<FnMut(&MenuItem, &Window)>>(data)(
71+
&menu_item,
72+
&window,
73+
);
74+
mem::forget(window);
75+
}
76+
}
77+
}
78+
79+
// Creates a `MenuItem` from a raw pointer
80+
pub unsafe fn from_raw(raw: *mut uiMenuItem) -> Self {
81+
MenuItem { ui_menu_item: raw}
82+
}
83+
}
84+
85+
impl Menu {
86+
/// Creates a new menu with the given name to be displayed in the menubar at the top of the window.
87+
pub fn new(_ctx: &UI, name: &str) -> Menu {
88+
unsafe {
89+
let c_string = CString::new(name.as_bytes().to_vec()).unwrap();
90+
Menu {
91+
ui_menu: ui_sys::uiNewMenu(c_string.as_ptr()),
92+
}
93+
}
94+
}
95+
96+
/// Adds a new item with the given name to the menu.
97+
pub fn append_item(&self, name: &str) -> MenuItem {
98+
unsafe {
99+
let c_string = CString::new(name.as_bytes().to_vec()).unwrap();
100+
MenuItem {
101+
ui_menu_item: ui_sys::uiMenuAppendItem(self.ui_menu, c_string.as_ptr()),
102+
}
103+
}
104+
}
105+
106+
/// Adds a new togglable (checkbox) item with the given name to the menu.
107+
pub fn append_check_item(&self, name: &str) -> MenuItem {
108+
unsafe {
109+
let c_string = CString::new(name.as_bytes().to_vec()).unwrap();
110+
MenuItem {
111+
ui_menu_item: ui_sys::uiMenuAppendCheckItem(self.ui_menu, c_string.as_ptr()),
112+
}
113+
}
114+
}
115+
116+
/// Adds a seperator to the menu.
117+
pub fn append_separator(&self) {
118+
unsafe { ui_sys::uiMenuAppendSeparator(self.ui_menu) }
119+
}
120+
}

iui/src/ui.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ impl UI {
9292
}
9393
}
9494

95-
/// Hands control of this thread to the UI toolkit, allowing it to display the UI and respond to events.
95+
/// Hands control of this thread to the UI toolkit, allowing it to display the UI and respond to events.
9696
/// Does not return until the UI [quit](struct.UI.html#method.quit)s.
97-
///
97+
///
9898
/// For more control, use the `EventLoop` struct.
9999
pub fn main(&self) {
100100
self.event_loop().run(self);
@@ -107,31 +107,31 @@ impl UI {
107107
}
108108

109109
/// Running this function causes the UI to quit, exiting from [main](struct.UI.html#method.main) and no longer showing any widgets.
110-
///
110+
///
111111
/// Run in every window's default `on_closing` callback.
112112
pub fn quit(&self) {
113113
unsafe { ui_sys::uiQuit() }
114114
}
115115

116116
/// Add a callback to the UI queue. These callbacks are run when the UI main() method is called,
117117
/// in the order in which they were queued.
118-
///
118+
///
119119
/// # Example
120-
///
120+
///
121121
/// ```
122122
/// use iui::prelude::*;
123-
///
123+
///
124124
/// let ui = UI::init().unwrap();
125-
///
125+
///
126126
/// // Let the UI exit immediately
127127
/// ui.quit();
128-
///
128+
///
129129
/// ui.queue_main(|| { println!("Runs first") } );
130130
/// ui.queue_main(|| { println!("Runs second") } );
131131
/// ```
132132
pub fn queue_main<F: FnMut()>(&self, callback: F) {
133133
unsafe {
134-
let mut data: Box<Box<FnMut()>> = Box::new(Box::new((callback)));
134+
let mut data: Box<Box<FnMut()>> = Box::new(Box::new(callback));
135135
ui_sys::uiQueueMain(
136136
ffi_tools::void_void_callback,
137137
&mut *data as *mut Box<FnMut()> as *mut c_void,
@@ -172,7 +172,7 @@ impl EventLoop {
172172

173173
/// Executes a tick in the event loop, returning immediately.
174174
/// The `on_tick` callback is executed after the UI step.
175-
///
175+
///
176176
/// Returns `true` if the application should continue running, and `false`
177177
/// if it should quit.
178178
pub fn next_tick(&mut self, _ctx: &UI) -> bool {
@@ -185,7 +185,7 @@ impl EventLoop {
185185

186186
/// Hands control to the event loop until the next UI event occurs.
187187
/// The `on_tick` callback is executed after the UI step.
188-
///
188+
///
189189
/// Returns `true` if the application should continue running, and `false`
190190
/// if it should quit.
191191
pub fn next_event_tick(&mut self, _ctx: &UI) -> bool {

0 commit comments

Comments
 (0)