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 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
//! # IUP //! //! [IUP][1] is a multi-platform toolkit for building graphical user interfaces. //! //! IUP's purpose is to allow a program to run in different systems without changes - the toolkit //! provides the application portability. Supported systems include: GTK+, Motif and Windows. //! //! IUP has some advantages over other interface toolkits available: //! //! + **Simplicity:** due to the small number of functions and to its attribute mechanism, //! the learning curve for a new user is often faster. //! + **Portability:** the same functions are implemented in each one of the platforms, thus //! assuring the interface system's portability. //! + **Customization:** the dialog specification language (LED) is a mechanisms in which it //! is possible to customize an application for a specific user with a simple-syntax text file. //! + **Flexibility:** its abstract layout mechanism provides flexibility to dialog creation. //! + **Extensibility:** the programmer can create new interface elements as needed. //! //! # The Rust Binding //! //! The Rust binding provides a way to do things in a more Rustic way but without moving out of //! IUP base nameclatures and philosophy in such a way that one can program on this binding by reading the //! original [IUP documentation][1]. //! //! Everything created by IUP is so called a [`element`](element/) which imeplements the `Element` //! trait. Each of those objects can also be encapsulated in a `Handle` element which contains //! the common functionalities and allow downcasting back to the original element type. //! //! The library is divided in a few submodules in a way that it matches the IUP documentation //! division of elements: //! //! + The [controls](control/) submodule contains the user interface controls. //! + The [layout](layout/) submodule contains the abstract layout composition controls. //! + The [dialogs](dialog/) submodule contains the dialog definitions, such as windows, //! message boxes, file selection, color selection between others. //! //! Each of those elements communicates with the programmer by the means of [callbacks](callback/) //! and attributes. Callbacks are closures that gets called when *something* happens with the //! control such as a button click and attributes are the way to set and get specific properties //! of the element such as it's design or value. //! //! Currently attributes are not individual methods specific to each element but that may be a //! thing in the future. //! //! The binding is built in a way one can build controls or even the entire window of the //! application in a single expression in a very expressive way, for example: //! //! ```ignore //! Dialog::new( //! Radio::new( //! VBox::new(elements![ //! Toggle::with_title("Option 1") //! .set_attrib("TIP", "I am a tip!") //! .set_attrib("VALUE", "ON") //! .set_action(|(_, state)| println!("Option 1 = {}", state)), //! Toggle::with_title("Option 2") //! .set_action(|(_, state)| println!("Option 2 = {}", state)) //! .set_valuechanged_cb(|_| println!("Option 2 changed!!!")), //! ]) //! ) //! ).set_attrib("TITLE", "Hello IUP!") //! .show(); //! ``` //! //! This is just a example of one of the many ways one could build the GUI creation code, //! this model opens a lot of possibilities on this matter. There's also the possibility to use //! the [LED](led/) file format and allow users to easily modify the user interface with no //! programming experience. //! //! ## Ownership //! //! IUP have a few ownership restrictions, the library owns most of the elements it creates. //! That unfortunately means the Rust ownership semantics are a bit useless on IUP and thus all //! elements are `Copy`able. //! //! The following elements are automatically destroyed when IUP closes: //! //! + All the dialogs and all of it's children widgets. //! + Any element associated with a handle name (as set by [LED](led/), `Element::add_handle_name`, //! or implicitly by `Element::set_attrib_handle`). //! //! The user is also able to destroy elements manually by calling `Element::destroy`, one should //! make sure such element does not have other *references* to it wandering in the code. //! //! From looking on the above auto-destroy rules, the following are the cases of elements that must //! be destroyed manually: //! //! + Dettached widgets with no handle name. //! + Images not associated with any widget and thus no handle name. //! + Resources with no handle name — usually timers, clipboards, popup menus, config and user elements. //! //! To help on the task of destroying those mentioned cases, the `Guard` type is available to //! provide some kind of RAII to them. This type wrapper automatically destroys the wrapped element //! when it gets out of scope. Please refer to its documentation for more details. //! //! ## UTF-8 //! //! By default in C, IUP uses strings in the current locale, IUP-Rust enables the UTF-8 mode of //! IUP to conform with Rust string standards, thus both `UTF8MODE` and `UTF8MODE_FILE` attributes //! are enabled by default in IUP-Rust. //! //! [1]: http://www.tecgraf.puc-rio.br/iup/ //! extern crate libc; extern crate iup_sys; use std::result::Result; use std::ptr; #[macro_use] mod macros; #[macro_use] pub mod element; pub use element::{Element, Handle, Guard}; #[macro_use] pub mod callback; pub mod dialog; pub mod layout; pub mod control; pub mod led; pub mod image; pub mod timer; pub mod clipboard; pub mod prelude; pub enum Orientation { Vertical, Horizontal, } impl Orientation { #[doc(hidden)] pub fn as_cstr(self) -> *const libc::c_char { use self::Orientation::*; match self { Vertical => cstr!("VERTICAL"), Horizontal => cstr!("HORIZONTAL"), } } } #[derive(Debug, Clone, Eq, PartialEq)] pub enum InitError { /// An IUP initialization error has happened. /// /// This usually happens only in UNIX because X-Windows may be not initialized. Error, /// The error returned by the user initialization function. UserError(String), /// IUP is already initialized. AlreadyOpen, } /// Initializes IUP toolkit, calls `f` for user initialization and runs the application. /// /// All IUP-Rust functions, objects and methods must be used within the bounds of the `f` closure. /// Such closure must return a `Result` indicating whether the user initialization was successful. /// /// This function will return only after the GUI application is closed. /// /// Returns `Ok` if the IUP initialization and user initialization were successful. `Err` otherwise. /// /// # Notes /// /// ## Blocking /// This functin will not return until until a callback returns `CallbackReturn::Close`, /// IupExitLoop (TODO) is called, or there are no visible dialogs. /// /// If the `f` closure returns successfully without any visible dialogs and no active timers, /// the application will hang and will not be possible to close the main loop. The process will /// have to be interrupted by the system. /// /// When the last visible dialog is hidden the IupExitLoop (TODO) function is automatically called, /// causing this function to return. To avoid that set LOCKLOOP=YES before hiding the last dialog. /// /// ## Enviroment Variables /// /// The toolkit's initialization depends also on platform-dependent environment variables, see /// each driver documentation. /// /// + **QUIET**: When this variable is set to `NO`, IUP will generate a message in console /// indicating the driver’s version when initializing. Default: `YES`. /// + **VERSION**: When this variable is set to `YES`, IUP generates a message dialog indicating /// the driver's version when initializing. Default: `NO`. /// pub fn with_iup<F: FnOnce() -> Result<(), String>>(f: F) -> Result<(), InitError> { match unsafe { iup_sys::IupOpen(ptr::null(), ptr::null()) } { iup_sys::IUP_NOERROR => {}, iup_sys::IUP_OPENED => return Err(InitError::AlreadyOpen), iup_sys::IUP_ERROR => return Err(InitError::Error), _ => unreachable!(), }; // Turn UTF-8 mode ON since Rust uses UTF-8 on strings. match element::global("DRIVER").unwrap().as_ref() { "GTK" | "Win32" => unsafe { iup_sys::IupSetGlobal(cstr!("UTF8MODE"), cstr!("YES")); iup_sys::IupSetGlobal(cstr!("UTF8MODE_FILE"), cstr!("YES")); }, _ => println!("Warning: This IUP driver does not seem to support UTF-8!"), } let user_result = f(); if user_result.is_ok() { // IupMainLoop always returns IUP_NOERROR. unsafe { iup_sys::IupMainLoop(); } } // perform manual drop_callback! on the global callbacks. // also calls our iup-rust specific close callback. callback::remove_idle(); callback::remove_close_cb().map( |mut fbox| fbox.on_callback(()) ); unsafe { iup_sys::IupClose(); } user_result.map_err(|e| InitError::UserError(e)) } /// Returns a string with the IUP version number. pub fn version() -> String { string_from_cstr!(unsafe { iup_sys::IupVersion() }) } /// Returns a number indicating the IUP version. pub fn version_number() -> i32 { unsafe { iup_sys::IupVersionNumber() as i32 } }