|
| 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 | +} |
0 commit comments