├── .gitmodules ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── ui-sys ├── Cargo.toml ├── build.rs └── src │ ├── ffi.rs │ ├── lib.rs │ └── platform │ ├── macos │ └── mod.rs │ ├── unix │ └── mod.rs │ └── windows │ └── mod.rs └── ui ├── Cargo.toml ├── examples ├── controlgallery.rs └── rustlogo.rs └── src ├── controls.rs ├── draw.rs ├── ffi_utils.rs ├── lib.rs ├── menus.rs ├── ui.rs └── windows.rs /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ui-sys/libui"] 2 | path = ui-sys/libui 3 | url = https://github.com/andlabs/libui 4 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 The Rust Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | These are work-in-progress Rust bindings to the minimalistic native UI library [libui][libui]. 2 | 3 | Author: Patrick Walton (@pcwalton) 4 | 5 | [libui]: https://github.com/andlabs/libui 6 | 7 | -------------------------------------------------------------------------------- /ui-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ui-sys" 3 | version = "0.1.0" 4 | authors = ["Patrick Walton "] 5 | build = "build.rs" 6 | license = "MIT/Apache 2.0" 7 | description = "Native bindings to the minimalist, cross-platform, widget set `libui`" 8 | 9 | [dependencies] 10 | libc = "0.2" 11 | 12 | [build-dependencies] 13 | make-cmd = "0.1" 14 | 15 | -------------------------------------------------------------------------------- /ui-sys/build.rs: -------------------------------------------------------------------------------- 1 | extern crate make_cmd; 2 | 3 | use std::env; 4 | use std::path::Path; 5 | use std::process::Command; 6 | 7 | fn main() { 8 | if !Path::new("libui/.git").exists() { 9 | Command::new("git").args(&["submodule", "update", "--init"]).status().unwrap(); 10 | } 11 | 12 | let out_dir = env::var("OUT_DIR").unwrap(); 13 | let outdir_argument = format!("OUTDIR={}", out_dir); 14 | let objdir_argument = format!("OBJDIR={}/obj", out_dir); 15 | make_cmd::gnu_make().args(&["-C", "libui", &*outdir_argument, &*objdir_argument]) 16 | .status() 17 | .unwrap(); 18 | 19 | println!("cargo:rustc-link-lib=dylib=ui"); 20 | println!("cargo:rustc-link-search=native={}", out_dir); 21 | } 22 | 23 | -------------------------------------------------------------------------------- /ui-sys/src/ffi.rs: -------------------------------------------------------------------------------- 1 | //! Low-level FFI bindings to `libui`. 2 | 3 | #![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)] 4 | 5 | use libc::{c_char, c_double, c_int, c_void, intmax_t, size_t, uintmax_t}; 6 | 7 | #[repr(C)] 8 | #[derive(Clone)] 9 | pub struct uiInitOptions { 10 | pub Size: size_t, 11 | } 12 | 13 | #[link(name = "ui")] 14 | extern { 15 | pub fn uiInit(options: *mut uiInitOptions) -> *const c_char; 16 | pub fn uiUninit(); 17 | pub fn uiFreeInitError(err: *const c_char); 18 | 19 | pub fn uiMain(); 20 | pub fn uiQuit(); 21 | 22 | pub fn uiQueueMain(f: extern "C" fn(data: *mut c_void), data: *mut c_void); 23 | 24 | pub fn uiOnShouldQuit(f: extern "C" fn(data: *mut c_void), data: *mut c_void); 25 | 26 | pub fn uiFreeText(text: *mut c_char); 27 | } 28 | 29 | #[repr(C)] 30 | #[allow(non_snake_case)] 31 | pub struct uiControl { 32 | pub Signature: u32, 33 | pub OSSignature: u32, 34 | pub TypeSignature: u32, 35 | pub Destroy: extern "C" fn(this: *mut uiControl), 36 | pub Handle: extern "C" fn(this: *mut uiControl) -> usize, 37 | pub Parent: extern "C" fn(this: *mut uiControl) -> *mut uiControl, 38 | pub SetParent: extern "C" fn(this: *mut uiControl, new_parent: *mut uiControl), 39 | pub Toplevel: extern "C" fn(this: *mut uiControl) -> c_int, 40 | pub Visible: extern "C" fn(this: *mut uiControl) -> c_int, 41 | pub Show: extern "C" fn(this: *mut uiControl), 42 | pub Hide: extern "C" fn(this: *mut uiControl), 43 | pub Enabled: extern "C" fn(this: *mut uiControl) -> c_int, 44 | pub Enable: extern "C" fn(this: *mut uiControl), 45 | pub Disable: extern "C" fn(this: *mut uiControl), 46 | } 47 | 48 | #[link(name = "ui")] 49 | extern { 50 | pub fn uiControlDestroy(control: *mut uiControl); 51 | pub fn uiControlHandle(control: *mut uiControl) -> usize; 52 | pub fn uiControlParent(control: *mut uiControl) -> *mut uiControl; 53 | pub fn uiControlSetParent(control: *mut uiControl, new_parent: *mut uiControl); 54 | pub fn uiControlToplevel(control: *mut uiControl) -> c_int; 55 | pub fn uiControlVisible(control: *mut uiControl) -> c_int; 56 | pub fn uiControlShow(control: *mut uiControl); 57 | pub fn uiControlHide(control: *mut uiControl); 58 | pub fn uiControlEnabled(control: *mut uiControl) -> c_int; 59 | pub fn uiControlEnable(control: *mut uiControl); 60 | pub fn uiControlDisable(control: *mut uiControl); 61 | 62 | pub fn uiAllocControl(n: size_t, OSsig: u32, typesig: u32, typenamestr: *const c_char) 63 | -> *mut uiControl; 64 | pub fn uiFreeControl(control: *mut uiControl); 65 | 66 | pub fn uiControlVerifyDestroy(control: *mut uiControl); 67 | pub fn uiControlVerifySetParent(control: *mut uiControl, new_parent: *mut uiControl); 68 | pub fn uiControlEnabledToUser(control: *mut uiControl) -> c_int; 69 | } 70 | 71 | pub enum uiWindow {} 72 | 73 | #[link(name = "ui")] 74 | extern { 75 | pub fn uiWindowTitle(w: *mut uiWindow) -> *mut c_char; 76 | pub fn uiWindowSetTitle(w: *mut uiWindow, title: *const c_char); 77 | pub fn uiWindowOnClosing(w: *mut uiWindow, 78 | f: extern "C" fn(w: *mut uiWindow, data: *mut c_void) -> c_int, 79 | data: *mut c_void); 80 | pub fn uiWindowSetChild(w: *mut uiWindow, child: *mut uiControl); 81 | pub fn uiWindowMargined(w: *mut uiWindow) -> c_int; 82 | pub fn uiWindowSetMargined(w: *mut uiWindow, margined: c_int); 83 | pub fn uiNewWindow(title: *const c_char, width: c_int, height: c_int, hasMenubar: c_int) 84 | -> *mut uiWindow; 85 | } 86 | 87 | pub enum uiButton {} 88 | 89 | #[link(name = "ui")] 90 | extern { 91 | pub fn uiButtonText(b: *mut uiButton) -> *mut c_char; 92 | pub fn uiButtonSetText(b: *mut uiButton, text: *const c_char); 93 | pub fn uiButtonOnClicked(b: *mut uiButton, 94 | callback: extern "C" fn(b: *mut uiButton, data: *mut c_void), 95 | data: *mut c_void); 96 | pub fn uiNewButton(text: *const c_char) -> *mut uiButton; 97 | } 98 | 99 | pub enum uiBox {} 100 | 101 | #[link(name = "ui")] 102 | extern { 103 | pub fn uiBoxAppend(b: *mut uiBox, child: *mut uiControl, stretchy: c_int); 104 | pub fn uiBoxDelete(b: *mut uiBox, index: uintmax_t); 105 | pub fn uiBoxPadded(b: *mut uiBox) -> c_int; 106 | pub fn uiBoxSetPadded(b: *mut uiBox, padded: c_int); 107 | pub fn uiNewHorizontalBox() -> *mut uiBox; 108 | pub fn uiNewVerticalBox() -> *mut uiBox; 109 | } 110 | 111 | pub enum uiEntry {} 112 | 113 | #[link(name = "ui")] 114 | extern { 115 | pub fn uiEntryText(e: *mut uiEntry) -> *mut c_char; 116 | pub fn uiEntrySetText(e: *mut uiEntry, text: *const c_char); 117 | pub fn uiEntryOnChanged(e: *mut uiEntry, 118 | f: extern "C" fn(e: *mut uiEntry, data: *mut c_void), 119 | data: *mut c_void); 120 | pub fn uiEntryReadOnly(e: *mut uiEntry) -> c_int; 121 | pub fn uiEntrySetReadOnly(e: *mut uiEntry, readonly: c_int); 122 | pub fn uiNewEntry() -> *mut uiEntry; 123 | } 124 | 125 | pub enum uiCheckbox {} 126 | 127 | #[link(name = "ui")] 128 | extern { 129 | pub fn uiCheckboxText(c: *mut uiCheckbox) -> *mut c_char; 130 | pub fn uiCheckboxSetText(c: *mut uiCheckbox, text: *const c_char); 131 | pub fn uiCheckboxOnToggled(c: *mut uiCheckbox, 132 | f: extern "C" fn(c: *mut uiCheckbox, data: *mut c_void), 133 | data: *mut c_void); 134 | pub fn uiCheckboxChecked(c: *mut uiCheckbox) -> c_int; 135 | pub fn uiCheckboxSetChecked(c: *mut uiCheckbox, checked: c_int); 136 | pub fn uiNewCheckbox(c: *const c_char) -> *mut uiCheckbox; 137 | } 138 | 139 | pub enum uiLabel {} 140 | 141 | #[link(name = "ui")] 142 | extern { 143 | pub fn uiLabelText(l: *mut uiLabel) -> *mut c_char; 144 | pub fn uiLabelSetText(l: *mut uiLabel, text: *const c_char); 145 | pub fn uiNewLabel(text: *const c_char) -> *mut uiLabel; 146 | } 147 | 148 | pub enum uiTab {} 149 | 150 | #[link(name = "ui")] 151 | extern { 152 | pub fn uiTabAppend(t: *mut uiTab, name: *const c_char, c: *mut uiControl); 153 | pub fn uiTabInsertAt(t: *mut uiTab, name: *const c_char, before: uintmax_t, c: *mut uiControl); 154 | pub fn uiTabDelete(t: *mut uiTab, index: uintmax_t); 155 | pub fn uiTabNumPages(t: *mut uiTab) -> uintmax_t; 156 | pub fn uiTabMargined(t: *mut uiTab, page: uintmax_t) -> c_int; 157 | pub fn uiTabSetMargined(t: *mut uiTab, page: uintmax_t, margined: c_int); 158 | pub fn uiNewTab() -> *mut uiTab; 159 | } 160 | 161 | pub enum uiGroup {} 162 | 163 | #[link(name = "ui")] 164 | extern { 165 | pub fn uiGroupTitle(g: *mut uiGroup) -> *mut c_char; 166 | pub fn uiGroupSetTitle(g: *mut uiGroup, title: *const c_char); 167 | pub fn uiGroupSetChild(g: *mut uiGroup, c: *mut uiControl); 168 | pub fn uiGroupMargined(g: *mut uiGroup) -> c_int; 169 | pub fn uiGroupSetMargined(g: *mut uiGroup, margined: c_int); 170 | pub fn uiNewGroup(title: *const c_char) -> *mut uiGroup; 171 | } 172 | 173 | pub enum uiSpinbox {} 174 | 175 | #[link(name = "ui")] 176 | extern { 177 | pub fn uiSpinboxValue(s: *mut uiSpinbox) -> intmax_t; 178 | pub fn uiSpinboxSetValue(s: *mut uiSpinbox, value: intmax_t); 179 | pub fn uiSpinboxOnChanged(s: *mut uiSpinbox, 180 | f: extern "C" fn(s: *mut uiSpinbox, data: *mut c_void), 181 | data: *mut c_void); 182 | pub fn uiNewSpinbox(min: intmax_t, max: intmax_t) -> *mut uiSpinbox; 183 | } 184 | 185 | pub enum uiProgressBar {} 186 | 187 | #[link(name = "ui")] 188 | extern { 189 | pub fn uiProgressBarSetValue(p: *mut uiProgressBar, n: c_int); 190 | pub fn uiNewProgressBar() -> *mut uiProgressBar; 191 | } 192 | 193 | pub enum uiSlider {} 194 | 195 | #[link(name = "ui")] 196 | extern { 197 | pub fn uiSliderValue(s: *mut uiSlider) -> intmax_t; 198 | pub fn uiSliderSetValue(s: *mut uiSlider, value: intmax_t); 199 | pub fn uiSliderOnChanged(s: *mut uiSlider, 200 | f: extern "C" fn(s: *mut uiSlider, data: *mut c_void), 201 | data: *mut c_void); 202 | pub fn uiNewSlider(min: intmax_t, max: intmax_t) -> *mut uiSlider; 203 | } 204 | 205 | pub enum uiSeparator {} 206 | 207 | #[link(name = "ui")] 208 | extern { 209 | pub fn uiNewHorizontalSeparator() -> *mut uiSeparator; 210 | } 211 | 212 | pub enum uiCombobox {} 213 | 214 | #[link(name = "ui")] 215 | extern { 216 | pub fn uiComboboxAppend(c: *mut uiCombobox, text: *const c_char); 217 | pub fn uiComboboxSelected(c: *mut uiCombobox) -> intmax_t; 218 | pub fn uiComboboxSetSelected(c: *mut uiCombobox, n: intmax_t); 219 | pub fn uiComboboxOnSelected(c: *mut uiCombobox, 220 | f: extern "C" fn(c: *mut uiCombobox, data: *mut c_void), 221 | data: *mut c_void); 222 | pub fn uiNewCombobox() -> *mut uiCombobox; 223 | pub fn uiNewEditableCombobox() -> *mut uiCombobox; 224 | } 225 | 226 | pub enum uiRadioButtons {} 227 | 228 | #[link(name = "ui")] 229 | extern { 230 | pub fn uiRadioButtonsAppend(r: *mut uiRadioButtons, text: *const c_char); 231 | pub fn uiNewRadioButtons() -> *mut uiRadioButtons; 232 | } 233 | 234 | pub enum uiDateTimePicker {} 235 | 236 | #[link(name = "ui")] 237 | extern { 238 | pub fn uiNewDateTimePicker() -> *mut uiDateTimePicker; 239 | pub fn uiNewDatePicker() -> *mut uiDateTimePicker; 240 | pub fn uiNewTimePicker() -> *mut uiDateTimePicker; 241 | } 242 | 243 | pub enum uiMultilineEntry {} 244 | 245 | #[link(name = "ui")] 246 | extern { 247 | pub fn uiMultilineEntryText(e: *mut uiMultilineEntry) -> *mut c_char; 248 | pub fn uiMultilineEntrySetText(e: *mut uiMultilineEntry, text: *const c_char); 249 | pub fn uiMultilineEntryAppend(e: *mut uiMultilineEntry, text: *const c_char); 250 | pub fn uiMultilineEntryOnChanged(e: *mut uiMultilineEntry, 251 | f: extern "C" fn(e: *mut uiMultilineEntry, data: *mut c_void), 252 | data: *mut c_void); 253 | pub fn uiMultilineEntryReadOnly(e: *mut uiMultilineEntry) -> c_int; 254 | pub fn uiMultilineEntrySetReadOnly(e: *mut uiMultilineEntry, readonly: c_int); 255 | pub fn uiNewMultilineEntry() -> *mut uiMultilineEntry; 256 | } 257 | 258 | pub enum uiMenuItem {} 259 | 260 | #[link(name = "ui")] 261 | extern { 262 | pub fn uiMenuItemEnable(m: *mut uiMenuItem); 263 | pub fn uiMenuItemDisable(m: *mut uiMenuItem); 264 | pub fn uiMenuItemOnClicked(m: *mut uiMenuItem, 265 | f: extern "C" fn(sender: *mut uiMenuItem, 266 | window: *mut uiWindow, 267 | data: *mut c_void), 268 | data: *mut c_void); 269 | pub fn uiMenuItemChecked(m: *mut uiMenuItem) -> c_int; 270 | pub fn uiMenuItemSetChecked(m: *mut uiMenuItem, checked: c_int); 271 | } 272 | 273 | pub enum uiMenu {} 274 | 275 | #[link(name = "ui")] 276 | extern { 277 | pub fn uiMenuAppendItem(m: *mut uiMenu, name: *const c_char) -> *mut uiMenuItem; 278 | pub fn uiMenuAppendCheckItem(m: *mut uiMenu, name: *const c_char) -> *mut uiMenuItem; 279 | pub fn uiMenuAppendQuitItem(m: *mut uiMenu) -> *mut uiMenuItem; 280 | pub fn uiMenuAppendPreferencesItem(m: *mut uiMenu) -> *mut uiMenuItem; 281 | pub fn uiMenuAppendAboutItem(m: *mut uiMenu) -> *mut uiMenuItem; 282 | pub fn uiMenuAppendSeparator(m: *mut uiMenu); 283 | pub fn uiNewMenu(name: *const c_char) -> *mut uiMenu; 284 | } 285 | 286 | #[link(name = "ui")] 287 | extern { 288 | pub fn uiOpenFile(parent: *mut uiWindow) -> *mut c_char; 289 | pub fn uiSaveFile(parent: *mut uiWindow) -> *mut c_char; 290 | pub fn uiMsgBox(parent: *mut uiWindow, title: *const c_char, description: *const c_char); 291 | pub fn uiMsgBoxError(parent: *mut uiWindow, title: *const c_char, description: *const c_char); 292 | } 293 | 294 | pub enum uiArea {} 295 | 296 | pub enum uiDrawContext {} 297 | 298 | #[repr(C)] 299 | pub struct uiAreaHandler { 300 | pub Draw: extern "C" fn(this: *mut uiAreaHandler, 301 | area: *mut uiArea, 302 | draw_params: *mut uiAreaDrawParams), 303 | pub MouseEvent: extern "C" fn(this: *mut uiAreaHandler, 304 | area: *mut uiArea, 305 | mouse_event: *mut uiAreaMouseEvent), 306 | pub MouseCrossed: extern "C" fn(this: *mut uiAreaHandler, area: *mut uiArea, left: c_int), 307 | pub DragBroken: extern "C" fn(this: *mut uiAreaHandler, area: *mut uiArea), 308 | pub KeyEvent: extern "C" fn(this: *mut uiAreaHandler, 309 | area: *mut uiArea, 310 | key_event: *mut uiAreaKeyEvent) 311 | -> c_int, 312 | } 313 | 314 | #[link(name = "ui")] 315 | extern { 316 | pub fn uiAreaSetSize(a: *mut uiArea, width: intmax_t, height: intmax_t); 317 | pub fn uiAreaQueueRedrawAll(a: *mut uiArea); 318 | pub fn uiAreaScrollTo(a: *mut uiArea, 319 | x: c_double, 320 | y: c_double, 321 | width: c_double, 322 | height: c_double); 323 | pub fn uiNewArea(ah: *mut uiAreaHandler) -> *mut uiArea; 324 | pub fn uiNewScrollingArea(ah: *mut uiAreaHandler, width: intmax_t, height: intmax_t) 325 | -> *mut uiArea; 326 | } 327 | 328 | #[repr(C)] 329 | #[derive(Clone)] 330 | pub struct uiAreaDrawParams { 331 | pub Context: *mut uiDrawContext, 332 | 333 | pub AreaWidth: c_double, 334 | pub AreaHeight: c_double, 335 | 336 | pub ClipX: c_double, 337 | pub ClipY: c_double, 338 | pub ClipWidth: c_double, 339 | pub ClipHeight: c_double, 340 | } 341 | 342 | pub enum uiDrawPath {} 343 | 344 | #[repr(u32)] 345 | #[derive(Copy, Clone, PartialEq, Debug)] 346 | pub enum uiDrawBrushType { 347 | Solid = 0, 348 | LinearGradient = 1, 349 | RadialGradient = 2, 350 | Image = 3, 351 | } 352 | 353 | #[repr(u32)] 354 | #[derive(Copy, Clone, PartialEq, Debug)] 355 | pub enum uiDrawLineCap { 356 | Flat = 0, 357 | Round = 1, 358 | Square = 2, 359 | } 360 | 361 | #[repr(u32)] 362 | #[derive(Copy, Clone, PartialEq, Debug)] 363 | pub enum uiDrawLineJoin { 364 | Miter = 0, 365 | Round = 1, 366 | Bevel = 2, 367 | } 368 | 369 | pub const uiDrawDefaultMiterLimit: c_double = 10.0; 370 | 371 | #[repr(u32)] 372 | #[derive(Copy, Clone, PartialEq, Debug)] 373 | pub enum uiDrawFillMode { 374 | Winding = 0, 375 | Alternate = 1, 376 | } 377 | 378 | #[repr(C)] 379 | #[derive(Copy, Clone, PartialEq, Debug)] 380 | pub struct uiDrawMatrix { 381 | pub M11: c_double, 382 | pub M12: c_double, 383 | pub M21: c_double, 384 | pub M22: c_double, 385 | pub M31: c_double, 386 | pub M32: c_double, 387 | } 388 | 389 | #[repr(C)] 390 | #[derive(Clone, Debug)] 391 | pub struct uiDrawBrush { 392 | pub Type: uiDrawBrushType, 393 | 394 | // Solid brushes: 395 | pub R: c_double, 396 | pub G: c_double, 397 | pub B: c_double, 398 | pub A: c_double, 399 | 400 | // Gradient brushes: 401 | /// Linear: start X; radial: start X. 402 | pub X0: c_double, 403 | /// Linear: start Y; radial: start Y. 404 | pub Y0: c_double, 405 | /// Linear: end X; radial: outer circle center X. 406 | pub X1: c_double, 407 | /// Linear: end Y; radial: outer circle center Y. 408 | pub Y1: c_double, 409 | /// Radial gradients only. 410 | pub OuterRadius: c_double, 411 | pub Stops: *mut uiDrawBrushGradientStop, 412 | pub NumStops: size_t, 413 | } 414 | 415 | #[repr(C)] 416 | #[derive(Copy, Clone, Debug)] 417 | pub struct uiDrawBrushGradientStop { 418 | pub Pos: c_double, 419 | pub R: c_double, 420 | pub G: c_double, 421 | pub B: c_double, 422 | pub A: c_double, 423 | } 424 | 425 | #[repr(C)] 426 | #[derive(Clone, Debug)] 427 | pub struct uiDrawStrokeParams { 428 | pub Cap: uiDrawLineCap, 429 | pub Join: uiDrawLineJoin, 430 | pub Thickness: c_double, 431 | pub MiterLimit: c_double, 432 | pub Dashes: *mut c_double, 433 | pub NumDashes: size_t, 434 | pub DashPhase: c_double, 435 | } 436 | 437 | #[link(name = "ui")] 438 | extern { 439 | pub fn uiDrawNewPath(fillMode: uiDrawFillMode) -> *mut uiDrawPath; 440 | pub fn uiDrawFreePath(p: *mut uiDrawPath); 441 | } 442 | 443 | #[link(name = "ui")] 444 | extern { 445 | pub fn uiDrawPathNewFigure(p: *mut uiDrawPath, x: c_double, y: c_double); 446 | pub fn uiDrawPathNewFigureWithArc(p: *mut uiDrawPath, 447 | xCenter: c_double, 448 | yCenter: c_double, 449 | radius: c_double, 450 | startAngle: c_double, 451 | sweep: c_double, 452 | negative: c_int); 453 | pub fn uiDrawPathLineTo(p: *mut uiDrawPath, x: c_double, y: c_double); 454 | pub fn uiDrawPathArcTo(p: *mut uiDrawPath, 455 | xCenter: c_double, 456 | yCenter: c_double, 457 | radius: c_double, 458 | startAngle: c_double, 459 | sweep: c_double, 460 | negative: c_int); 461 | pub fn uiDrawPathBezierTo(p: *mut uiDrawPath, 462 | c1x: c_double, 463 | c1y: c_double, 464 | c2x: c_double, 465 | c2y: c_double, 466 | endX: c_double, 467 | endY: c_double); 468 | pub fn uiDrawPathCloseFigure(p: *mut uiDrawPath); 469 | 470 | pub fn uiDrawPathAddRectangle(p: *mut uiDrawPath, 471 | x: c_double, 472 | y: c_double, 473 | width: c_double, 474 | height: c_double); 475 | pub fn uiDrawPathEnd(p: *mut uiDrawPath); 476 | 477 | pub fn uiDrawStroke(c: *mut uiDrawContext, 478 | path: *mut uiDrawPath, 479 | b: *mut uiDrawBrush, 480 | p: *mut uiDrawStrokeParams); 481 | pub fn uiDrawFill(c: *mut uiDrawContext, path: *mut uiDrawPath, b: *mut uiDrawBrush); 482 | } 483 | 484 | extern "C" { 485 | pub fn uiDrawMatrixSetIdentity(m: *mut uiDrawMatrix); 486 | pub fn uiDrawMatrixTranslate(m: *mut uiDrawMatrix, x: c_double, y: c_double); 487 | pub fn uiDrawMatrixScale(m: *mut uiDrawMatrix, 488 | xCenter: c_double, 489 | yCenter: c_double, 490 | x: c_double, 491 | y: c_double); 492 | pub fn uiDrawMatrixRotate(m: *mut uiDrawMatrix, x: c_double, y: c_double, amount: c_double); 493 | pub fn uiDrawMatrixSkew(m: *mut uiDrawMatrix, 494 | x: c_double, 495 | y: c_double, 496 | xamount: c_double, 497 | yamount: c_double); 498 | pub fn uiDrawMatrixMultiply(dest: *mut uiDrawMatrix, src: *mut uiDrawMatrix); 499 | pub fn uiDrawMatrixInvertible(m: *mut uiDrawMatrix) -> c_int; 500 | pub fn uiDrawMatrixInvert(m: *mut uiDrawMatrix) -> c_int; 501 | pub fn uiDrawMatrixTransformPoint(m: *mut uiDrawMatrix, x: *mut c_double, y: *mut c_double); 502 | pub fn uiDrawMatrixTransformSize(m: *mut uiDrawMatrix, x: *mut c_double, y: *mut c_double); 503 | } 504 | 505 | extern "C" { 506 | pub fn uiDrawTransform(c: *mut uiDrawContext, m: *mut uiDrawMatrix); 507 | 508 | pub fn uiDrawClip(c: *mut uiDrawContext, path: *mut uiDrawPath); 509 | 510 | pub fn uiDrawSave(c: *mut uiDrawContext); 511 | pub fn uiDrawRestore(c: *mut uiDrawContext); 512 | } 513 | 514 | pub enum uiDrawFontFamilies {} 515 | 516 | extern "C" { 517 | pub fn uiDrawListFontFamilies() -> *mut uiDrawFontFamilies; 518 | pub fn uiDrawFontFamiliesNumFamilies(ff: *mut uiDrawFontFamilies) -> uintmax_t; 519 | pub fn uiDrawFontFamiliesFamily(ff: *mut uiDrawFontFamilies, n: uintmax_t) -> *mut c_char; 520 | pub fn uiDrawFreeFontFamilies(ff: *mut uiDrawFontFamilies); 521 | } 522 | 523 | pub enum uiDrawTextLayout {} 524 | pub enum uiDrawTextFont {} 525 | 526 | #[repr(u32)] 527 | #[derive(Copy, Clone, PartialEq, Debug)] 528 | pub enum uiDrawTextWeight { 529 | Thin = 0, 530 | UltraLight = 1, 531 | Light = 2, 532 | Book = 3, 533 | Normal = 4, 534 | Medium = 5, 535 | SemiBold = 6, 536 | Bold = 7, 537 | /// [sic] 538 | UtraBold = 8, 539 | Heavy = 9, 540 | UltraHeavy = 10, 541 | } 542 | 543 | #[repr(u32)] 544 | #[derive(Copy, Clone, PartialEq, Debug)] 545 | pub enum uiDrawTextItalic { 546 | Normal = 0, 547 | Oblique = 1, 548 | Italic = 2, 549 | } 550 | 551 | #[repr(u32)] 552 | #[derive(Copy, Clone, PartialEq, Debug)] 553 | pub enum uiDrawTextStretch { 554 | UltraCondensed = 0, 555 | ExtraCondensed = 1, 556 | Condensed = 2, 557 | SemiCondensed = 3, 558 | Normal = 4, 559 | SemiExpanded = 5, 560 | Expanded = 6, 561 | ExtraExpanded = 7, 562 | UltraExpanded = 8, 563 | } 564 | 565 | #[repr(C)] 566 | #[derive(Clone)] 567 | pub struct uiDrawTextFontDescriptor { 568 | pub Family: *const c_char, 569 | pub Size: c_double, 570 | pub Weight: uiDrawTextWeight, 571 | pub Italic: uiDrawTextItalic, 572 | pub Stretch: uiDrawTextStretch, 573 | } 574 | 575 | #[repr(C)] 576 | #[derive(Copy, Clone, Debug)] 577 | pub struct uiDrawTextFontMetrics { 578 | pub Ascent: c_double, 579 | pub Descent: c_double, 580 | pub Leading: c_double, 581 | pub UnderlinePos: c_double, 582 | pub UnderlineThickness: c_double, 583 | } 584 | 585 | extern "C" { 586 | pub fn uiDrawLoadClosestFont(desc: *const uiDrawTextFontDescriptor) -> *mut uiDrawTextFont; 587 | pub fn uiDrawFreeTextFont(font: *mut uiDrawTextFont); 588 | pub fn uiDrawTextFontHandle(font: *mut uiDrawTextFont) -> usize; 589 | pub fn uiDrawTextFontDescribe(font: *mut uiDrawTextFont, 590 | desc: *mut uiDrawTextFontDescriptor); 591 | pub fn uiDrawTextFontGetMetrics(font: *mut uiDrawTextFont, 592 | metrics: *mut uiDrawTextFontMetrics); 593 | } 594 | 595 | extern "C" { 596 | pub fn uiDrawNewTextLayout(text: *const c_char, 597 | defaultFont: *mut uiDrawTextFont, 598 | width: c_double) 599 | -> *mut uiDrawTextLayout; 600 | pub fn uiDrawFreeTextLayout(layout: *mut uiDrawTextLayout); 601 | pub fn uiDrawTextLayoutSetWidth(layout: *mut uiDrawTextLayout, width: c_double); 602 | pub fn uiDrawTextLayoutExtents(layout: *mut uiDrawTextLayout, 603 | width: *mut c_double, 604 | height: *mut c_double); 605 | 606 | pub fn uiDrawTextLayoutSetColor(layout: *mut uiDrawTextLayout, 607 | startChar: intmax_t, 608 | endChar: intmax_t, 609 | r: c_double, 610 | g: c_double, 611 | b: c_double, 612 | a: c_double); 613 | 614 | pub fn uiDrawText(c: *mut uiDrawContext, 615 | x: c_double, 616 | y: c_double, 617 | layout: *mut uiDrawTextLayout); 618 | } 619 | 620 | pub type uiModifiers = c_int; 621 | 622 | pub const uiModifierCtrl: uiModifiers = 1 << 0; 623 | pub const uiModifierAlt: uiModifiers = 1 << 1; 624 | pub const uiModifierShift: uiModifiers = 1 << 2; 625 | pub const uiModifierSuper: uiModifiers = 1 << 3; 626 | 627 | #[repr(C)] 628 | #[derive(Copy, Clone, Debug)] 629 | pub struct uiAreaMouseEvent { 630 | pub X: c_double, 631 | pub Y: c_double, 632 | 633 | pub AreaWidth: c_double, 634 | pub AreaHeight: c_double, 635 | 636 | pub Down: uintmax_t, 637 | pub Up: uintmax_t, 638 | 639 | pub Count: uintmax_t, 640 | 641 | pub Modifiers: uiModifiers, 642 | 643 | pub Held1To64: u64, 644 | } 645 | 646 | #[repr(u32)] 647 | #[derive(Copy, Clone, PartialEq, Debug)] 648 | pub enum uiExtKey { 649 | Escape = 1, 650 | /// Equivalent to "Help" on Apple keyboards. 651 | Insert = 2, 652 | Delete = 3, 653 | Home = 4, 654 | End = 5, 655 | PageUp = 6, 656 | PageDown = 7, 657 | Up = 8, 658 | Down = 9, 659 | Left = 10, 660 | Right = 11, 661 | // F1..F12 are guaranteed to be consecutive. 662 | F1 = 12, 663 | F2 = 13, 664 | F3 = 14, 665 | F4 = 15, 666 | F5 = 16, 667 | F6 = 17, 668 | F7 = 18, 669 | F8 = 19, 670 | F9 = 20, 671 | F10 = 21, 672 | F11 = 22, 673 | F12 = 23, 674 | // Numpad keys; independent of Num Lock state. 675 | // N0..N9 are guaranteed to be consecutive. 676 | N0 = 24, 677 | N1 = 25, 678 | N2 = 26, 679 | N3 = 27, 680 | N4 = 28, 681 | N5 = 29, 682 | N6 = 30, 683 | N7 = 31, 684 | N8 = 32, 685 | N9 = 33, 686 | NDot = 34, 687 | NEnter = 35, 688 | NAdd = 36, 689 | NSubtract = 37, 690 | NMultiply = 38, 691 | NDivide = 39, 692 | } 693 | 694 | #[repr(C)] 695 | #[derive(Copy, Clone, Debug)] 696 | pub struct uiAreaKeyEvent { 697 | pub Key: c_char, 698 | pub ExtKey: uiExtKey, 699 | pub Modifier: uiModifiers, 700 | 701 | pub Modifiers: uiModifiers, 702 | 703 | pub Up: c_int, 704 | } 705 | 706 | pub enum uiFontButton {} 707 | 708 | #[link(name = "ui")] 709 | extern { 710 | pub fn uiFontButtonFont(b: *mut uiFontButton) -> *mut uiDrawTextFont; 711 | pub fn uiFontButtonOnChanged(b: *mut uiFontButton, 712 | f: extern "C" fn(this: *mut uiFontButton, data: *mut c_void), 713 | data: *mut c_void); 714 | pub fn uiNewFontButton() -> *mut uiFontButton; 715 | } 716 | 717 | pub enum uiColorButton {} 718 | 719 | #[link(name = "ui")] 720 | extern { 721 | pub fn uiColorButtonColor(b: *mut uiColorButton, 722 | r: *mut c_double, 723 | g: *mut c_double, 724 | bl: *mut c_double, 725 | a: *mut c_double); 726 | pub fn uiColorButtonSetColor(b: *mut uiColorButton, 727 | r: c_double, 728 | g: c_double, 729 | bl: c_double, 730 | a: c_double); 731 | pub fn uiColorButtonOnChanged(b: *mut uiColorButton, 732 | f: extern "C" fn(this: *mut uiColorButton, data: *mut c_void), 733 | data: *mut c_void); 734 | pub fn uiNewColorButton() -> *mut uiColorButton; 735 | } 736 | 737 | -------------------------------------------------------------------------------- /ui-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Low-level FFI bindings to `libui`. 2 | 3 | #![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)] 4 | 5 | extern crate libc; 6 | 7 | use libc::{c_char, c_double, c_int, c_void, intmax_t, size_t, uintmax_t}; 8 | 9 | pub mod platform { 10 | pub mod macos; 11 | pub mod unix; 12 | pub mod windows; 13 | } 14 | 15 | #[repr(C)] 16 | #[derive(Clone)] 17 | pub struct uiInitOptions { 18 | pub Size: size_t, 19 | } 20 | 21 | #[link(name = "ui")] 22 | extern { 23 | pub fn uiInit(options: *mut uiInitOptions) -> *const c_char; 24 | pub fn uiUninit(); 25 | pub fn uiFreeInitError(err: *const c_char); 26 | 27 | pub fn uiMain(); 28 | pub fn uiQuit(); 29 | 30 | pub fn uiQueueMain(f: extern "C" fn(data: *mut c_void), data: *mut c_void); 31 | 32 | pub fn uiOnShouldQuit(f: extern "C" fn(data: *mut c_void), data: *mut c_void); 33 | 34 | pub fn uiFreeText(text: *mut c_char); 35 | } 36 | 37 | #[repr(C)] 38 | #[allow(non_snake_case)] 39 | pub struct uiControl { 40 | pub Signature: u32, 41 | pub OSSignature: u32, 42 | pub TypeSignature: u32, 43 | pub Destroy: extern "C" fn(this: *mut uiControl), 44 | pub Handle: extern "C" fn(this: *mut uiControl) -> usize, 45 | pub Parent: extern "C" fn(this: *mut uiControl) -> *mut uiControl, 46 | pub SetParent: extern "C" fn(this: *mut uiControl, new_parent: *mut uiControl), 47 | pub Toplevel: extern "C" fn(this: *mut uiControl) -> c_int, 48 | pub Visible: extern "C" fn(this: *mut uiControl) -> c_int, 49 | pub Show: extern "C" fn(this: *mut uiControl), 50 | pub Hide: extern "C" fn(this: *mut uiControl), 51 | pub Enabled: extern "C" fn(this: *mut uiControl) -> c_int, 52 | pub Enable: extern "C" fn(this: *mut uiControl), 53 | pub Disable: extern "C" fn(this: *mut uiControl), 54 | } 55 | 56 | #[link(name = "ui")] 57 | extern { 58 | pub fn uiControlDestroy(control: *mut uiControl); 59 | pub fn uiControlHandle(control: *mut uiControl) -> usize; 60 | pub fn uiControlParent(control: *mut uiControl) -> *mut uiControl; 61 | pub fn uiControlSetParent(control: *mut uiControl, new_parent: *mut uiControl); 62 | pub fn uiControlToplevel(control: *mut uiControl) -> c_int; 63 | pub fn uiControlVisible(control: *mut uiControl) -> c_int; 64 | pub fn uiControlShow(control: *mut uiControl); 65 | pub fn uiControlHide(control: *mut uiControl); 66 | pub fn uiControlEnabled(control: *mut uiControl) -> c_int; 67 | pub fn uiControlEnable(control: *mut uiControl); 68 | pub fn uiControlDisable(control: *mut uiControl); 69 | 70 | pub fn uiAllocControl(n: size_t, OSsig: u32, typesig: u32, typenamestr: *const c_char) 71 | -> *mut uiControl; 72 | pub fn uiFreeControl(control: *mut uiControl); 73 | 74 | pub fn uiControlVerifyDestroy(control: *mut uiControl); 75 | pub fn uiControlVerifySetParent(control: *mut uiControl, new_parent: *mut uiControl); 76 | pub fn uiControlEnabledToUser(control: *mut uiControl) -> c_int; 77 | } 78 | 79 | pub enum uiWindow {} 80 | 81 | #[link(name = "ui")] 82 | extern { 83 | pub fn uiWindowTitle(w: *mut uiWindow) -> *mut c_char; 84 | pub fn uiWindowSetTitle(w: *mut uiWindow, title: *const c_char); 85 | pub fn uiWindowOnClosing(w: *mut uiWindow, 86 | f: extern "C" fn(w: *mut uiWindow, data: *mut c_void) -> c_int, 87 | data: *mut c_void); 88 | pub fn uiWindowSetChild(w: *mut uiWindow, child: *mut uiControl); 89 | pub fn uiWindowMargined(w: *mut uiWindow) -> c_int; 90 | pub fn uiWindowSetMargined(w: *mut uiWindow, margined: c_int); 91 | pub fn uiNewWindow(title: *const c_char, width: c_int, height: c_int, hasMenubar: c_int) 92 | -> *mut uiWindow; 93 | } 94 | 95 | pub enum uiButton {} 96 | 97 | #[link(name = "ui")] 98 | extern { 99 | pub fn uiButtonText(b: *mut uiButton) -> *mut c_char; 100 | pub fn uiButtonSetText(b: *mut uiButton, text: *const c_char); 101 | pub fn uiButtonOnClicked(b: *mut uiButton, 102 | callback: extern "C" fn(b: *mut uiButton, data: *mut c_void), 103 | data: *mut c_void); 104 | pub fn uiNewButton(text: *const c_char) -> *mut uiButton; 105 | } 106 | 107 | pub enum uiBox {} 108 | 109 | #[link(name = "ui")] 110 | extern { 111 | pub fn uiBoxAppend(b: *mut uiBox, child: *mut uiControl, stretchy: c_int); 112 | pub fn uiBoxDelete(b: *mut uiBox, index: uintmax_t); 113 | pub fn uiBoxPadded(b: *mut uiBox) -> c_int; 114 | pub fn uiBoxSetPadded(b: *mut uiBox, padded: c_int); 115 | pub fn uiNewHorizontalBox() -> *mut uiBox; 116 | pub fn uiNewVerticalBox() -> *mut uiBox; 117 | } 118 | 119 | pub enum uiEntry {} 120 | 121 | #[link(name = "ui")] 122 | extern { 123 | pub fn uiEntryText(e: *mut uiEntry) -> *mut c_char; 124 | pub fn uiEntrySetText(e: *mut uiEntry, text: *const c_char); 125 | pub fn uiEntryOnChanged(e: *mut uiEntry, 126 | f: extern "C" fn(e: *mut uiEntry, data: *mut c_void), 127 | data: *mut c_void); 128 | pub fn uiEntryReadOnly(e: *mut uiEntry) -> c_int; 129 | pub fn uiEntrySetReadOnly(e: *mut uiEntry, readonly: c_int); 130 | pub fn uiNewEntry() -> *mut uiEntry; 131 | } 132 | 133 | pub enum uiCheckbox {} 134 | 135 | #[link(name = "ui")] 136 | extern { 137 | pub fn uiCheckboxText(c: *mut uiCheckbox) -> *mut c_char; 138 | pub fn uiCheckboxSetText(c: *mut uiCheckbox, text: *const c_char); 139 | pub fn uiCheckboxOnToggled(c: *mut uiCheckbox, 140 | f: extern "C" fn(c: *mut uiCheckbox, data: *mut c_void), 141 | data: *mut c_void); 142 | pub fn uiCheckboxChecked(c: *mut uiCheckbox) -> c_int; 143 | pub fn uiCheckboxSetChecked(c: *mut uiCheckbox, checked: c_int); 144 | pub fn uiNewCheckbox(c: *const c_char) -> *mut uiCheckbox; 145 | } 146 | 147 | pub enum uiLabel {} 148 | 149 | #[link(name = "ui")] 150 | extern { 151 | pub fn uiLabelText(l: *mut uiLabel) -> *mut c_char; 152 | pub fn uiLabelSetText(l: *mut uiLabel, text: *const c_char); 153 | pub fn uiNewLabel(text: *const c_char) -> *mut uiLabel; 154 | } 155 | 156 | pub enum uiTab {} 157 | 158 | #[link(name = "ui")] 159 | extern { 160 | pub fn uiTabAppend(t: *mut uiTab, name: *const c_char, c: *mut uiControl); 161 | pub fn uiTabInsertAt(t: *mut uiTab, name: *const c_char, before: uintmax_t, c: *mut uiControl); 162 | pub fn uiTabDelete(t: *mut uiTab, index: uintmax_t); 163 | pub fn uiTabNumPages(t: *mut uiTab) -> uintmax_t; 164 | pub fn uiTabMargined(t: *mut uiTab, page: uintmax_t) -> c_int; 165 | pub fn uiTabSetMargined(t: *mut uiTab, page: uintmax_t, margined: c_int); 166 | pub fn uiNewTab() -> *mut uiTab; 167 | } 168 | 169 | pub enum uiGroup {} 170 | 171 | #[link(name = "ui")] 172 | extern { 173 | pub fn uiGroupTitle(g: *mut uiGroup) -> *mut c_char; 174 | pub fn uiGroupSetTitle(g: *mut uiGroup, title: *const c_char); 175 | pub fn uiGroupSetChild(g: *mut uiGroup, c: *mut uiControl); 176 | pub fn uiGroupMargined(g: *mut uiGroup) -> c_int; 177 | pub fn uiGroupSetMargined(g: *mut uiGroup, margined: c_int); 178 | pub fn uiNewGroup(title: *const c_char) -> *mut uiGroup; 179 | } 180 | 181 | pub enum uiSpinbox {} 182 | 183 | #[link(name = "ui")] 184 | extern { 185 | pub fn uiSpinboxValue(s: *mut uiSpinbox) -> intmax_t; 186 | pub fn uiSpinboxSetValue(s: *mut uiSpinbox, value: intmax_t); 187 | pub fn uiSpinboxOnChanged(s: *mut uiSpinbox, 188 | f: extern "C" fn(s: *mut uiSpinbox, data: *mut c_void), 189 | data: *mut c_void); 190 | pub fn uiNewSpinbox(min: intmax_t, max: intmax_t) -> *mut uiSpinbox; 191 | } 192 | 193 | pub enum uiProgressBar {} 194 | 195 | #[link(name = "ui")] 196 | extern { 197 | pub fn uiProgressBarSetValue(p: *mut uiProgressBar, n: c_int); 198 | pub fn uiNewProgressBar() -> *mut uiProgressBar; 199 | } 200 | 201 | pub enum uiSlider {} 202 | 203 | #[link(name = "ui")] 204 | extern { 205 | pub fn uiSliderValue(s: *mut uiSlider) -> intmax_t; 206 | pub fn uiSliderSetValue(s: *mut uiSlider, value: intmax_t); 207 | pub fn uiSliderOnChanged(s: *mut uiSlider, 208 | f: extern "C" fn(s: *mut uiSlider, data: *mut c_void), 209 | data: *mut c_void); 210 | pub fn uiNewSlider(min: intmax_t, max: intmax_t) -> *mut uiSlider; 211 | } 212 | 213 | pub enum uiSeparator {} 214 | 215 | #[link(name = "ui")] 216 | extern { 217 | pub fn uiNewHorizontalSeparator() -> *mut uiSeparator; 218 | } 219 | 220 | pub enum uiCombobox {} 221 | 222 | #[link(name = "ui")] 223 | extern { 224 | pub fn uiComboboxAppend(c: *mut uiCombobox, text: *const c_char); 225 | pub fn uiComboboxSelected(c: *mut uiCombobox) -> intmax_t; 226 | pub fn uiComboboxSetSelected(c: *mut uiCombobox, n: intmax_t); 227 | pub fn uiComboboxOnSelected(c: *mut uiCombobox, 228 | f: extern "C" fn(c: *mut uiCombobox, data: *mut c_void), 229 | data: *mut c_void); 230 | pub fn uiNewCombobox() -> *mut uiCombobox; 231 | pub fn uiNewEditableCombobox() -> *mut uiCombobox; 232 | } 233 | 234 | pub enum uiRadioButtons {} 235 | 236 | #[link(name = "ui")] 237 | extern { 238 | pub fn uiRadioButtonsAppend(r: *mut uiRadioButtons, text: *const c_char); 239 | pub fn uiNewRadioButtons() -> *mut uiRadioButtons; 240 | } 241 | 242 | pub enum uiDateTimePicker {} 243 | 244 | #[link(name = "ui")] 245 | extern { 246 | pub fn uiNewDateTimePicker() -> *mut uiDateTimePicker; 247 | pub fn uiNewDatePicker() -> *mut uiDateTimePicker; 248 | pub fn uiNewTimePicker() -> *mut uiDateTimePicker; 249 | } 250 | 251 | pub enum uiMultilineEntry {} 252 | 253 | #[link(name = "ui")] 254 | extern { 255 | pub fn uiMultilineEntryText(e: *mut uiMultilineEntry) -> *mut c_char; 256 | pub fn uiMultilineEntrySetText(e: *mut uiMultilineEntry, text: *const c_char); 257 | pub fn uiMultilineEntryAppend(e: *mut uiMultilineEntry, text: *const c_char); 258 | pub fn uiMultilineEntryOnChanged(e: *mut uiMultilineEntry, 259 | f: extern "C" fn(e: *mut uiMultilineEntry, data: *mut c_void), 260 | data: *mut c_void); 261 | pub fn uiMultilineEntryReadOnly(e: *mut uiMultilineEntry) -> c_int; 262 | pub fn uiMultilineEntrySetReadOnly(e: *mut uiMultilineEntry, readonly: c_int); 263 | pub fn uiNewMultilineEntry() -> *mut uiMultilineEntry; 264 | } 265 | 266 | pub enum uiMenuItem {} 267 | 268 | #[link(name = "ui")] 269 | extern { 270 | pub fn uiMenuItemEnable(m: *mut uiMenuItem); 271 | pub fn uiMenuItemDisable(m: *mut uiMenuItem); 272 | pub fn uiMenuItemOnClicked(m: *mut uiMenuItem, 273 | f: extern "C" fn(sender: *mut uiMenuItem, 274 | window: *mut uiWindow, 275 | data: *mut c_void), 276 | data: *mut c_void); 277 | pub fn uiMenuItemChecked(m: *mut uiMenuItem) -> c_int; 278 | pub fn uiMenuItemSetChecked(m: *mut uiMenuItem, checked: c_int); 279 | } 280 | 281 | pub enum uiMenu {} 282 | 283 | #[link(name = "ui")] 284 | extern { 285 | pub fn uiMenuAppendItem(m: *mut uiMenu, name: *const c_char) -> *mut uiMenuItem; 286 | pub fn uiMenuAppendCheckItem(m: *mut uiMenu, name: *const c_char) -> *mut uiMenuItem; 287 | pub fn uiMenuAppendQuitItem(m: *mut uiMenu) -> *mut uiMenuItem; 288 | pub fn uiMenuAppendPreferencesItem(m: *mut uiMenu) -> *mut uiMenuItem; 289 | pub fn uiMenuAppendAboutItem(m: *mut uiMenu) -> *mut uiMenuItem; 290 | pub fn uiMenuAppendSeparator(m: *mut uiMenu); 291 | pub fn uiNewMenu(name: *const c_char) -> *mut uiMenu; 292 | } 293 | 294 | #[link(name = "ui")] 295 | extern { 296 | pub fn uiOpenFile(parent: *mut uiWindow) -> *mut c_char; 297 | pub fn uiSaveFile(parent: *mut uiWindow) -> *mut c_char; 298 | pub fn uiMsgBox(parent: *mut uiWindow, title: *const c_char, description: *const c_char); 299 | pub fn uiMsgBoxError(parent: *mut uiWindow, title: *const c_char, description: *const c_char); 300 | } 301 | 302 | pub enum uiArea {} 303 | 304 | pub enum uiDrawContext {} 305 | 306 | #[repr(C)] 307 | pub struct uiAreaHandler { 308 | pub Draw: extern "C" fn(this: *mut uiAreaHandler, 309 | area: *mut uiArea, 310 | draw_params: *mut uiAreaDrawParams), 311 | pub MouseEvent: extern "C" fn(this: *mut uiAreaHandler, 312 | area: *mut uiArea, 313 | mouse_event: *mut uiAreaMouseEvent), 314 | pub MouseCrossed: extern "C" fn(this: *mut uiAreaHandler, area: *mut uiArea, left: c_int), 315 | pub DragBroken: extern "C" fn(this: *mut uiAreaHandler, area: *mut uiArea), 316 | pub KeyEvent: extern "C" fn(this: *mut uiAreaHandler, 317 | area: *mut uiArea, 318 | key_event: *mut uiAreaKeyEvent) 319 | -> c_int, 320 | } 321 | 322 | #[link(name = "ui")] 323 | extern { 324 | pub fn uiAreaSetSize(a: *mut uiArea, width: intmax_t, height: intmax_t); 325 | pub fn uiAreaQueueRedrawAll(a: *mut uiArea); 326 | pub fn uiAreaScrollTo(a: *mut uiArea, 327 | x: c_double, 328 | y: c_double, 329 | width: c_double, 330 | height: c_double); 331 | pub fn uiNewArea(ah: *mut uiAreaHandler) -> *mut uiArea; 332 | pub fn uiNewScrollingArea(ah: *mut uiAreaHandler, width: intmax_t, height: intmax_t) 333 | -> *mut uiArea; 334 | } 335 | 336 | #[repr(C)] 337 | #[derive(Clone)] 338 | pub struct uiAreaDrawParams { 339 | pub Context: *mut uiDrawContext, 340 | 341 | pub AreaWidth: c_double, 342 | pub AreaHeight: c_double, 343 | 344 | pub ClipX: c_double, 345 | pub ClipY: c_double, 346 | pub ClipWidth: c_double, 347 | pub ClipHeight: c_double, 348 | } 349 | 350 | pub enum uiDrawPath {} 351 | 352 | #[repr(u32)] 353 | #[derive(Copy, Clone, PartialEq, Debug)] 354 | pub enum uiDrawBrushType { 355 | Solid = 0, 356 | LinearGradient = 1, 357 | RadialGradient = 2, 358 | Image = 3, 359 | } 360 | 361 | #[repr(u32)] 362 | #[derive(Copy, Clone, PartialEq, Debug)] 363 | pub enum uiDrawLineCap { 364 | Flat = 0, 365 | Round = 1, 366 | Square = 2, 367 | } 368 | 369 | #[repr(u32)] 370 | #[derive(Copy, Clone, PartialEq, Debug)] 371 | pub enum uiDrawLineJoin { 372 | Miter = 0, 373 | Round = 1, 374 | Bevel = 2, 375 | } 376 | 377 | pub const uiDrawDefaultMiterLimit: c_double = 10.0; 378 | 379 | #[repr(u32)] 380 | #[derive(Copy, Clone, PartialEq, Debug)] 381 | pub enum uiDrawFillMode { 382 | Winding = 0, 383 | Alternate = 1, 384 | } 385 | 386 | #[repr(C)] 387 | #[derive(Copy, Clone, PartialEq, Debug)] 388 | pub struct uiDrawMatrix { 389 | pub M11: c_double, 390 | pub M12: c_double, 391 | pub M21: c_double, 392 | pub M22: c_double, 393 | pub M31: c_double, 394 | pub M32: c_double, 395 | } 396 | 397 | #[repr(C)] 398 | #[derive(Clone, Debug)] 399 | pub struct uiDrawBrush { 400 | pub Type: uiDrawBrushType, 401 | 402 | // Solid brushes: 403 | pub R: c_double, 404 | pub G: c_double, 405 | pub B: c_double, 406 | pub A: c_double, 407 | 408 | // Gradient brushes: 409 | /// Linear: start X; radial: start X. 410 | pub X0: c_double, 411 | /// Linear: start Y; radial: start Y. 412 | pub Y0: c_double, 413 | /// Linear: end X; radial: outer circle center X. 414 | pub X1: c_double, 415 | /// Linear: end Y; radial: outer circle center Y. 416 | pub Y1: c_double, 417 | /// Radial gradients only. 418 | pub OuterRadius: c_double, 419 | pub Stops: *mut uiDrawBrushGradientStop, 420 | pub NumStops: size_t, 421 | } 422 | 423 | #[repr(C)] 424 | #[derive(Copy, Clone, Debug)] 425 | pub struct uiDrawBrushGradientStop { 426 | pub Pos: c_double, 427 | pub R: c_double, 428 | pub G: c_double, 429 | pub B: c_double, 430 | pub A: c_double, 431 | } 432 | 433 | #[repr(C)] 434 | #[derive(Clone, Debug)] 435 | pub struct uiDrawStrokeParams { 436 | pub Cap: uiDrawLineCap, 437 | pub Join: uiDrawLineJoin, 438 | pub Thickness: c_double, 439 | pub MiterLimit: c_double, 440 | pub Dashes: *mut c_double, 441 | pub NumDashes: size_t, 442 | pub DashPhase: c_double, 443 | } 444 | 445 | #[link(name = "ui")] 446 | extern { 447 | pub fn uiDrawNewPath(fillMode: uiDrawFillMode) -> *mut uiDrawPath; 448 | pub fn uiDrawFreePath(p: *mut uiDrawPath); 449 | } 450 | 451 | #[link(name = "ui")] 452 | extern { 453 | pub fn uiDrawPathNewFigure(p: *mut uiDrawPath, x: c_double, y: c_double); 454 | pub fn uiDrawPathNewFigureWithArc(p: *mut uiDrawPath, 455 | xCenter: c_double, 456 | yCenter: c_double, 457 | radius: c_double, 458 | startAngle: c_double, 459 | sweep: c_double, 460 | negative: c_int); 461 | pub fn uiDrawPathLineTo(p: *mut uiDrawPath, x: c_double, y: c_double); 462 | pub fn uiDrawPathArcTo(p: *mut uiDrawPath, 463 | xCenter: c_double, 464 | yCenter: c_double, 465 | radius: c_double, 466 | startAngle: c_double, 467 | sweep: c_double, 468 | negative: c_int); 469 | pub fn uiDrawPathBezierTo(p: *mut uiDrawPath, 470 | c1x: c_double, 471 | c1y: c_double, 472 | c2x: c_double, 473 | c2y: c_double, 474 | endX: c_double, 475 | endY: c_double); 476 | pub fn uiDrawPathCloseFigure(p: *mut uiDrawPath); 477 | 478 | pub fn uiDrawPathAddRectangle(p: *mut uiDrawPath, 479 | x: c_double, 480 | y: c_double, 481 | width: c_double, 482 | height: c_double); 483 | pub fn uiDrawPathEnd(p: *mut uiDrawPath); 484 | 485 | pub fn uiDrawStroke(c: *mut uiDrawContext, 486 | path: *mut uiDrawPath, 487 | b: *mut uiDrawBrush, 488 | p: *mut uiDrawStrokeParams); 489 | pub fn uiDrawFill(c: *mut uiDrawContext, path: *mut uiDrawPath, b: *mut uiDrawBrush); 490 | } 491 | 492 | extern "C" { 493 | pub fn uiDrawMatrixSetIdentity(m: *mut uiDrawMatrix); 494 | pub fn uiDrawMatrixTranslate(m: *mut uiDrawMatrix, x: c_double, y: c_double); 495 | pub fn uiDrawMatrixScale(m: *mut uiDrawMatrix, 496 | xCenter: c_double, 497 | yCenter: c_double, 498 | x: c_double, 499 | y: c_double); 500 | pub fn uiDrawMatrixRotate(m: *mut uiDrawMatrix, x: c_double, y: c_double, amount: c_double); 501 | pub fn uiDrawMatrixSkew(m: *mut uiDrawMatrix, 502 | x: c_double, 503 | y: c_double, 504 | xamount: c_double, 505 | yamount: c_double); 506 | pub fn uiDrawMatrixMultiply(dest: *mut uiDrawMatrix, src: *mut uiDrawMatrix); 507 | pub fn uiDrawMatrixInvertible(m: *mut uiDrawMatrix) -> c_int; 508 | pub fn uiDrawMatrixInvert(m: *mut uiDrawMatrix) -> c_int; 509 | pub fn uiDrawMatrixTransformPoint(m: *mut uiDrawMatrix, x: *mut c_double, y: *mut c_double); 510 | pub fn uiDrawMatrixTransformSize(m: *mut uiDrawMatrix, x: *mut c_double, y: *mut c_double); 511 | } 512 | 513 | extern "C" { 514 | pub fn uiDrawTransform(c: *mut uiDrawContext, m: *mut uiDrawMatrix); 515 | 516 | pub fn uiDrawClip(c: *mut uiDrawContext, path: *mut uiDrawPath); 517 | 518 | pub fn uiDrawSave(c: *mut uiDrawContext); 519 | pub fn uiDrawRestore(c: *mut uiDrawContext); 520 | } 521 | 522 | pub enum uiDrawFontFamilies {} 523 | 524 | extern "C" { 525 | pub fn uiDrawListFontFamilies() -> *mut uiDrawFontFamilies; 526 | pub fn uiDrawFontFamiliesNumFamilies(ff: *mut uiDrawFontFamilies) -> uintmax_t; 527 | pub fn uiDrawFontFamiliesFamily(ff: *mut uiDrawFontFamilies, n: uintmax_t) -> *mut c_char; 528 | pub fn uiDrawFreeFontFamilies(ff: *mut uiDrawFontFamilies); 529 | } 530 | 531 | pub enum uiDrawTextLayout {} 532 | pub enum uiDrawTextFont {} 533 | 534 | #[repr(u32)] 535 | #[derive(Copy, Clone, PartialEq, Debug)] 536 | pub enum uiDrawTextWeight { 537 | Thin = 0, 538 | UltraLight = 1, 539 | Light = 2, 540 | Book = 3, 541 | Normal = 4, 542 | Medium = 5, 543 | SemiBold = 6, 544 | Bold = 7, 545 | /// [sic] 546 | UtraBold = 8, 547 | Heavy = 9, 548 | UltraHeavy = 10, 549 | } 550 | 551 | #[repr(u32)] 552 | #[derive(Copy, Clone, PartialEq, Debug)] 553 | pub enum uiDrawTextItalic { 554 | Normal = 0, 555 | Oblique = 1, 556 | Italic = 2, 557 | } 558 | 559 | #[repr(u32)] 560 | #[derive(Copy, Clone, PartialEq, Debug)] 561 | pub enum uiDrawTextStretch { 562 | UltraCondensed = 0, 563 | ExtraCondensed = 1, 564 | Condensed = 2, 565 | SemiCondensed = 3, 566 | Normal = 4, 567 | SemiExpanded = 5, 568 | Expanded = 6, 569 | ExtraExpanded = 7, 570 | UltraExpanded = 8, 571 | } 572 | 573 | #[repr(C)] 574 | #[derive(Clone)] 575 | pub struct uiDrawTextFontDescriptor { 576 | pub Family: *const c_char, 577 | pub Size: c_double, 578 | pub Weight: uiDrawTextWeight, 579 | pub Italic: uiDrawTextItalic, 580 | pub Stretch: uiDrawTextStretch, 581 | } 582 | 583 | #[repr(C)] 584 | #[derive(Copy, Clone, Debug)] 585 | pub struct uiDrawTextFontMetrics { 586 | pub Ascent: c_double, 587 | pub Descent: c_double, 588 | pub Leading: c_double, 589 | pub UnderlinePos: c_double, 590 | pub UnderlineThickness: c_double, 591 | } 592 | 593 | extern "C" { 594 | pub fn uiDrawLoadClosestFont(desc: *const uiDrawTextFontDescriptor) -> *mut uiDrawTextFont; 595 | pub fn uiDrawFreeTextFont(font: *mut uiDrawTextFont); 596 | pub fn uiDrawTextFontHandle(font: *mut uiDrawTextFont) -> usize; 597 | pub fn uiDrawTextFontDescribe(font: *mut uiDrawTextFont, 598 | desc: *mut uiDrawTextFontDescriptor); 599 | pub fn uiDrawTextFontGetMetrics(font: *mut uiDrawTextFont, 600 | metrics: *mut uiDrawTextFontMetrics); 601 | } 602 | 603 | extern "C" { 604 | pub fn uiDrawNewTextLayout(text: *const c_char, 605 | defaultFont: *mut uiDrawTextFont, 606 | width: c_double) 607 | -> *mut uiDrawTextLayout; 608 | pub fn uiDrawFreeTextLayout(layout: *mut uiDrawTextLayout); 609 | pub fn uiDrawTextLayoutSetWidth(layout: *mut uiDrawTextLayout, width: c_double); 610 | pub fn uiDrawTextLayoutExtents(layout: *mut uiDrawTextLayout, 611 | width: *mut c_double, 612 | height: *mut c_double); 613 | 614 | pub fn uiDrawTextLayoutSetColor(layout: *mut uiDrawTextLayout, 615 | startChar: intmax_t, 616 | endChar: intmax_t, 617 | r: c_double, 618 | g: c_double, 619 | b: c_double, 620 | a: c_double); 621 | 622 | pub fn uiDrawText(c: *mut uiDrawContext, 623 | x: c_double, 624 | y: c_double, 625 | layout: *mut uiDrawTextLayout); 626 | } 627 | 628 | pub type uiModifiers = c_int; 629 | 630 | pub const uiModifierCtrl: uiModifiers = 1 << 0; 631 | pub const uiModifierAlt: uiModifiers = 1 << 1; 632 | pub const uiModifierShift: uiModifiers = 1 << 2; 633 | pub const uiModifierSuper: uiModifiers = 1 << 3; 634 | 635 | #[repr(C)] 636 | #[derive(Copy, Clone, Debug)] 637 | pub struct uiAreaMouseEvent { 638 | pub X: c_double, 639 | pub Y: c_double, 640 | 641 | pub AreaWidth: c_double, 642 | pub AreaHeight: c_double, 643 | 644 | pub Down: uintmax_t, 645 | pub Up: uintmax_t, 646 | 647 | pub Count: uintmax_t, 648 | 649 | pub Modifiers: uiModifiers, 650 | 651 | pub Held1To64: u64, 652 | } 653 | 654 | #[repr(u32)] 655 | #[derive(Copy, Clone, PartialEq, Debug)] 656 | pub enum uiExtKey { 657 | Escape = 1, 658 | /// Equivalent to "Help" on Apple keyboards. 659 | Insert = 2, 660 | Delete = 3, 661 | Home = 4, 662 | End = 5, 663 | PageUp = 6, 664 | PageDown = 7, 665 | Up = 8, 666 | Down = 9, 667 | Left = 10, 668 | Right = 11, 669 | // F1..F12 are guaranteed to be consecutive. 670 | F1 = 12, 671 | F2 = 13, 672 | F3 = 14, 673 | F4 = 15, 674 | F5 = 16, 675 | F6 = 17, 676 | F7 = 18, 677 | F8 = 19, 678 | F9 = 20, 679 | F10 = 21, 680 | F11 = 22, 681 | F12 = 23, 682 | // Numpad keys; independent of Num Lock state. 683 | // N0..N9 are guaranteed to be consecutive. 684 | N0 = 24, 685 | N1 = 25, 686 | N2 = 26, 687 | N3 = 27, 688 | N4 = 28, 689 | N5 = 29, 690 | N6 = 30, 691 | N7 = 31, 692 | N8 = 32, 693 | N9 = 33, 694 | NDot = 34, 695 | NEnter = 35, 696 | NAdd = 36, 697 | NSubtract = 37, 698 | NMultiply = 38, 699 | NDivide = 39, 700 | } 701 | 702 | #[repr(C)] 703 | #[derive(Copy, Clone, Debug)] 704 | pub struct uiAreaKeyEvent { 705 | pub Key: c_char, 706 | pub ExtKey: uiExtKey, 707 | pub Modifier: uiModifiers, 708 | 709 | pub Modifiers: uiModifiers, 710 | 711 | pub Up: c_int, 712 | } 713 | 714 | pub enum uiFontButton {} 715 | 716 | #[link(name = "ui")] 717 | extern { 718 | pub fn uiFontButtonFont(b: *mut uiFontButton) -> *mut uiDrawTextFont; 719 | pub fn uiFontButtonOnChanged(b: *mut uiFontButton, 720 | f: extern "C" fn(this: *mut uiFontButton, data: *mut c_void), 721 | data: *mut c_void); 722 | pub fn uiNewFontButton() -> *mut uiFontButton; 723 | } 724 | 725 | pub enum uiColorButton {} 726 | 727 | #[link(name = "ui")] 728 | extern { 729 | pub fn uiColorButtonColor(b: *mut uiColorButton, 730 | r: *mut c_double, 731 | g: *mut c_double, 732 | bl: *mut c_double, 733 | a: *mut c_double); 734 | pub fn uiColorButtonSetColor(b: *mut uiColorButton, 735 | r: c_double, 736 | g: c_double, 737 | bl: c_double, 738 | a: c_double); 739 | pub fn uiColorButtonOnChanged(b: *mut uiColorButton, 740 | f: extern "C" fn(this: *mut uiColorButton, data: *mut c_void), 741 | data: *mut c_void); 742 | pub fn uiNewColorButton() -> *mut uiColorButton; 743 | } 744 | 745 | -------------------------------------------------------------------------------- /ui-sys/src/platform/macos/mod.rs: -------------------------------------------------------------------------------- 1 | //! Low-level bindings to API-specific functions for interfacing with foreign controls on Mac OS X. 2 | 3 | #![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)] 4 | 5 | use libc::{c_float, c_int}; 6 | use uiControl; 7 | 8 | #[repr(C)] 9 | pub struct uiDarwinControl { 10 | pub c: uiControl, 11 | pub parent: *mut uiControl, 12 | pub enabled: BOOL, 13 | pub visible: BOOL, 14 | pub SyncEnableState: extern "C" fn(*mut uiDarwinControl, c_int), 15 | pub SetSuperview: extern "C" fn(*mut uiDarwinControl, *mut NSView), 16 | pub HugsTrailingEdge: extern "C" fn(*mut uiDarwinControl) -> BOOL, 17 | pub HugsBottom: extern "C" fn(*mut uiDarwinControl) -> BOOL, 18 | pub ChildEdgeHuggingChanged: extern "C" fn(*mut uiDarwinControl), 19 | pub HuggingPriority: extern "C" fn(*mut uiDarwinControl, NSLayoutConstraintOrientation) 20 | -> NSLayoutPriority, 21 | pub SetHuggingPriority: extern "C" fn(*mut uiDarwinControl, 22 | NSLayoutPriority, 23 | NSLayoutConstraintOrientation), 24 | } 25 | 26 | #[link(name = "ui")] 27 | extern { 28 | pub fn uiDarwinControlSyncEnableState(control: *mut uiDarwinControl, state: c_int); 29 | pub fn uiDarwinControlSetSuperview(control: *mut uiDarwinControl, view: *mut NSView); 30 | pub fn uiDarwinControlHugsTrailingEdge(control: *mut uiDarwinControl) -> BOOL; 31 | pub fn uiDarwinControlHugsBottom(control: *mut uiDarwinControl) -> BOOL; 32 | pub fn uiDarwinControlChildEdgeHuggingChanged(control: *mut uiDarwinControl); 33 | pub fn uiDarwinControlHuggingPriority(control: *mut uiDarwinControl, 34 | orientation: NSLayoutConstraintOrientation) 35 | -> NSLayoutPriority; 36 | pub fn uiDarwinControlSetHuggingPriority(control: *mut uiDarwinControl, 37 | priority: NSLayoutPriority, 38 | orientation: NSLayoutConstraintOrientation); 39 | } 40 | 41 | pub type BOOL = c_int; 42 | 43 | pub enum NSView {} 44 | 45 | // This is an NSInteger. 46 | #[repr(i64)] 47 | #[derive(Copy, Clone, PartialEq, Debug)] 48 | pub enum NSLayoutConstraintOrientation { 49 | Horizontal = 0, 50 | Vertical = 1, 51 | } 52 | 53 | pub type NSLayoutPriority = c_float; 54 | 55 | pub const NSLayoutPriorityRequired: NSLayoutPriority = 1000.0; 56 | pub const NSLayoutPriorityDefaultHigh: NSLayoutPriority = 750.0; 57 | pub const NSLayoutPriorityDragThatCanResizeWindow: NSLayoutPriority = 510.0; 58 | pub const NSLayoutPriorityWindowSizeStayPut: NSLayoutPriority = 500.0; 59 | pub const NSLayoutPriorityDragThatCannotResizeWindow: NSLayoutPriority = 490.0; 60 | pub const NSLayoutPriorityDefaultLow: NSLayoutPriority = 250.0; 61 | pub const NSLayoutPriorityFittingSizeCompression: NSLayoutPriority = 50.0; 62 | 63 | -------------------------------------------------------------------------------- /ui-sys/src/platform/unix/mod.rs: -------------------------------------------------------------------------------- 1 | //! Low-level bindings to API-specific functions for interfacing with foreign controls on Unix 2 | //! systems that use GTK+ to provide their UI (currently all except Mac OS X). 3 | 4 | #![allow(non_camel_case_types, non_snake_case)] 5 | 6 | use libc::{c_char, c_int, size_t}; 7 | use uiControl; 8 | 9 | #[repr(C)] 10 | pub struct uiUnixControl { 11 | pub c: uiControl, 12 | pub parent: *mut uiControl, 13 | pub addedBefore: gboolean, 14 | pub SetContainer: extern "C" fn(*mut uiUnixControl, *mut GtkContainer, gboolean), 15 | } 16 | 17 | #[link(name = "ui")] 18 | extern { 19 | pub fn uiUnixControlSetContainer(control: *mut uiUnixControl, 20 | container: *mut GtkContainer, 21 | addBefore: gboolean); 22 | pub fn uiUnixAllocControl(n: size_t, typesig: u32, typenamestr: *const c_char) 23 | -> *mut uiUnixControl; 24 | pub fn uiUnixStrdupText(text: *const c_char) -> *mut c_char; 25 | } 26 | 27 | pub type gboolean = gint; 28 | 29 | pub type gint = c_int; 30 | 31 | pub enum GtkContainer {} 32 | 33 | -------------------------------------------------------------------------------- /ui-sys/src/platform/windows/mod.rs: -------------------------------------------------------------------------------- 1 | //! Low-level bindings to API-specific functions for interfacing with foreign controls on Windows. 2 | 3 | #![allow(non_camel_case_types, non_snake_case)] 4 | 5 | use libc::{c_char, c_int, c_long, c_ulong, c_uint, c_ushort, c_void, intmax_t, size_t, wchar_t}; 6 | use uiControl; 7 | 8 | #[repr(C)] 9 | pub struct uiWindowsControl { 10 | pub c: uiControl, 11 | pub parent: *mut uiControl, 12 | pub enabled: BOOL, 13 | pub visible: BOOL, 14 | pub SyncEnableState: extern "C" fn(*mut uiWindowsControl, c_int), 15 | pub SetParentHWND: extern "C" fn(*mut uiWindowsControl, HWND), 16 | pub MinimumSize: extern "C" fn(*mut uiWindowsControl, *mut intmax_t, *mut intmax_t), 17 | pub MinimumSizeChanged: extern "C" fn(*mut uiWindowsControl), 18 | pub LayoutRect: extern "C" fn(*mut uiWindowsControl, *mut RECT), 19 | pub AssignControlIDZOrder: extern "C" fn(*mut uiWindowsControl, *mut LONG_PTR, *mut HWND), 20 | } 21 | 22 | #[link(name = "ui")] 23 | extern { 24 | pub fn uiWindowsControlSyncEnableState(control: *mut uiWindowsControl, state: c_int); 25 | pub fn uiWindowsControlSetParentHWND(control: *mut uiWindowsControl, parent: HWND); 26 | pub fn uiWindowsControlMinimumSize(control: *mut uiWindowsControl, 27 | width: *mut intmax_t, 28 | height: *mut intmax_t); 29 | pub fn uiWindowsControlMinimumSizeChanged(control: *mut uiWindowsControl); 30 | pub fn uiWindowsControlLayoutRect(control: *mut uiWindowsControl, rect: *mut RECT); 31 | pub fn uiWindowsControlAssignControlIDZOrder(control: *mut uiWindowsControl, 32 | controlID: *mut LONG_PTR, 33 | insertAfter: *mut HWND); 34 | 35 | pub fn uiWindowsAllocControl(n: size_t, typesig: u32, typenamestr: *const c_char) 36 | -> *mut uiWindowsControl; 37 | 38 | pub fn uiWindowsEnsureCreateControlHWND(dwExStyle: DWORD, 39 | lpClassName: LPCWSTR, 40 | lpWindowName: LPCWSTR, 41 | dwStyle: DWORD, 42 | hInstance: HINSTANCE, 43 | lpParam: LPVOID, 44 | useStandardControlFont: BOOL) 45 | -> HWND; 46 | 47 | pub fn uiWindowsEnsureDestroyWindow(hwnd: HWND); 48 | 49 | pub fn uiWindowsEnsureSetParentHWND(hwnd: HWND, parent: HWND); 50 | 51 | pub fn uiWindowsEnsureAssignControlIDZOrder(hwnd: HWND, 52 | controlID: *mut LONG_PTR, 53 | insertAfter: *mut HWND); 54 | 55 | pub fn uiWindowsEnsureGetClientRect(hwnd: HWND, r: *mut RECT); 56 | pub fn uiWindowsEnsureGetWindowRect(hwnd: HWND, r: *mut RECT); 57 | 58 | pub fn uiWindowsWindowText(hwnd: HWND) -> *mut c_char; 59 | pub fn uiWindowsSetWindowText(hwnd: HWND, text: *const c_char); 60 | 61 | pub fn uiWindowsWindowTextWidth(hwnd: HWND) -> intmax_t; 62 | 63 | pub fn uiWindowsEnsureMoveWindowDuringResize(hwnd: HWND, 64 | x: intmax_t, 65 | y: intmax_t, 66 | width: intmax_t, 67 | height: intmax_t); 68 | 69 | pub fn uiWindowsRegisterWM_COMMANDHandler(hwnd: HWND, 70 | handler: extern "C" fn(*mut uiControl, 71 | HWND, 72 | WORD, 73 | *mut LRESULT) 74 | -> BOOL, 75 | c: *mut uiControl); 76 | pub fn uiWindowsUnregisterWM_COMMANDHandler(hwnd: HWND); 77 | 78 | pub fn uiWindowsRegisterWM_NOTIFYHandler(hwnd: HWND, 79 | handler: extern "C" fn(*mut uiControl, 80 | HWND, 81 | *mut NMHDR, 82 | *mut LRESULT) 83 | -> BOOL, 84 | c: *mut uiControl); 85 | pub fn uiWindowsUnregisterWM_NOTIFYHandler(hwnd: HWND); 86 | 87 | pub fn uiWindowsRegisterWM_HSCROLLHandler(hwnd: HWND, 88 | handler: extern "C" fn(*mut uiControl, 89 | HWND, 90 | WORD, 91 | *mut LRESULT) 92 | -> BOOL, 93 | c: *mut uiControl); 94 | pub fn uiWindowsUnregisterWM_HSCROLLHandler(hwnd: HWND); 95 | 96 | pub fn uiWindowsRegisterReceiveWM_WININICHANGE(hwnd: HWND); 97 | pub fn uiWindowsUnregisterReceiveWM_WININICHANGE(hwnd: HWND); 98 | } 99 | 100 | #[repr(C)] 101 | #[derive(Copy, Clone, Debug)] 102 | pub struct uiWindowsSizing { 103 | pub BaseX: c_int, 104 | pub BaseY: c_int, 105 | pub InternalLeading: LONG, 106 | } 107 | 108 | #[link(name = "ui")] 109 | extern { 110 | pub fn uiWindowsGetSizing(hwnd: HWND, sizing: *mut uiWindowsSizing); 111 | pub fn uiWindowsSizingDlgUnitsToPixels(sizing: *mut uiWindowsSizing, 112 | x: *mut c_int, 113 | y: *mut c_int); 114 | pub fn uiWindowsSizingStandardPadding(sizing: *mut uiWindowsSizing, 115 | x: *mut c_int, 116 | y: *mut c_int); 117 | 118 | pub fn uiWindowsMakeContainer(c: *mut uiWindowsControl, 119 | onResize: extern "C" fn(*mut uiWindowsControl) -> HWND) 120 | -> HWND; 121 | 122 | pub fn uiWindowsControlTooSmall(c: *mut uiWindowsControl) -> BOOL; 123 | pub fn uiWindowsControlContinueMinimumSizeChanged(c: *mut uiWindowsControl); 124 | 125 | pub fn uiWindowsControlAssignSoleControlIDZOrder(control: *mut uiWindowsControl); 126 | 127 | pub fn uiWindowsShouldStopSyncEnableState(c: *mut uiWindowsControl, enabled: c_int) -> BOOL; 128 | } 129 | 130 | #[repr(C)] 131 | #[derive(Copy, Clone, PartialEq, Debug)] 132 | pub struct NMHDR { 133 | pub hwndFrom: HWND, 134 | pub idFrom: UINT_PTR, 135 | pub code: UINT, 136 | } 137 | 138 | #[repr(C)] 139 | #[derive(Copy, Clone, PartialEq, Debug)] 140 | pub struct RECT { 141 | pub left: LONG, 142 | pub top: LONG, 143 | pub right: LONG, 144 | pub bottom: LONG, 145 | } 146 | 147 | pub type BOOL = c_int; 148 | 149 | pub type DWORD = c_ulong; 150 | 151 | pub type HANDLE = PVOID; 152 | 153 | pub type HINSTANCE = HANDLE; 154 | 155 | pub type HWND = HANDLE; 156 | 157 | pub type LONG = c_long; 158 | 159 | #[cfg(target_pointer_width = "64")] 160 | pub type LONG_PTR = i64; 161 | #[cfg(not(target_pointer_width = "64"))] 162 | pub type LONG_PTR = c_long; 163 | 164 | pub type LPCWSTR = *const WCHAR; 165 | 166 | pub type LPVOID = *mut c_void; 167 | 168 | pub type LRESULT = LONG_PTR; 169 | 170 | pub type PVOID = *mut c_void; 171 | 172 | pub type UINT = c_uint; 173 | 174 | #[cfg(target_pointer_width = "64")] 175 | pub type UINT_PTR = u64; 176 | #[cfg(not(target_pointer_width = "64"))] 177 | pub type UINT_PTR = c_uint; 178 | 179 | pub type WCHAR = wchar_t; 180 | 181 | pub type WORD = c_ushort; 182 | 183 | -------------------------------------------------------------------------------- /ui/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ui" 3 | version = "0.1.0" 4 | authors = ["Patrick Walton "] 5 | 6 | [dependencies] 7 | bitflags = "0.7" 8 | libc = "*" 9 | 10 | [dependencies.ui-sys] 11 | path = "../ui-sys" 12 | 13 | -------------------------------------------------------------------------------- /ui/examples/controlgallery.rs: -------------------------------------------------------------------------------- 1 | //! An example control gallery: a port of the same `ui` example. 2 | 3 | extern crate ui; 4 | 5 | use ui::{BoxControl, Button, Checkbox, ColorButton, Combobox, DateTimePicker, Entry}; 6 | use ui::{FontButton, Group, InitOptions, Label, Menu, MenuItem, ProgressBar, RadioButtons}; 7 | use ui::{Separator, Slider, Spinbox, Tab, Window}; 8 | 9 | fn run() { 10 | let menu = Menu::new("File"); 11 | menu.append_item("Open").on_clicked(Box::new(open_clicked)); 12 | menu.append_item("Save").on_clicked(Box::new(save_clicked)); 13 | 14 | let menu = Menu::new("Edit"); 15 | menu.append_check_item("Checkable Item"); 16 | menu.append_separator(); 17 | let item = menu.append_item("Disabled Item"); 18 | item.disable(); 19 | menu.append_preferences_item(); 20 | 21 | let menu = Menu::new("Help"); 22 | menu.append_item("Help"); 23 | menu.append_about_item(); 24 | 25 | let mainwin = Window::new("ui Control Gallery", 640, 480, true); 26 | mainwin.set_margined(true); 27 | mainwin.on_closing(Box::new(|_| { 28 | ui::quit(); 29 | false 30 | })); 31 | 32 | let vbox = BoxControl::new_vertical(); 33 | vbox.set_padded(true); 34 | mainwin.set_child(vbox.clone().into()); 35 | 36 | let hbox = BoxControl::new_horizontal(); 37 | hbox.set_padded(true); 38 | vbox.append(hbox.clone().into(), true); 39 | 40 | let group = Group::new("Basic Controls"); 41 | group.set_margined(true); 42 | hbox.append(group.clone().into(), false); 43 | 44 | let inner = BoxControl::new_vertical(); 45 | inner.set_padded(true); 46 | group.set_child(inner.clone().into()); 47 | 48 | inner.append(Button::new("Button").into(), false); 49 | inner.append(Checkbox::new("Checkbox").into(), false); 50 | let entry = Entry::new(); 51 | entry.set_text("Entry"); 52 | inner.append(entry.into(), false); 53 | inner.append(Label::new("Label").into(), false); 54 | inner.append(Separator::new_horizontal().into(), false); 55 | 56 | inner.append(DateTimePicker::new_date_picker().into(), false); 57 | inner.append(DateTimePicker::new_time_picker().into(), false); 58 | inner.append(DateTimePicker::new_date_time_picker().into(), false); 59 | 60 | inner.append(FontButton::new().into(), false); 61 | inner.append(ColorButton::new().into(), false); 62 | 63 | let inner2 = BoxControl::new_vertical(); 64 | inner2.set_padded(true); 65 | hbox.append(inner2.clone().into(), true); 66 | 67 | let group = Group::new("Numbers"); 68 | group.set_margined(true); 69 | inner2.append(group.clone().into(), false); 70 | 71 | let inner = BoxControl::new_vertical(); 72 | inner.set_padded(true); 73 | group.set_child(inner.clone().into()); 74 | 75 | let spinbox = Spinbox::new(0, 100); 76 | spinbox.on_changed(Box::new(|spinbox| update(spinbox.value()))); 77 | inner.append(spinbox.into(), false); 78 | 79 | let slider = Slider::new(0, 100); 80 | slider.on_changed(Box::new(|slider| update(slider.value()))); 81 | inner.append(slider.into(), false); 82 | 83 | let progress_bar = ProgressBar::new(); 84 | inner.append(progress_bar.into(), false); 85 | 86 | let group = Group::new("Lists"); 87 | group.set_margined(true); 88 | inner2.append(group.clone().into(), false); 89 | 90 | let inner = BoxControl::new_vertical(); 91 | inner.set_padded(true); 92 | group.set_child(inner.clone().into()); 93 | 94 | let cbox = Combobox::new(); 95 | cbox.append("Combobox Item 1"); 96 | cbox.append("Combobox Item 2"); 97 | cbox.append("Combobox Item 3"); 98 | inner.append(cbox.into(), false); 99 | 100 | let cbox = Combobox::new_editable(); 101 | cbox.append("Editable Item 1"); 102 | cbox.append("Editable Item 2"); 103 | cbox.append("Editable Item 3"); 104 | inner.append(cbox.into(), false); 105 | 106 | let rb = RadioButtons::new(); 107 | rb.append("Radio Button 1"); 108 | rb.append("Radio Button 2"); 109 | rb.append("Radio Button 3"); 110 | inner.append(rb.into(), true); 111 | 112 | let tab = Tab::new(); 113 | tab.append("Page 1", BoxControl::new_horizontal().into()); 114 | tab.append("Page 2", BoxControl::new_horizontal().into()); 115 | tab.append("Page 3", BoxControl::new_horizontal().into()); 116 | inner2.append(tab.into(), true); 117 | 118 | mainwin.show(); 119 | ui::main(); 120 | } 121 | 122 | pub fn main() { 123 | ui::init(InitOptions).unwrap(); 124 | run(); 125 | ui::uninit(); 126 | } 127 | 128 | fn open_clicked(_: &MenuItem, mainwin: &Window) { 129 | match ui::open_file(mainwin) { 130 | Some(filename) => ui::msg_box(mainwin, "File selected", &*filename), 131 | None => ui::msg_box_error(mainwin, "No file selected", "Don't be alarmed!"), 132 | } 133 | } 134 | 135 | fn save_clicked(_: &MenuItem, mainwin: &Window) { 136 | match ui::open_file(mainwin) { 137 | Some(filename) => { 138 | ui::msg_box(mainwin, "File selected (don't worry, it's still there)", &*filename) 139 | } 140 | None => ui::msg_box_error(mainwin, "No file selected", "Don't be alarmed!"), 141 | } 142 | } 143 | 144 | fn update(_: i64) { 145 | // TODO(pcwalton) 146 | } 147 | 148 | -------------------------------------------------------------------------------- /ui/examples/rustlogo.rs: -------------------------------------------------------------------------------- 1 | //! An example app that displays the Rust logo. 2 | //! 3 | //! FIXME(pcwalton): This is a very broken Rust logo! It was halfheartedly autoconverted from SVG. 4 | 5 | extern crate ui; 6 | 7 | use ui::{Area, AreaDrawParams, AreaHandler, InitOptions, Window}; 8 | use ui::draw::{Brush, FillMode, Path, SolidBrush}; 9 | 10 | struct RustLogoArea; 11 | 12 | trait PathExt { 13 | fn arc2(&self, 14 | x_center: f64, 15 | y_center: f64, 16 | radius: f64, 17 | start_angle: f64, 18 | end_angle: f64, 19 | anticlockwise: i32); 20 | } 21 | 22 | impl PathExt for Path { 23 | fn arc2(&self, 24 | x_center: f64, 25 | y_center: f64, 26 | radius: f64, 27 | start_angle: f64, 28 | end_angle: f64, 29 | anticlockwise: i32) { 30 | self.arc_to(x_center, 31 | y_center, 32 | radius, 33 | start_angle, 34 | end_angle - start_angle, 35 | anticlockwise != 0) 36 | } 37 | } 38 | 39 | impl AreaHandler for RustLogoArea { 40 | fn draw(&mut self, area: &Area, area_draw_params: &AreaDrawParams) { 41 | let path = Path::new(FillMode::Winding); 42 | path.new_figure(67.743,31.035); 43 | path.arc2(0.0,0.0,3.108,-3.1415926088863095,-4.470348358154297e-8,0); 44 | path.arc2(0.0,0.0,3.108,4.4703483581542975e-8,3.1415926088863095,0); 45 | path.new_figure(30.666,59.175); 46 | path.arc2(0.0,0.0,3.108,-3.1415926237874707,-2.9802322387695312e-8,0); 47 | path.arc2(0.0,0.0,3.108,0.0,3.141592653589793,0); 48 | path.new_figure(104.819,59.32); 49 | path.arc2(0.0,0.0,3.108,-3.1415926088863095,-4.470348358154297e-8,0); 50 | path.arc2(0.0,0.0,3.108,4.4703483581542975e-8,3.1415926088863095,0); 51 | path.new_figure(39.663,63.578); 52 | path.bezier_to(41.092999999999996,62.943000000000005,41.739,61.267,41.104,59.834); 53 | path.line_to(39.725,56.716); 54 | path.line_to(45.148,56.716); 55 | path.line_to(45.148,81.16); 56 | path.line_to(34.207,81.16); 57 | path.arc2(0.0,0.0,38.265,2.86422996073528,3.2497157630874733,0); 58 | path.close_figure(); 59 | path.new_figure(55.653000000000006,67.154); 60 | path.line_to(55.653000000000006,59.949); 61 | path.line_to(68.56700000000001,59.949); 62 | path.bezier_to(69.23400000000001,59.949,73.277,60.72,73.277,63.742999999999995); 63 | path.bezier_to(73.277,66.253,70.176,67.15299999999999,67.626,67.15299999999999); 64 | path.close_figure(); 65 | path.new_figure(44.717,102.972); 66 | path.arc2(0.0,0.0,3.108,3.141592653589793,6.283185307179586,0); 67 | path.arc2(0.0,0.0,3.108,0.0,3.141592653589793,0); 68 | path.new_figure(90.768,103.11699999999999); 69 | path.arc2(0.0,0.0,3.108,-3.1415926088863095,-4.470348358154297e-8,0); 70 | path.arc2(0.0,0.0,3.108,4.4703483581542975e-8,3.1415926088863095,0); 71 | path.new_figure(91.729,96.06899999999999); 72 | path.bezier_to(90.198,95.74099999999999,88.692,96.71499999999999,88.364,98.249); 73 | path.line_to(86.804,105.529); 74 | path.arc2(0.0,0.0,38.265,1.1454723568150609,2.005709393175716,0); 75 | path.line_to(53.334,98.09599999999999); 76 | path.bezier_to(53.006,96.564,51.5,95.588,49.970000000000006,95.91699999999999); 77 | path.line_to(43.543000000000006,97.29699999999998); 78 | path.arc2(0.0,0.0,38.265,2.370885356807905,2.5052253278412,0); 79 | path.line_to(71.492,93.37999999999998); 80 | path.bezier_to(71.846,93.37999999999998,72.08200000000001,93.31599999999999,72.08200000000001,92.99399999999999); 81 | path.line_to(72.08200000000001,81.932); 82 | path.bezier_to(72.08200000000001,81.61,71.846,81.546,71.492,81.546); 83 | path.line_to(62.346000000000004,81.546); 84 | path.line_to(62.346000000000004,74.534); 85 | path.line_to(72.238,74.534); 86 | path.bezier_to(73.141,74.534,77.066,74.792,78.321,79.80900000000001); 87 | path.bezier_to(78.714,81.35200000000002,79.577,86.37100000000001,80.167,87.97800000000001); 88 | path.bezier_to(80.755,89.78000000000002,83.149,93.38000000000001,85.7,93.38000000000001); 89 | path.line_to(101.846,93.38000000000001); 90 | path.arc2(0.0,0.0,38.265,0.6416547285438904,0.7834412266197291,0); 91 | path.close_figure(); 92 | path.new_figure(115.667,68.275); 93 | path.arc2(0.0,0.0,38.265,-0.09911109621689877,0.07472573234517861,0); 94 | path.line_to(111.822,74.918); 95 | path.bezier_to(111.429,74.918,111.271,75.176,111.271,75.561); 96 | path.line_to(111.271,77.364); 97 | path.bezier_to(111.271,81.608,108.878,82.531,106.781,82.766); 98 | path.bezier_to(104.784,82.991,102.57000000000001,81.93,102.29700000000001,80.708); 99 | path.bezier_to(101.11900000000001,74.082,99.156,72.667,96.05600000000001,70.222); 100 | path.bezier_to(99.903,67.779,103.906,64.175,103.906,59.35099999999999); 101 | path.bezier_to(103.906,54.141999999999996,100.33500000000001,50.86099999999999,97.90100000000001,49.251999999999995); 102 | path.bezier_to(94.486,47.001,90.70500000000001,46.55,89.68500000000002,46.55); 103 | path.line_to(42.509,46.55); 104 | path.arc2(0.0,0.0,38.265,-2.4116088516416183,-1.7575991851921633,0); 105 | path.line_to(68.703,39.489); 106 | path.bezier_to(69.785,40.622,71.577,40.663999999999994,72.709,39.580999999999996); 107 | path.line_to(78.06400000000001,34.458999999999996); 108 | path.arc2(0.0,0.0,38.265,-1.3856307110991473,-0.5182172818862707,0); 109 | path.line_to(100.59400000000001,61.396); 110 | path.bezier_to(99.96100000000001,62.829,100.60700000000001,64.505,102.036,65.14); 111 | path.close_figure(); 112 | path.new_figure(111.179,65.274); 113 | path.line_to(111.054,63.994); 114 | path.line_to(114.83,60.472); 115 | path.bezier_to(115.598,59.756,115.31099999999999,58.315,114.329,57.949); 116 | path.line_to(109.502,56.144); 117 | path.line_to(109.124,54.897999999999996); 118 | path.line_to(112.13499999999999,50.715999999999994); 119 | path.bezier_to(112.749,49.86599999999999,112.18499999999999,48.50899999999999,111.151,48.33899999999999); 120 | path.line_to(106.06099999999999,47.51099999999999); 121 | path.line_to(105.449,46.36799999999999); 122 | path.line_to(107.588,41.67299999999999); 123 | path.bezier_to(108.026,40.716999999999985,107.21199999999999,39.493999999999986,106.16,39.533999999999985); 124 | path.line_to(100.994,39.713999999999984); 125 | path.line_to(100.178,38.72399999999998); 126 | path.line_to(101.365,33.69199999999998); 127 | path.bezier_to(101.60499999999999,32.66999999999998,100.568,31.63199999999998,99.54599999999999,31.87199999999998); 128 | path.line_to(94.51499999999999,33.05799999999998); 129 | path.line_to(93.52299999999998,32.241999999999976); 130 | path.line_to(93.70399999999998,27.075999999999976); 131 | path.bezier_to(93.74399999999999,26.029999999999976,92.51999999999998,25.212999999999976,91.56599999999997,25.646999999999977); 132 | path.line_to(86.87199999999997,27.786999999999978); 133 | path.line_to(85.72899999999997,27.173999999999978); 134 | path.line_to(84.89899999999997,22.082999999999977); 135 | path.bezier_to(84.73099999999997,21.050999999999977,83.37299999999998,20.486999999999977,82.52299999999997,21.098999999999975); 136 | path.line_to(78.33799999999997,24.109999999999975); 137 | path.line_to(77.09399999999997,23.732999999999976); 138 | path.line_to(75.28899999999996,18.904999999999976); 139 | path.bezier_to(74.92299999999996,17.920999999999978,73.48099999999995,17.637999999999977,72.76699999999995,18.401999999999976); 140 | path.line_to(69.24499999999995,22.180999999999976); 141 | path.line_to(67.96499999999995,22.055999999999976); 142 | path.line_to(65.24499999999995,17.660999999999976); 143 | path.bezier_to(64.69499999999995,16.770999999999976,63.221999999999944,16.770999999999976,62.67399999999995,17.660999999999976); 144 | path.line_to(59.95399999999995,22.055999999999976); 145 | path.line_to(58.67299999999995,22.180999999999976); 146 | path.line_to(55.14999999999995,18.401999999999976); 147 | path.bezier_to(54.43599999999995,17.637999999999977,52.99399999999995,17.920999999999975,52.62799999999995,18.904999999999976); 148 | path.line_to(50.82299999999995,23.732999999999976); 149 | path.line_to(49.57799999999995,24.109999999999975); 150 | path.line_to(45.393999999999956,21.098999999999975); 151 | path.bezier_to(44.543999999999954,20.484999999999975,43.18499999999995,21.050999999999977,43.01699999999995,22.082999999999977); 152 | path.line_to(42.186999999999955,27.173999999999978); 153 | path.line_to(41.043999999999954,27.786999999999978); 154 | path.line_to(36.34999999999995,25.646999999999977); 155 | path.bezier_to(35.39599999999995,25.210999999999977,34.171999999999954,26.029999999999976,34.211999999999954,27.075999999999976); 156 | path.line_to(34.39199999999995,32.241999999999976); 157 | path.line_to(33.399999999999956,33.05799999999998); 158 | path.line_to(28.368999999999957,31.87199999999998); 159 | path.bezier_to(27.34699999999996,31.63399999999998,26.30899999999996,32.66999999999998,26.548999999999957,33.69199999999998); 160 | path.line_to(27.733999999999956,38.723999999999975); 161 | path.line_to(26.919999999999956,39.71399999999998); 162 | path.line_to(21.753999999999955,39.53399999999998); 163 | path.bezier_to(20.711999999999954,39.50399999999998,19.890999999999956,40.71699999999998,20.324999999999957,41.67299999999998); 164 | path.line_to(22.464999999999957,46.36799999999998); 165 | path.line_to(21.851999999999958,47.51099999999998); 166 | path.line_to(16.761999999999958,48.338999999999984); 167 | path.bezier_to(15.727999999999957,48.506999999999984,15.167999999999958,49.865999999999985,15.777999999999958,50.71599999999999); 168 | path.line_to(18.78899999999996,54.89799999999999); 169 | path.line_to(18.41099999999996,56.14399999999999); 170 | path.line_to(13.58299999999996,57.94899999999999); 171 | path.bezier_to(12.602999999999959,58.31499999999999,12.31599999999996,59.75599999999999,13.08199999999996,60.471999999999994); 172 | path.line_to(16.85899999999996,63.99399999999999); 173 | path.line_to(16.73399999999996,65.27399999999999); 174 | path.line_to(12.339999999999959,67.99399999999999); 175 | path.bezier_to(11.449999999999958,68.54399999999998,11.449999999999958,70.01699999999998,12.339999999999959,70.56499999999998); 176 | path.line_to(16.73399999999996,73.28499999999998); 177 | path.line_to(16.85899999999996,74.56499999999998); 178 | path.line_to(13.081999999999958,78.08799999999998); 179 | path.bezier_to(12.315999999999958,78.80199999999998,12.602999999999959,80.24199999999998,13.582999999999958,80.60999999999999); 180 | path.line_to(18.41099999999996,82.41499999999999); 181 | path.line_to(18.78899999999996,83.66099999999999); 182 | path.line_to(15.77799999999996,87.844); 183 | path.bezier_to(15.16599999999996,88.696,15.72899999999996,90.05399999999999,16.76299999999996,90.22); 184 | path.line_to(21.85199999999996,91.048); 185 | path.line_to(22.99699999999996,88.908); 186 | path.line_to(27.689999999999962,180.0); 187 | path.line_to(27.253999999999962,180.0); 188 | path.line_to(29.434999999999963,180.0); 189 | path.line_to(31.573999999999963,180.0); 190 | path.line_to(36.737999999999964,180.0); 191 | path.line_to(37.55399999999997,180.0); 192 | path.line_to(42.58699999999997,180.0); 193 | path.line_to(42.346999999999966,180.0); 194 | path.line_to(43.14499999999997,180.0); 195 | path.line_to(44.96499999999997,180.0); 196 | path.line_to(49.99599999999997,180.0); 197 | path.line_to(50.987999999999964,180.0); 198 | path.line_to(56.154999999999966,180.0); 199 | path.line_to(56.11499999999997,180.0); 200 | path.line_to(57.298999999999964,180.0); 201 | path.line_to(59.43699999999996,180.0); 202 | path.line_to(64.13099999999996,180.0); 203 | path.line_to(65.27399999999996,180.0); 204 | path.line_to(70.36199999999995,180.0); 205 | path.line_to(70.52999999999996,180.0); 206 | path.line_to(72.05699999999996,180.0); 207 | path.line_to(74.43399999999995,180.0); 208 | path.line_to(78.61599999999996,180.0); 209 | path.line_to(79.86199999999995,180.0); 210 | path.line_to(81.66699999999996,180.0); 211 | path.bezier_to(82.03299999999996,180.0,83.47499999999997,180.0,84.18899999999996,180.0); 212 | path.line_to(87.71199999999996,180.0); 213 | path.line_to(88.99299999999997,180.0); 214 | path.line_to(91.71299999999997,180.0); 215 | path.bezier_to(92.26099999999997,180.0,93.73399999999997,180.0,94.28399999999996,180.0); 216 | path.line_to(97.00399999999996,180.0); 217 | path.line_to(98.28399999999996,180.0); 218 | path.line_to(101.80599999999997,180.0); 219 | path.bezier_to(102.51999999999997,180.0,103.96199999999997,180.0,104.32799999999997,180.0); 220 | path.line_to(106.13299999999998,180.0); 221 | path.line_to(107.37899999999998,180.0); 222 | path.line_to(111.56199999999998,180.0); 223 | path.bezier_to(112.41199999999998,180.0,113.76999999999998,180.0,113.93799999999999,180.0); 224 | path.line_to(114.76799999999999,180.0); 225 | path.line_to(115.91099999999999,180.0); 226 | path.line_to(120.60499999999999,180.0); 227 | path.bezier_to(121.55899999999998,180.0,122.78099999999999,180.0,122.743,180.0); 228 | path.line_to(122.56299999999999,180.0); 229 | path.line_to(123.55399999999999,180.0); 230 | path.line_to(128.58499999999998,180.0); 231 | path.bezier_to(129.60699999999997,180.0,130.64399999999998,180.0,130.40399999999997,180.0); 232 | path.line_to(129.21899999999997,180.0); 233 | path.line_to(130.03299999999996,180.0); 234 | path.line_to(135.19899999999996,180.0); 235 | path.bezier_to(136.24099999999996,180.0,137.06499999999997,180.0,136.62699999999995,180.0); 236 | path.line_to(134.48799999999994,180.0); 237 | path.line_to(135.09999999999994,180.0); 238 | path.line_to(140.18999999999994,180.0); 239 | path.bezier_to(141.22599999999994,180.0,141.78799999999995,180.0,141.17399999999995,180.0); 240 | path.line_to(138.16299999999995,180.0); 241 | path.line_to(138.54099999999994,180.0); 242 | path.line_to(143.36799999999994,180.0); 243 | path.bezier_to(144.34999999999994,180.0,144.63699999999994,180.0,143.86899999999994,180.0); 244 | path.line_to(140.09299999999993,180.0); 245 | path.line_to(140.21799999999993,180.0); 246 | path.line_to(144.61199999999994,180.0); 247 | path.bezier_to(145.50199999999992,180.0,145.50299999999993,180.0,144.61299999999994,180.0); 248 | path.end(); 249 | 250 | let brush = Brush::Solid(SolidBrush { 251 | r: 0.0, 252 | g: 0.0, 253 | b: 0.0, 254 | a: 255.0, 255 | }); 256 | area_draw_params.context.fill(&path, &brush); 257 | } 258 | } 259 | 260 | fn run() { 261 | let window = Window::new("Rust logo", 640, 480, true); 262 | window.on_closing(Box::new(|_| { 263 | ui::quit(); 264 | false 265 | })); 266 | 267 | let area = Area::new(Box::new(RustLogoArea)); 268 | window.set_child(area.into()); 269 | window.show(); 270 | ui::main(); 271 | } 272 | 273 | fn main() { 274 | ui::init(InitOptions).unwrap(); 275 | run(); 276 | ui::uninit(); 277 | } 278 | 279 | -------------------------------------------------------------------------------- /ui/src/controls.rs: -------------------------------------------------------------------------------- 1 | //! Functions and types related to widgets. 2 | 3 | use draw; 4 | use ffi_utils::{self, Text}; 5 | use libc::{c_int, c_void}; 6 | use std::ffi::CString; 7 | use std::mem; 8 | use std::ptr; 9 | use ui_sys::{self, uiArea, uiAreaDrawParams, uiAreaHandler, uiAreaKeyEvent, uiAreaMouseEvent}; 10 | use ui_sys::{uiBox, uiButton, uiCheckbox, uiColorButton, uiCombobox, uiControl, uiDateTimePicker}; 11 | use ui_sys::{uiEntry, uiFontButton, uiGroup, uiLabel, uiMultilineEntry, uiProgressBar}; 12 | use ui_sys::{uiRadioButtons, uiSeparator, uiSlider, uiSpinbox, uiTab}; 13 | 14 | pub use ui_sys::uiExtKey as ExtKey; 15 | 16 | // Defines a new control, creating a Rust wrapper, a `Deref` implementation, and a destructor. 17 | // An example of use: 18 | // 19 | // define_control!(Slider, uiSlider, ui_slider) 20 | #[macro_export] 21 | macro_rules! define_control { 22 | ($rust_type:ident, $ui_type:ident, $ui_field:ident) => { 23 | pub struct $rust_type { 24 | $ui_field: *mut $ui_type, 25 | } 26 | 27 | impl ::std::ops::Deref for $rust_type { 28 | type Target = ::controls::Control; 29 | 30 | #[inline] 31 | fn deref(&self) -> &::controls::Control { 32 | // FIXME(pcwalton): $10 says this is undefined behavior. How do I make it not so? 33 | unsafe { 34 | mem::transmute::<&$rust_type, &::controls::Control>(self) 35 | } 36 | } 37 | } 38 | 39 | impl Drop for $rust_type { 40 | #[inline] 41 | fn drop(&mut self) { 42 | // For now this does nothing, but in the future, when `libui` supports proper 43 | // memory management, this will likely need to twiddle reference counts. 44 | } 45 | } 46 | 47 | impl Clone for $rust_type { 48 | #[inline] 49 | fn clone(&self) -> $rust_type { 50 | $rust_type { 51 | $ui_field: self.$ui_field, 52 | } 53 | } 54 | } 55 | 56 | impl Into for $rust_type { 57 | #[inline] 58 | fn into(self) -> Control { 59 | unsafe { 60 | let control = Control::from_ui_control(self.$ui_field as *mut uiControl); 61 | mem::forget(self); 62 | control 63 | } 64 | } 65 | } 66 | 67 | impl $rust_type { 68 | #[inline] 69 | pub unsafe fn from_ui_control($ui_field: *mut $ui_type) -> $rust_type { 70 | $rust_type { 71 | $ui_field: $ui_field 72 | } 73 | } 74 | } 75 | } 76 | } 77 | 78 | pub struct Control { 79 | ui_control: *mut uiControl, 80 | } 81 | 82 | impl Drop for Control { 83 | #[inline] 84 | fn drop(&mut self) { 85 | // For now this does nothing, but in the future, when `libui` supports proper memory 86 | // management, this will likely need to twiddle reference counts. 87 | } 88 | } 89 | 90 | impl Clone for Control { 91 | #[inline] 92 | fn clone(&self) -> Control { 93 | Control { 94 | ui_control: self.ui_control, 95 | } 96 | } 97 | } 98 | 99 | impl Control { 100 | /// Creates a new `Control` object from an existing `uiControl`. 101 | #[inline] 102 | pub unsafe fn from_ui_control(ui_control: *mut uiControl) -> Control { 103 | Control { 104 | ui_control: ui_control, 105 | } 106 | } 107 | 108 | #[inline] 109 | pub fn as_ui_control(&self) -> *mut uiControl { 110 | self.ui_control 111 | } 112 | 113 | /// Destroys a control. Any use of the control after this is use-after-free; therefore, this 114 | /// is marked unsafe. 115 | #[inline] 116 | pub unsafe fn destroy(&self) { 117 | // Don't check for initialization here since this can be run during deinitialization. 118 | ui_sys::uiControlDestroy(self.ui_control) 119 | } 120 | 121 | #[inline] 122 | pub fn handle(&self) -> usize { 123 | ffi_utils::ensure_initialized(); 124 | unsafe { 125 | ui_sys::uiControlHandle(self.ui_control) 126 | } 127 | } 128 | 129 | #[inline] 130 | pub fn parent(&self) -> Option { 131 | ffi_utils::ensure_initialized(); 132 | unsafe { 133 | let ui_control = ui_sys::uiControlParent(self.ui_control); 134 | if ui_control.is_null() { 135 | None 136 | } else { 137 | Some(Control::from_ui_control(ui_control)) 138 | } 139 | } 140 | } 141 | 142 | #[inline] 143 | pub unsafe fn set_parent(&self, parent: Option<&Control>) { 144 | ffi_utils::ensure_initialized(); 145 | ui_sys::uiControlSetParent(self.ui_control, 146 | match parent { 147 | None => ptr::null_mut(), 148 | Some(parent) => parent.ui_control, 149 | }) 150 | } 151 | 152 | #[inline] 153 | pub fn toplevel(&self) -> bool { 154 | ffi_utils::ensure_initialized(); 155 | unsafe { 156 | ui_sys::uiControlToplevel(self.ui_control) != 0 157 | } 158 | } 159 | 160 | #[inline] 161 | pub fn visible(&self) -> bool { 162 | ffi_utils::ensure_initialized(); 163 | unsafe { 164 | ui_sys::uiControlVisible(self.ui_control) != 0 165 | } 166 | } 167 | 168 | #[inline] 169 | pub fn show(&self) { 170 | ffi_utils::ensure_initialized(); 171 | unsafe { 172 | ui_sys::uiControlShow(self.ui_control) 173 | } 174 | } 175 | 176 | #[inline] 177 | pub fn hide(&self) { 178 | ffi_utils::ensure_initialized(); 179 | unsafe { 180 | ui_sys::uiControlHide(self.ui_control) 181 | } 182 | } 183 | 184 | #[inline] 185 | pub fn enabled(&self) -> bool { 186 | ffi_utils::ensure_initialized(); 187 | unsafe { 188 | ui_sys::uiControlEnabled(self.ui_control) != 0 189 | } 190 | } 191 | 192 | #[inline] 193 | pub fn enable(&self) { 194 | ffi_utils::ensure_initialized(); 195 | unsafe { 196 | ui_sys::uiControlEnable(self.ui_control) 197 | } 198 | } 199 | 200 | #[inline] 201 | pub fn disable(&self) { 202 | ffi_utils::ensure_initialized(); 203 | unsafe { 204 | ui_sys::uiControlDisable(self.ui_control) 205 | } 206 | } 207 | } 208 | 209 | define_control!(Button, uiButton, ui_button); 210 | 211 | impl Button { 212 | #[inline] 213 | pub fn text(&self) -> Text { 214 | ffi_utils::ensure_initialized(); 215 | unsafe { 216 | Text::new(ui_sys::uiButtonText(self.ui_button)) 217 | } 218 | } 219 | 220 | #[inline] 221 | pub fn set_text(&self, text: &str) { 222 | ffi_utils::ensure_initialized(); 223 | unsafe { 224 | let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); 225 | ui_sys::uiButtonSetText(self.ui_button, c_string.as_ptr()) 226 | } 227 | } 228 | 229 | #[inline] 230 | pub fn on_clicked(&self, callback: Box) { 231 | ffi_utils::ensure_initialized(); 232 | unsafe { 233 | let mut data: Box> = Box::new(callback); 234 | ui_sys::uiButtonOnClicked(self.ui_button, 235 | c_callback, 236 | &mut *data as *mut Box as *mut c_void); 237 | mem::forget(data); 238 | } 239 | 240 | extern "C" fn c_callback(button: *mut uiButton, data: *mut c_void) { 241 | unsafe { 242 | let button = Button { 243 | ui_button: button, 244 | }; 245 | mem::transmute::<*mut c_void, &mut Box>(data)(&button) 246 | } 247 | } 248 | } 249 | 250 | #[inline] 251 | pub fn new(text: &str) -> Button { 252 | ffi_utils::ensure_initialized(); 253 | unsafe { 254 | let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); 255 | Button::from_ui_control(ui_sys::uiNewButton(c_string.as_ptr())) 256 | } 257 | } 258 | } 259 | 260 | define_control!(BoxControl, uiBox, ui_box); 261 | 262 | impl BoxControl { 263 | #[inline] 264 | pub fn append(&self, child: Control, stretchy: bool) { 265 | ffi_utils::ensure_initialized(); 266 | unsafe { 267 | assert!(child.parent().is_none()); 268 | ui_sys::uiBoxAppend(self.ui_box, child.ui_control, stretchy as c_int) 269 | } 270 | } 271 | 272 | /// FIXME(pcwalton): This will leak the deleted control! We have no way of actually getting it 273 | /// to decrement its reference count per `libui`'s UI as of today, unless we maintain a 274 | /// separate list of children ourselves… 275 | #[inline] 276 | pub fn delete(&self, index: u64) { 277 | ffi_utils::ensure_initialized(); 278 | unsafe { 279 | ui_sys::uiBoxDelete(self.ui_box, index) 280 | } 281 | } 282 | 283 | #[inline] 284 | pub fn padded(&self) -> bool { 285 | ffi_utils::ensure_initialized(); 286 | unsafe { 287 | ui_sys::uiBoxPadded(self.ui_box) != 0 288 | } 289 | } 290 | 291 | #[inline] 292 | pub fn set_padded(&self, padded: bool) { 293 | ffi_utils::ensure_initialized(); 294 | unsafe { 295 | ui_sys::uiBoxSetPadded(self.ui_box, padded as c_int) 296 | } 297 | } 298 | 299 | #[inline] 300 | pub fn new_horizontal() -> BoxControl { 301 | ffi_utils::ensure_initialized(); 302 | unsafe { 303 | BoxControl::from_ui_control(ui_sys::uiNewHorizontalBox()) 304 | } 305 | } 306 | 307 | #[inline] 308 | pub fn new_vertical() -> BoxControl { 309 | ffi_utils::ensure_initialized(); 310 | unsafe { 311 | BoxControl::from_ui_control(ui_sys::uiNewVerticalBox()) 312 | } 313 | } 314 | } 315 | 316 | define_control!(Entry, uiEntry, ui_entry); 317 | 318 | impl Entry { 319 | #[inline] 320 | pub fn text(&self) -> Text { 321 | ffi_utils::ensure_initialized(); 322 | unsafe { 323 | Text::new(ui_sys::uiEntryText(self.ui_entry)) 324 | } 325 | } 326 | 327 | #[inline] 328 | pub fn set_text(&self, text: &str) { 329 | ffi_utils::ensure_initialized(); 330 | unsafe { 331 | let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); 332 | ui_sys::uiEntrySetText(self.ui_entry, c_string.as_ptr()) 333 | } 334 | } 335 | 336 | #[inline] 337 | pub fn on_changed(&self, callback: Box) { 338 | ffi_utils::ensure_initialized(); 339 | unsafe { 340 | let mut data: Box> = Box::new(callback); 341 | ui_sys::uiEntryOnChanged(self.ui_entry, 342 | c_callback, 343 | &mut *data as *mut Box as *mut c_void); 344 | mem::forget(data); 345 | } 346 | 347 | extern "C" fn c_callback(entry: *mut uiEntry, data: *mut c_void) { 348 | unsafe { 349 | let entry = Entry::from_ui_control(entry); 350 | mem::transmute::<*mut c_void, &mut Box>(data)(&entry); 351 | mem::forget(entry); 352 | } 353 | } 354 | } 355 | 356 | #[inline] 357 | pub fn read_only(&self) -> bool { 358 | ffi_utils::ensure_initialized(); 359 | unsafe { 360 | ui_sys::uiEntryReadOnly(self.ui_entry) != 0 361 | } 362 | } 363 | 364 | #[inline] 365 | pub fn set_read_only(&self, readonly: bool) { 366 | ffi_utils::ensure_initialized(); 367 | unsafe { 368 | ui_sys::uiEntrySetReadOnly(self.ui_entry, readonly as c_int) 369 | } 370 | } 371 | 372 | #[inline] 373 | pub fn new() -> Entry { 374 | ffi_utils::ensure_initialized(); 375 | unsafe { 376 | Entry::from_ui_control(ui_sys::uiNewEntry()) 377 | } 378 | } 379 | } 380 | 381 | define_control!(Checkbox, uiCheckbox, ui_checkbox); 382 | 383 | impl Checkbox { 384 | #[inline] 385 | pub fn text(&self) -> Text { 386 | ffi_utils::ensure_initialized(); 387 | unsafe { 388 | Text::new(ui_sys::uiCheckboxText(self.ui_checkbox)) 389 | } 390 | } 391 | 392 | #[inline] 393 | pub fn set_text(&self, text: &str) { 394 | ffi_utils::ensure_initialized(); 395 | unsafe { 396 | let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); 397 | ui_sys::uiCheckboxSetText(self.ui_checkbox, c_string.as_ptr()) 398 | } 399 | } 400 | 401 | #[inline] 402 | pub fn on_toggled(&self, callback: Box) { 403 | ffi_utils::ensure_initialized(); 404 | unsafe { 405 | let mut data: Box> = Box::new(callback); 406 | ui_sys::uiCheckboxOnToggled(self.ui_checkbox, 407 | c_callback, 408 | &mut *data as *mut Box as *mut c_void); 409 | mem::forget(data); 410 | } 411 | 412 | extern "C" fn c_callback(checkbox: *mut uiCheckbox, data: *mut c_void) { 413 | unsafe { 414 | let checkbox = Checkbox::from_ui_control(checkbox); 415 | mem::transmute::<*mut c_void, &mut Box>(data)(&checkbox); 416 | mem::forget(checkbox) 417 | } 418 | } 419 | } 420 | 421 | #[inline] 422 | pub fn checked(&self) -> bool { 423 | ffi_utils::ensure_initialized(); 424 | unsafe { 425 | ui_sys::uiCheckboxChecked(self.ui_checkbox) != 0 426 | } 427 | } 428 | 429 | #[inline] 430 | pub fn set_checked(&self, checked: bool) { 431 | ffi_utils::ensure_initialized(); 432 | unsafe { 433 | ui_sys::uiCheckboxSetChecked(self.ui_checkbox, checked as c_int) 434 | } 435 | } 436 | 437 | #[inline] 438 | pub fn new(text: &str) -> Checkbox { 439 | ffi_utils::ensure_initialized(); 440 | unsafe { 441 | let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); 442 | Checkbox::from_ui_control(ui_sys::uiNewCheckbox(c_string.as_ptr())) 443 | } 444 | } 445 | } 446 | 447 | define_control!(Label, uiLabel, ui_label); 448 | 449 | impl Label { 450 | #[inline] 451 | pub fn text(&self) -> Text { 452 | ffi_utils::ensure_initialized(); 453 | unsafe { 454 | Text::new(ui_sys::uiLabelText(self.ui_label)) 455 | } 456 | } 457 | 458 | #[inline] 459 | pub fn set_text(&self, text: &str) { 460 | ffi_utils::ensure_initialized(); 461 | unsafe { 462 | let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); 463 | ui_sys::uiLabelSetText(self.ui_label, c_string.as_ptr()) 464 | } 465 | } 466 | 467 | #[inline] 468 | pub fn new(text: &str) -> Label { 469 | ffi_utils::ensure_initialized(); 470 | unsafe { 471 | let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); 472 | Label::from_ui_control(ui_sys::uiNewLabel(c_string.as_ptr())) 473 | } 474 | } 475 | } 476 | 477 | define_control!(Tab, uiTab, ui_tab); 478 | 479 | impl Tab { 480 | #[inline] 481 | pub fn append(&self, name: &str, control: Control) { 482 | ffi_utils::ensure_initialized(); 483 | unsafe { 484 | let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); 485 | ui_sys::uiTabAppend(self.ui_tab, c_string.as_ptr(), control.ui_control) 486 | } 487 | } 488 | 489 | #[inline] 490 | pub fn insert_at(&self, name: &str, before: u64, control: Control) { 491 | ffi_utils::ensure_initialized(); 492 | unsafe { 493 | let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); 494 | ui_sys::uiTabInsertAt(self.ui_tab, c_string.as_ptr(), before, control.ui_control) 495 | } 496 | } 497 | 498 | /// FIXME(pcwalton): This will leak the deleted control! We have no way of actually getting it 499 | /// to decrement its reference count per `libui`'s UI as of today, unless we maintain a 500 | /// separate list of children ourselves… 501 | #[inline] 502 | pub fn delete(&self, index: u64) { 503 | ffi_utils::ensure_initialized(); 504 | unsafe { 505 | ui_sys::uiTabDelete(self.ui_tab, index) 506 | } 507 | } 508 | 509 | #[inline] 510 | pub fn margined(&self, page: u64) -> bool { 511 | ffi_utils::ensure_initialized(); 512 | unsafe { 513 | ui_sys::uiTabMargined(self.ui_tab, page) != 0 514 | } 515 | } 516 | 517 | #[inline] 518 | pub fn set_margined(&self, page: u64, margined: bool) { 519 | ffi_utils::ensure_initialized(); 520 | unsafe { 521 | ui_sys::uiTabSetMargined(self.ui_tab, page, margined as c_int) 522 | } 523 | } 524 | 525 | #[inline] 526 | pub fn new() -> Tab { 527 | ffi_utils::ensure_initialized(); 528 | unsafe { 529 | Tab::from_ui_control(ui_sys::uiNewTab()) 530 | } 531 | } 532 | } 533 | 534 | define_control!(Group, uiGroup, ui_group); 535 | 536 | impl Group { 537 | #[inline] 538 | pub fn title(&self) -> Text { 539 | ffi_utils::ensure_initialized(); 540 | unsafe { 541 | Text::new(ui_sys::uiGroupTitle(self.ui_group)) 542 | } 543 | } 544 | 545 | #[inline] 546 | pub fn set_title(&self, title: &str) { 547 | ffi_utils::ensure_initialized(); 548 | unsafe { 549 | let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); 550 | ui_sys::uiGroupSetTitle(self.ui_group, c_string.as_ptr()) 551 | } 552 | } 553 | 554 | #[inline] 555 | pub fn set_child(&self, child: Control) { 556 | ffi_utils::ensure_initialized(); 557 | unsafe { 558 | ui_sys::uiGroupSetChild(self.ui_group, child.ui_control) 559 | } 560 | } 561 | 562 | #[inline] 563 | pub fn margined(&self) -> bool { 564 | ffi_utils::ensure_initialized(); 565 | unsafe { 566 | ui_sys::uiGroupMargined(self.ui_group) != 0 567 | } 568 | } 569 | 570 | #[inline] 571 | pub fn set_margined(&self, margined: bool) { 572 | ffi_utils::ensure_initialized(); 573 | unsafe { 574 | ui_sys::uiGroupSetMargined(self.ui_group, margined as c_int) 575 | } 576 | } 577 | 578 | #[inline] 579 | pub fn new(title: &str) -> Group { 580 | ffi_utils::ensure_initialized(); 581 | unsafe { 582 | let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); 583 | Group::from_ui_control(ui_sys::uiNewGroup(c_string.as_ptr())) 584 | } 585 | } 586 | } 587 | 588 | define_control!(Spinbox, uiSpinbox, ui_spinbox); 589 | 590 | impl Spinbox { 591 | #[inline] 592 | pub fn value(&self) -> i64 { 593 | ffi_utils::ensure_initialized(); 594 | unsafe { 595 | ui_sys::uiSpinboxValue(self.ui_spinbox) 596 | } 597 | } 598 | 599 | #[inline] 600 | pub fn set_value(&self, value: i64) { 601 | ffi_utils::ensure_initialized(); 602 | unsafe { 603 | ui_sys::uiSpinboxSetValue(self.ui_spinbox, value) 604 | } 605 | } 606 | 607 | #[inline] 608 | pub fn on_changed(&self, callback: Box) { 609 | ffi_utils::ensure_initialized(); 610 | unsafe { 611 | let mut data: Box> = Box::new(callback); 612 | ui_sys::uiSpinboxOnChanged(self.ui_spinbox, 613 | c_callback, 614 | &mut *data as *mut Box as *mut c_void); 615 | mem::forget(data); 616 | } 617 | 618 | extern "C" fn c_callback(spinbox: *mut uiSpinbox, data: *mut c_void) { 619 | unsafe { 620 | let spinbox = Spinbox::from_ui_control(spinbox); 621 | mem::transmute::<*mut c_void, &mut Box>(data)(&spinbox); 622 | mem::forget(spinbox); 623 | } 624 | } 625 | } 626 | 627 | #[inline] 628 | pub fn new(min: i64, max: i64) -> Spinbox { 629 | ffi_utils::ensure_initialized(); 630 | unsafe { 631 | Spinbox::from_ui_control(ui_sys::uiNewSpinbox(min, max)) 632 | } 633 | } 634 | } 635 | 636 | define_control!(ProgressBar, uiProgressBar, ui_progress_bar); 637 | 638 | impl ProgressBar { 639 | #[inline] 640 | pub fn set_value(&self, n: i32) { 641 | ffi_utils::ensure_initialized(); 642 | unsafe { 643 | ui_sys::uiProgressBarSetValue(self.ui_progress_bar, n) 644 | } 645 | } 646 | 647 | #[inline] 648 | pub fn new() -> ProgressBar { 649 | ffi_utils::ensure_initialized(); 650 | unsafe { 651 | ProgressBar::from_ui_control(ui_sys::uiNewProgressBar()) 652 | } 653 | } 654 | } 655 | 656 | define_control!(Slider, uiSlider, ui_slider); 657 | 658 | impl Slider { 659 | #[inline] 660 | pub fn value(&self) -> i64 { 661 | ffi_utils::ensure_initialized(); 662 | unsafe { 663 | ui_sys::uiSliderValue(self.ui_slider) 664 | } 665 | } 666 | 667 | #[inline] 668 | pub fn set_value(&self, value: i64) { 669 | ffi_utils::ensure_initialized(); 670 | unsafe { 671 | ui_sys::uiSliderSetValue(self.ui_slider, value) 672 | } 673 | } 674 | 675 | #[inline] 676 | pub fn on_changed(&self, callback: Box) { 677 | ffi_utils::ensure_initialized(); 678 | unsafe { 679 | let mut data: Box> = Box::new(callback); 680 | ui_sys::uiSliderOnChanged(self.ui_slider, 681 | c_callback, 682 | &mut *data as *mut Box as *mut c_void); 683 | mem::forget(data); 684 | } 685 | 686 | extern "C" fn c_callback(slider: *mut uiSlider, data: *mut c_void) { 687 | unsafe { 688 | let slider = Slider::from_ui_control(slider); 689 | mem::transmute::<*mut c_void, &mut Box>(data)(&slider); 690 | mem::forget(slider); 691 | } 692 | } 693 | } 694 | 695 | #[inline] 696 | pub fn new(min: i64, max: i64) -> Slider { 697 | ffi_utils::ensure_initialized(); 698 | unsafe { 699 | Slider::from_ui_control(ui_sys::uiNewSlider(min, max)) 700 | } 701 | } 702 | } 703 | 704 | define_control!(Separator, uiSeparator, ui_separator); 705 | 706 | impl Separator { 707 | #[inline] 708 | pub fn new_horizontal() -> Separator { 709 | ffi_utils::ensure_initialized(); 710 | unsafe { 711 | Separator::from_ui_control(ui_sys::uiNewHorizontalSeparator()) 712 | } 713 | } 714 | } 715 | 716 | define_control!(Combobox, uiCombobox, ui_combobox); 717 | 718 | impl Combobox { 719 | #[inline] 720 | pub fn append(&self, name: &str) { 721 | ffi_utils::ensure_initialized(); 722 | unsafe { 723 | let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); 724 | ui_sys::uiComboboxAppend(self.ui_combobox, c_string.as_ptr()) 725 | } 726 | } 727 | 728 | #[inline] 729 | pub fn selected(&self) -> i64 { 730 | ffi_utils::ensure_initialized(); 731 | unsafe { 732 | ui_sys::uiComboboxSelected(self.ui_combobox) 733 | } 734 | } 735 | 736 | #[inline] 737 | pub fn set_selected(&self, n: i64) { 738 | ffi_utils::ensure_initialized(); 739 | unsafe { 740 | ui_sys::uiComboboxSetSelected(self.ui_combobox, n) 741 | } 742 | } 743 | 744 | #[inline] 745 | pub fn on_selected(&self, callback: Box) { 746 | ffi_utils::ensure_initialized(); 747 | unsafe { 748 | let mut data: Box> = Box::new(callback); 749 | ui_sys::uiComboboxOnSelected(self.ui_combobox, 750 | c_callback, 751 | &mut *data as *mut Box as *mut c_void); 752 | mem::forget(data); 753 | } 754 | 755 | extern "C" fn c_callback(combobox: *mut uiCombobox, data: *mut c_void) { 756 | unsafe { 757 | let combobox = Combobox::from_ui_control(combobox); 758 | mem::transmute::<*mut c_void, &mut Box>(data)(&combobox); 759 | mem::forget(combobox); 760 | } 761 | } 762 | } 763 | 764 | #[inline] 765 | pub fn new() -> Combobox { 766 | ffi_utils::ensure_initialized(); 767 | unsafe { 768 | Combobox::from_ui_control(ui_sys::uiNewCombobox()) 769 | } 770 | } 771 | 772 | #[inline] 773 | pub fn new_editable() -> Combobox { 774 | ffi_utils::ensure_initialized(); 775 | unsafe { 776 | Combobox::from_ui_control(ui_sys::uiNewEditableCombobox()) 777 | } 778 | } 779 | } 780 | 781 | // FIXME(pcwalton): Are these supposed to be a subclass of something? They don't seem very usable 782 | // with just the `uiRadioButtons*` methods… 783 | define_control!(RadioButtons, uiRadioButtons, ui_radio_buttons); 784 | 785 | impl RadioButtons { 786 | #[inline] 787 | pub fn append(&self, name: &str) { 788 | ffi_utils::ensure_initialized(); 789 | unsafe { 790 | let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); 791 | ui_sys::uiRadioButtonsAppend(self.ui_radio_buttons, c_string.as_ptr()) 792 | } 793 | } 794 | 795 | #[inline] 796 | pub fn new() -> RadioButtons { 797 | ffi_utils::ensure_initialized(); 798 | unsafe { 799 | RadioButtons::from_ui_control(ui_sys::uiNewRadioButtons()) 800 | } 801 | } 802 | } 803 | 804 | // FIXME(pcwalton): Are these supposed to be a subclass of something? They don't seem very usable 805 | // with just the `uiDatetimePicker*` methods… 806 | define_control!(DateTimePicker, uiDateTimePicker, ui_date_time_picker); 807 | 808 | impl DateTimePicker { 809 | pub fn new_date_time_picker() -> DateTimePicker { 810 | ffi_utils::ensure_initialized(); 811 | unsafe { 812 | DateTimePicker::from_ui_control(ui_sys::uiNewDateTimePicker()) 813 | } 814 | } 815 | 816 | pub fn new_date_picker() -> DateTimePicker { 817 | ffi_utils::ensure_initialized(); 818 | unsafe { 819 | DateTimePicker::from_ui_control(ui_sys::uiNewDatePicker()) 820 | } 821 | } 822 | 823 | pub fn new_time_picker() -> DateTimePicker { 824 | ffi_utils::ensure_initialized(); 825 | unsafe { 826 | DateTimePicker::from_ui_control(ui_sys::uiNewTimePicker()) 827 | } 828 | } 829 | } 830 | 831 | define_control!(MultilineEntry, uiMultilineEntry, ui_multiline_entry); 832 | 833 | impl MultilineEntry { 834 | #[inline] 835 | pub fn text(&self) -> Text { 836 | ffi_utils::ensure_initialized(); 837 | unsafe { 838 | Text::new(ui_sys::uiMultilineEntryText(self.ui_multiline_entry)) 839 | } 840 | } 841 | 842 | #[inline] 843 | pub fn set_text(&self, text: &str) { 844 | ffi_utils::ensure_initialized(); 845 | unsafe { 846 | let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); 847 | ui_sys::uiMultilineEntrySetText(self.ui_multiline_entry, c_string.as_ptr()) 848 | } 849 | } 850 | 851 | #[inline] 852 | pub fn on_changed(&self, callback: Box) { 853 | ffi_utils::ensure_initialized(); 854 | unsafe { 855 | let mut data: Box> = Box::new(callback); 856 | ui_sys::uiMultilineEntryOnChanged(self.ui_multiline_entry, 857 | c_callback, 858 | &mut *data as *mut Box as 859 | *mut c_void); 860 | mem::forget(data); 861 | } 862 | 863 | extern "C" fn c_callback(multiline_entry: *mut uiMultilineEntry, data: *mut c_void) { 864 | unsafe { 865 | let multiline_entry = MultilineEntry::from_ui_control(multiline_entry); 866 | mem::transmute::<*mut c_void, 867 | &mut Box>(data)(&multiline_entry); 868 | mem::forget(multiline_entry); 869 | } 870 | } 871 | } 872 | 873 | #[inline] 874 | pub fn read_only(&self) -> bool { 875 | ffi_utils::ensure_initialized(); 876 | unsafe { 877 | ui_sys::uiMultilineEntryReadOnly(self.ui_multiline_entry) != 0 878 | } 879 | } 880 | 881 | #[inline] 882 | pub fn set_read_only(&self, readonly: bool) { 883 | ffi_utils::ensure_initialized(); 884 | unsafe { 885 | ui_sys::uiMultilineEntrySetReadOnly(self.ui_multiline_entry, readonly as c_int) 886 | } 887 | } 888 | 889 | #[inline] 890 | pub fn new() -> MultilineEntry { 891 | ffi_utils::ensure_initialized(); 892 | unsafe { 893 | MultilineEntry::from_ui_control(ui_sys::uiNewMultilineEntry()) 894 | } 895 | } 896 | } 897 | 898 | pub trait AreaHandler { 899 | fn draw(&mut self, _area: &Area, _area_draw_params: &AreaDrawParams) {} 900 | fn mouse_event(&mut self, _area: &Area, _area_mouse_event: &AreaMouseEvent) {} 901 | fn mouse_crossed(&mut self, _area: &Area, _left: bool) {} 902 | fn drag_broken(&mut self, _area: &Area) {} 903 | fn key_event(&mut self, _area: &Area, _area_key_event: &AreaKeyEvent) -> bool { 904 | true 905 | } 906 | } 907 | 908 | #[repr(C)] 909 | struct RustAreaHandler { 910 | ui_area_handler: uiAreaHandler, 911 | trait_object: Box, 912 | } 913 | 914 | impl RustAreaHandler { 915 | #[inline] 916 | fn new(trait_object: Box) -> Box { 917 | ffi_utils::ensure_initialized(); 918 | return Box::new(RustAreaHandler { 919 | ui_area_handler: uiAreaHandler { 920 | Draw: draw, 921 | MouseEvent: mouse_event, 922 | MouseCrossed: mouse_crossed, 923 | DragBroken: drag_broken, 924 | KeyEvent: key_event, 925 | }, 926 | trait_object: trait_object, 927 | }); 928 | 929 | extern "C" fn draw(ui_area_handler: *mut uiAreaHandler, 930 | ui_area: *mut uiArea, 931 | ui_area_draw_params: *mut uiAreaDrawParams) { 932 | unsafe { 933 | let area = Area::from_ui_area(ui_area); 934 | let area_draw_params = 935 | AreaDrawParams::from_ui_area_draw_params(&*ui_area_draw_params); 936 | (*(ui_area_handler as *mut RustAreaHandler)).trait_object.draw(&area, 937 | &area_draw_params); 938 | mem::forget(area_draw_params); 939 | mem::forget(area); 940 | } 941 | } 942 | 943 | extern "C" fn mouse_event(ui_area_handler: *mut uiAreaHandler, 944 | ui_area: *mut uiArea, 945 | ui_area_mouse_event: *mut uiAreaMouseEvent) { 946 | unsafe { 947 | let area = Area::from_ui_area(ui_area); 948 | let area_mouse_event = 949 | AreaMouseEvent::from_ui_area_mouse_event(&*ui_area_mouse_event); 950 | (*(ui_area_handler as *mut RustAreaHandler)).trait_object 951 | .mouse_event(&area, &area_mouse_event); 952 | mem::forget(area_mouse_event); 953 | mem::forget(area); 954 | } 955 | } 956 | 957 | extern "C" fn mouse_crossed(ui_area_handler: *mut uiAreaHandler, 958 | ui_area: *mut uiArea, 959 | left: c_int) { 960 | unsafe { 961 | let area = Area::from_ui_area(ui_area); 962 | (*(ui_area_handler as *mut RustAreaHandler)).trait_object.mouse_crossed(&area, 963 | left != 0); 964 | mem::forget(area); 965 | } 966 | } 967 | 968 | extern "C" fn drag_broken(ui_area_handler: *mut uiAreaHandler, ui_area: *mut uiArea) { 969 | unsafe { 970 | let area = Area::from_ui_area(ui_area); 971 | (*(ui_area_handler as *mut RustAreaHandler)).trait_object.drag_broken(&area); 972 | mem::forget(area); 973 | } 974 | } 975 | 976 | extern "C" fn key_event(ui_area_handler: *mut uiAreaHandler, 977 | ui_area: *mut uiArea, 978 | ui_area_key_event: *mut uiAreaKeyEvent) 979 | -> c_int { 980 | unsafe { 981 | let area = Area::from_ui_area(ui_area); 982 | let area_key_event = AreaKeyEvent::from_ui_area_key_event(&*ui_area_key_event); 983 | let result = 984 | (*(ui_area_handler as *mut RustAreaHandler)).trait_object 985 | .key_event(&area, &area_key_event); 986 | mem::forget(area_key_event); 987 | mem::forget(area); 988 | result as c_int 989 | } 990 | } 991 | } 992 | } 993 | 994 | define_control!(Area, uiArea, ui_area); 995 | 996 | impl Area { 997 | #[inline] 998 | pub unsafe fn from_ui_area(ui_area: *mut uiArea) -> Area { 999 | Area { 1000 | ui_area: ui_area, 1001 | } 1002 | } 1003 | 1004 | #[inline] 1005 | pub fn set_size(&self, width: i64, height: i64) { 1006 | ffi_utils::ensure_initialized(); 1007 | unsafe { 1008 | ui_sys::uiAreaSetSize(self.ui_area, width, height) 1009 | } 1010 | } 1011 | 1012 | #[inline] 1013 | pub fn queue_redraw_all(&self) { 1014 | ffi_utils::ensure_initialized(); 1015 | unsafe { 1016 | ui_sys::uiAreaQueueRedrawAll(self.ui_area) 1017 | } 1018 | } 1019 | 1020 | #[inline] 1021 | pub fn scroll_to(&self, x: f64, y: f64, width: f64, height: f64) { 1022 | ffi_utils::ensure_initialized(); 1023 | unsafe { 1024 | ui_sys::uiAreaScrollTo(self.ui_area, x, y, width, height) 1025 | } 1026 | } 1027 | 1028 | #[inline] 1029 | pub fn new(area_handler: Box) -> Area { 1030 | ffi_utils::ensure_initialized(); 1031 | unsafe { 1032 | let mut rust_area_handler = RustAreaHandler::new(area_handler); 1033 | let area = 1034 | Area::from_ui_control(ui_sys::uiNewArea(&mut *rust_area_handler as 1035 | *mut RustAreaHandler as 1036 | *mut uiAreaHandler)); 1037 | mem::forget(rust_area_handler); 1038 | area 1039 | } 1040 | } 1041 | 1042 | #[inline] 1043 | pub fn new_scrolling(area_handler: Box, width: i64, height: i64) -> Area { 1044 | ffi_utils::ensure_initialized(); 1045 | unsafe { 1046 | let mut rust_area_handler = RustAreaHandler::new(area_handler); 1047 | let area = 1048 | Area::from_ui_control(ui_sys::uiNewScrollingArea(&mut *rust_area_handler as 1049 | *mut RustAreaHandler as 1050 | *mut uiAreaHandler, 1051 | width, 1052 | height)); 1053 | mem::forget(rust_area_handler); 1054 | area 1055 | } 1056 | } 1057 | } 1058 | 1059 | pub struct AreaDrawParams { 1060 | pub context: draw::Context, 1061 | 1062 | pub area_width: f64, 1063 | pub area_height: f64, 1064 | 1065 | pub clip_x: f64, 1066 | pub clip_y: f64, 1067 | pub clip_width: f64, 1068 | pub clip_height: f64, 1069 | } 1070 | 1071 | impl AreaDrawParams { 1072 | #[inline] 1073 | unsafe fn from_ui_area_draw_params(ui_area_draw_params: &uiAreaDrawParams) -> AreaDrawParams { 1074 | ffi_utils::ensure_initialized(); 1075 | AreaDrawParams { 1076 | context: draw::Context::from_ui_draw_context(ui_area_draw_params.Context), 1077 | area_width: ui_area_draw_params.AreaWidth, 1078 | area_height: ui_area_draw_params.AreaHeight, 1079 | clip_x: ui_area_draw_params.ClipX, 1080 | clip_y: ui_area_draw_params.ClipY, 1081 | clip_width: ui_area_draw_params.ClipWidth, 1082 | clip_height: ui_area_draw_params.ClipHeight, 1083 | } 1084 | } 1085 | } 1086 | 1087 | bitflags! { 1088 | pub flags Modifiers: u8 { 1089 | const MODIFIER_CTRL = 1 << 0, 1090 | const MODIFIER_ALT = 1 << 1, 1091 | const MODIFIER_SHIFT = 1 << 2, 1092 | const MODIFIER_SUPER = 1 << 3, 1093 | } 1094 | } 1095 | 1096 | #[derive(Copy, Clone, Debug)] 1097 | pub struct AreaMouseEvent { 1098 | pub x: f64, 1099 | pub y: f64, 1100 | 1101 | pub area_width: f64, 1102 | pub area_height: f64, 1103 | 1104 | pub down: u64, 1105 | pub up: u64, 1106 | 1107 | pub count: u64, 1108 | 1109 | pub modifiers: Modifiers, 1110 | 1111 | pub held_1_to_64: u64, 1112 | } 1113 | 1114 | impl AreaMouseEvent { 1115 | #[inline] 1116 | pub fn from_ui_area_mouse_event(ui_area_mouse_event: &uiAreaMouseEvent) -> AreaMouseEvent { 1117 | ffi_utils::ensure_initialized(); 1118 | AreaMouseEvent { 1119 | x: ui_area_mouse_event.X, 1120 | y: ui_area_mouse_event.Y, 1121 | area_width: ui_area_mouse_event.AreaWidth, 1122 | area_height: ui_area_mouse_event.AreaHeight, 1123 | down: ui_area_mouse_event.Down, 1124 | up: ui_area_mouse_event.Up, 1125 | count: ui_area_mouse_event.Count, 1126 | modifiers: Modifiers::from_bits(ui_area_mouse_event.Modifiers as u8).unwrap(), 1127 | held_1_to_64: ui_area_mouse_event.Held1To64, 1128 | } 1129 | } 1130 | } 1131 | 1132 | #[derive(Copy, Clone, Debug)] 1133 | pub struct AreaKeyEvent { 1134 | pub key: u8, 1135 | pub ext_key: ExtKey, 1136 | pub modifier: Modifiers, 1137 | pub modifiers: Modifiers, 1138 | pub up: bool, 1139 | } 1140 | 1141 | impl AreaKeyEvent { 1142 | #[inline] 1143 | pub fn from_ui_area_key_event(ui_area_key_event: &uiAreaKeyEvent) -> AreaKeyEvent { 1144 | ffi_utils::ensure_initialized(); 1145 | AreaKeyEvent { 1146 | key: ui_area_key_event.Key as u8, 1147 | ext_key: ui_area_key_event.ExtKey, 1148 | modifier: Modifiers::from_bits(ui_area_key_event.Modifier as u8).unwrap(), 1149 | modifiers: Modifiers::from_bits(ui_area_key_event.Modifiers as u8).unwrap(), 1150 | up: ui_area_key_event.Up != 0, 1151 | } 1152 | } 1153 | } 1154 | 1155 | define_control!(FontButton, uiFontButton, ui_font_button); 1156 | 1157 | impl FontButton { 1158 | /// Returns a new font. 1159 | #[inline] 1160 | pub fn font(&self) -> draw::text::Font { 1161 | ffi_utils::ensure_initialized(); 1162 | unsafe { 1163 | draw::text::Font::from_ui_draw_text_font(ui_sys::uiFontButtonFont(self.ui_font_button)) 1164 | } 1165 | } 1166 | 1167 | #[inline] 1168 | pub fn on_changed(&self, callback: Box) { 1169 | ffi_utils::ensure_initialized(); 1170 | unsafe { 1171 | let mut data: Box> = Box::new(callback); 1172 | ui_sys::uiFontButtonOnChanged(self.ui_font_button, 1173 | c_callback, 1174 | &mut *data as *mut Box as 1175 | *mut c_void); 1176 | mem::forget(data); 1177 | } 1178 | 1179 | extern "C" fn c_callback(ui_font_button: *mut uiFontButton, data: *mut c_void) { 1180 | unsafe { 1181 | let font_button = FontButton::from_ui_control(ui_font_button); 1182 | mem::transmute::<*mut c_void, &mut Box>(data)(&font_button); 1183 | mem::forget(font_button); 1184 | } 1185 | } 1186 | } 1187 | 1188 | #[inline] 1189 | pub fn new() -> FontButton { 1190 | ffi_utils::ensure_initialized(); 1191 | unsafe { 1192 | FontButton::from_ui_control(ui_sys::uiNewFontButton()) 1193 | } 1194 | } 1195 | } 1196 | 1197 | define_control!(ColorButton, uiColorButton, ui_color_button); 1198 | 1199 | impl ColorButton { 1200 | #[inline] 1201 | pub fn color(&self) -> Color { 1202 | ffi_utils::ensure_initialized(); 1203 | unsafe { 1204 | let mut color: Color = mem::uninitialized(); 1205 | ui_sys::uiColorButtonColor(self.ui_color_button, 1206 | &mut color.r, 1207 | &mut color.g, 1208 | &mut color.b, 1209 | &mut color.a); 1210 | color 1211 | } 1212 | } 1213 | 1214 | #[inline] 1215 | pub fn set_color(&self, color: &Color) { 1216 | ffi_utils::ensure_initialized(); 1217 | unsafe { 1218 | ui_sys::uiColorButtonSetColor(self.ui_color_button, color.r, color.g, color.b, color.a) 1219 | } 1220 | } 1221 | 1222 | #[inline] 1223 | pub fn on_changed(&self, callback: Box) { 1224 | ffi_utils::ensure_initialized(); 1225 | unsafe { 1226 | let mut data: Box> = Box::new(callback); 1227 | ui_sys::uiColorButtonOnChanged(self.ui_color_button, 1228 | c_callback, 1229 | &mut *data as *mut Box as 1230 | *mut c_void); 1231 | mem::forget(data); 1232 | } 1233 | 1234 | extern "C" fn c_callback(ui_color_button: *mut uiColorButton, data: *mut c_void) { 1235 | unsafe { 1236 | let color_button = ColorButton::from_ui_control(ui_color_button); 1237 | mem::transmute::<*mut c_void, &mut Box>(data)(&color_button); 1238 | mem::forget(color_button) 1239 | } 1240 | } 1241 | } 1242 | 1243 | #[inline] 1244 | pub fn new() -> ColorButton { 1245 | ffi_utils::ensure_initialized(); 1246 | unsafe { 1247 | ColorButton::from_ui_control(ui_sys::uiNewColorButton()) 1248 | } 1249 | } 1250 | } 1251 | 1252 | #[derive(Copy, Clone, PartialEq, Debug)] 1253 | pub struct Color { 1254 | r: f64, 1255 | g: f64, 1256 | b: f64, 1257 | a: f64, 1258 | } 1259 | 1260 | -------------------------------------------------------------------------------- /ui/src/draw.rs: -------------------------------------------------------------------------------- 1 | //! Functions and types related to 2D vector graphics. 2 | 3 | use ffi_utils::{self, Text}; 4 | use libc::{c_double, c_int}; 5 | use std::marker::PhantomData; 6 | use std::mem; 7 | use std::ops::Mul; 8 | use std::ptr; 9 | use ui_sys::{self, uiDrawBrush, uiDrawBrushType, uiDrawContext, uiDrawFontFamilies, uiDrawMatrix}; 10 | use ui_sys::{uiDrawPath, uiDrawStrokeParams}; 11 | 12 | pub use ui_sys::uiDrawBrushGradientStop as BrushGradientStop; 13 | pub use ui_sys::uiDrawLineCap as LineCap; 14 | pub use ui_sys::uiDrawLineJoin as LineJoin; 15 | pub use ui_sys::uiDrawDefaultMiterLimit as DEFAULT_MITER_LIMIT; 16 | pub use ui_sys::uiDrawFillMode as FillMode; 17 | 18 | pub struct Context { 19 | ui_draw_context: *mut uiDrawContext, 20 | } 21 | 22 | impl Context { 23 | #[inline] 24 | pub unsafe fn from_ui_draw_context(ui_draw_context: *mut uiDrawContext) -> Context { 25 | ffi_utils::ensure_initialized(); 26 | Context { 27 | ui_draw_context: ui_draw_context, 28 | } 29 | } 30 | 31 | #[inline] 32 | pub fn stroke(&self, path: &Path, brush: &Brush, stroke_params: &StrokeParams) { 33 | ffi_utils::ensure_initialized(); 34 | unsafe { 35 | let brush = brush.as_ui_draw_brush_ref(); 36 | let stroke_params = stroke_params.as_ui_draw_stroke_params_ref(); 37 | ui_sys::uiDrawStroke(self.ui_draw_context, 38 | path.ui_draw_path, 39 | &brush.ui_draw_brush as *const uiDrawBrush as *mut uiDrawBrush, 40 | &stroke_params.ui_draw_stroke_params as *const uiDrawStrokeParams 41 | as *mut uiDrawStrokeParams) 42 | } 43 | } 44 | 45 | #[inline] 46 | pub fn fill(&self, path: &Path, brush: &Brush) { 47 | ffi_utils::ensure_initialized(); 48 | unsafe { 49 | let brush = brush.as_ui_draw_brush_ref(); 50 | ui_sys::uiDrawFill(self.ui_draw_context, 51 | path.ui_draw_path, 52 | &brush.ui_draw_brush as *const uiDrawBrush as *mut uiDrawBrush) 53 | } 54 | } 55 | 56 | #[inline] 57 | pub fn transform(&self, matrix: &Matrix) { 58 | ffi_utils::ensure_initialized(); 59 | unsafe { 60 | ui_sys::uiDrawTransform(self.ui_draw_context, 61 | &matrix.ui_matrix as *const uiDrawMatrix as *mut uiDrawMatrix) 62 | } 63 | } 64 | 65 | #[inline] 66 | pub fn save(&self) { 67 | ffi_utils::ensure_initialized(); 68 | unsafe { 69 | ui_sys::uiDrawSave(self.ui_draw_context) 70 | } 71 | } 72 | 73 | #[inline] 74 | pub fn restore(&self) { 75 | ffi_utils::ensure_initialized(); 76 | unsafe { 77 | ui_sys::uiDrawRestore(self.ui_draw_context) 78 | } 79 | } 80 | 81 | #[inline] 82 | pub fn draw_text(&self, x: f64, y: f64, layout: &text::Layout) { 83 | ffi_utils::ensure_initialized(); 84 | unsafe { 85 | ui_sys::uiDrawText(self.ui_draw_context, x, y, layout.as_ui_draw_text_layout()) 86 | } 87 | } 88 | } 89 | 90 | #[derive(Clone, Debug)] 91 | pub enum Brush { 92 | Solid(SolidBrush), 93 | LinearGradient(LinearGradientBrush), 94 | RadialGradient(RadialGradientBrush), 95 | Image, 96 | } 97 | 98 | #[derive(Clone, Debug)] 99 | pub struct UiDrawBrushRef<'a> { 100 | ui_draw_brush: uiDrawBrush, 101 | phantom: PhantomData<&'a uiDrawBrush>, 102 | } 103 | 104 | impl Brush { 105 | pub fn as_ui_draw_brush_ref(&self) -> UiDrawBrushRef { 106 | ffi_utils::ensure_initialized(); 107 | match *self { 108 | Brush::Solid(ref solid_brush) => { 109 | UiDrawBrushRef { 110 | ui_draw_brush: uiDrawBrush { 111 | Type: uiDrawBrushType::Solid, 112 | 113 | R: solid_brush.r, 114 | G: solid_brush.g, 115 | B: solid_brush.b, 116 | A: solid_brush.a, 117 | 118 | X0: 0.0, 119 | Y0: 0.0, 120 | X1: 0.0, 121 | Y1: 0.0, 122 | OuterRadius: 0.0, 123 | Stops: ptr::null_mut(), 124 | NumStops: 0, 125 | }, 126 | phantom: PhantomData, 127 | } 128 | } 129 | Brush::LinearGradient(ref linear_gradient_brush) => { 130 | UiDrawBrushRef { 131 | ui_draw_brush: uiDrawBrush { 132 | Type: uiDrawBrushType::LinearGradient, 133 | 134 | R: 0.0, 135 | G: 0.0, 136 | B: 0.0, 137 | A: 0.0, 138 | 139 | X0: linear_gradient_brush.start_x, 140 | Y0: linear_gradient_brush.start_y, 141 | X1: linear_gradient_brush.end_x, 142 | Y1: linear_gradient_brush.end_y, 143 | OuterRadius: 0.0, 144 | Stops: linear_gradient_brush.stops.as_ptr() as *mut BrushGradientStop, 145 | NumStops: linear_gradient_brush.stops.len(), 146 | }, 147 | phantom: PhantomData, 148 | } 149 | } 150 | Brush::RadialGradient(ref radial_gradient_brush) => { 151 | UiDrawBrushRef { 152 | ui_draw_brush: uiDrawBrush { 153 | Type: uiDrawBrushType::RadialGradient, 154 | 155 | R: 0.0, 156 | G: 0.0, 157 | B: 0.0, 158 | A: 0.0, 159 | 160 | X0: radial_gradient_brush.start_x, 161 | Y0: radial_gradient_brush.start_y, 162 | X1: radial_gradient_brush.outer_circle_center_x, 163 | Y1: radial_gradient_brush.outer_circle_center_y, 164 | OuterRadius: radial_gradient_brush.outer_radius, 165 | Stops: radial_gradient_brush.stops.as_ptr() as *mut BrushGradientStop, 166 | NumStops: radial_gradient_brush.stops.len(), 167 | }, 168 | phantom: PhantomData, 169 | } 170 | } 171 | Brush::Image => { 172 | // These don't work yet in `libui`, but just for completeness' sake… 173 | UiDrawBrushRef { 174 | ui_draw_brush: uiDrawBrush { 175 | Type: uiDrawBrushType::Image, 176 | 177 | R: 0.0, 178 | G: 0.0, 179 | B: 0.0, 180 | A: 0.0, 181 | 182 | X0: 0.0, 183 | Y0: 0.0, 184 | X1: 0.0, 185 | Y1: 0.0, 186 | OuterRadius: 0.0, 187 | Stops: ptr::null_mut(), 188 | NumStops: 0, 189 | }, 190 | phantom: PhantomData, 191 | } 192 | } 193 | } 194 | } 195 | } 196 | 197 | #[derive(Copy, Clone, PartialEq, Debug)] 198 | pub struct SolidBrush { 199 | pub r: f64, 200 | pub g: f64, 201 | pub b: f64, 202 | pub a: f64, 203 | } 204 | 205 | #[derive(Clone, Debug)] 206 | pub struct LinearGradientBrush { 207 | pub start_x: f64, 208 | pub start_y: f64, 209 | pub end_x: f64, 210 | pub end_y: f64, 211 | pub stops: Vec, 212 | } 213 | 214 | #[derive(Clone, Debug)] 215 | pub struct RadialGradientBrush { 216 | pub start_x: f64, 217 | pub start_y: f64, 218 | pub outer_circle_center_x: f64, 219 | pub outer_circle_center_y: f64, 220 | pub outer_radius: f64, 221 | pub stops: Vec, 222 | } 223 | 224 | #[derive(Clone, Debug)] 225 | pub struct StrokeParams { 226 | pub cap: LineCap, 227 | pub join: LineJoin, 228 | pub thickness: f64, 229 | pub miter_limit: f64, 230 | pub dashes: Vec, 231 | pub dash_phase: f64, 232 | } 233 | 234 | #[derive(Clone, Debug)] 235 | pub struct UiDrawStrokeParamsRef<'a> { 236 | ui_draw_stroke_params: uiDrawStrokeParams, 237 | phantom: PhantomData<&'a uiDrawStrokeParams>, 238 | } 239 | 240 | impl StrokeParams { 241 | pub fn as_ui_draw_stroke_params_ref(&self) -> UiDrawStrokeParamsRef { 242 | ffi_utils::ensure_initialized(); 243 | UiDrawStrokeParamsRef { 244 | ui_draw_stroke_params: uiDrawStrokeParams { 245 | Cap: self.cap, 246 | Join: self.join, 247 | Thickness: self.thickness, 248 | MiterLimit: self.miter_limit, 249 | Dashes: self.dashes.as_ptr() as *mut c_double, 250 | NumDashes: self.dashes.len(), 251 | DashPhase: self.dash_phase, 252 | }, 253 | phantom: PhantomData, 254 | } 255 | } 256 | } 257 | 258 | pub struct Path { 259 | ui_draw_path: *mut uiDrawPath, 260 | } 261 | 262 | impl Drop for Path { 263 | #[inline] 264 | fn drop(&mut self) { 265 | ffi_utils::ensure_initialized(); 266 | unsafe { 267 | ui_sys::uiDrawFreePath(self.ui_draw_path) 268 | } 269 | } 270 | } 271 | 272 | impl Path { 273 | #[inline] 274 | pub fn new(fill_mode: FillMode) -> Path { 275 | ffi_utils::ensure_initialized(); 276 | unsafe { 277 | Path { 278 | ui_draw_path: ui_sys::uiDrawNewPath(fill_mode), 279 | } 280 | } 281 | } 282 | 283 | #[inline] 284 | pub fn new_figure(&self, x: f64, y: f64) { 285 | ffi_utils::ensure_initialized(); 286 | unsafe { 287 | ui_sys::uiDrawPathNewFigure(self.ui_draw_path, x, y) 288 | } 289 | } 290 | 291 | #[inline] 292 | pub fn new_figure_with_arc(&self, 293 | x_center: f64, 294 | y_center: f64, 295 | radius: f64, 296 | start_angle: f64, 297 | sweep: f64, 298 | negative: bool) { 299 | ffi_utils::ensure_initialized(); 300 | unsafe { 301 | ui_sys::uiDrawPathNewFigureWithArc(self.ui_draw_path, 302 | x_center, 303 | y_center, 304 | radius, 305 | start_angle, 306 | sweep, 307 | negative as c_int) 308 | } 309 | } 310 | 311 | #[inline] 312 | pub fn line_to(&self, x: f64, y: f64) { 313 | ffi_utils::ensure_initialized(); 314 | unsafe { 315 | ui_sys::uiDrawPathLineTo(self.ui_draw_path, x, y) 316 | } 317 | } 318 | 319 | #[inline] 320 | pub fn arc_to(&self, 321 | x_center: f64, 322 | y_center: f64, 323 | radius: f64, 324 | start_angle: f64, 325 | sweep: f64, 326 | negative: bool) { 327 | ffi_utils::ensure_initialized(); 328 | unsafe { 329 | ui_sys::uiDrawPathArcTo(self.ui_draw_path, 330 | x_center, 331 | y_center, 332 | radius, 333 | start_angle, 334 | sweep, 335 | negative as c_int) 336 | } 337 | } 338 | 339 | #[inline] 340 | pub fn bezier_to(&self, c1x: f64, c1y: f64, c2x: f64, c2y: f64, end_x: f64, end_y: f64) { 341 | ffi_utils::ensure_initialized(); 342 | unsafe { 343 | ui_sys::uiDrawPathBezierTo(self.ui_draw_path, c1x, c1y, c2x, c2y, end_x, end_y) 344 | } 345 | } 346 | 347 | #[inline] 348 | pub fn close_figure(&self) { 349 | ffi_utils::ensure_initialized(); 350 | unsafe { 351 | ui_sys::uiDrawPathCloseFigure(self.ui_draw_path) 352 | } 353 | } 354 | 355 | #[inline] 356 | pub fn add_rectangle(&self, x: f64, y: f64, width: f64, height: f64) { 357 | ffi_utils::ensure_initialized(); 358 | unsafe { 359 | ui_sys::uiDrawPathAddRectangle(self.ui_draw_path, x, y, width, height) 360 | } 361 | } 362 | 363 | #[inline] 364 | pub fn end(&self) { 365 | ffi_utils::ensure_initialized(); 366 | unsafe { 367 | ui_sys::uiDrawPathEnd(self.ui_draw_path) 368 | } 369 | } 370 | } 371 | 372 | #[derive(Copy, Clone, PartialEq, Debug)] 373 | pub struct Matrix { 374 | pub ui_matrix: uiDrawMatrix, 375 | } 376 | 377 | impl Matrix { 378 | #[inline] 379 | pub fn from_ui_matrix(ui_matrix: &uiDrawMatrix) -> Matrix { 380 | Matrix { 381 | ui_matrix: *ui_matrix, 382 | } 383 | } 384 | 385 | #[inline] 386 | pub fn identity() -> Matrix { 387 | unsafe { 388 | let mut matrix = mem::uninitialized(); 389 | ui_sys::uiDrawMatrixSetIdentity(&mut matrix); 390 | Matrix::from_ui_matrix(&matrix) 391 | } 392 | } 393 | 394 | #[inline] 395 | pub fn translate(&mut self, x: f64, y: f64) { 396 | unsafe { 397 | ui_sys::uiDrawMatrixTranslate(&mut self.ui_matrix, x, y) 398 | } 399 | } 400 | 401 | #[inline] 402 | pub fn scale(&mut self, x_center: f64, y_center: f64, x: f64, y: f64) { 403 | unsafe { 404 | ui_sys::uiDrawMatrixScale(&mut self.ui_matrix, x_center, y_center, x, y) 405 | } 406 | } 407 | 408 | #[inline] 409 | pub fn rotate(&mut self, x: f64, y: f64, angle: f64) { 410 | unsafe { 411 | ui_sys::uiDrawMatrixRotate(&mut self.ui_matrix, x, y, angle) 412 | } 413 | } 414 | 415 | #[inline] 416 | pub fn skew(&mut self, x: f64, y: f64, xamount: f64, yamount: f64) { 417 | unsafe { 418 | ui_sys::uiDrawMatrixSkew(&mut self.ui_matrix, x, y, xamount, yamount) 419 | } 420 | } 421 | 422 | #[inline] 423 | pub fn multiply(&mut self, src: &Matrix) { 424 | unsafe { 425 | ui_sys::uiDrawMatrixMultiply(&mut self.ui_matrix, 426 | &src.ui_matrix as *const uiDrawMatrix 427 | as *mut uiDrawMatrix) 428 | } 429 | } 430 | 431 | #[inline] 432 | pub fn invertible(&self) -> bool { 433 | unsafe { 434 | ui_sys::uiDrawMatrixInvertible(&self.ui_matrix as *const uiDrawMatrix 435 | as *mut uiDrawMatrix) != 0 436 | } 437 | } 438 | 439 | #[inline] 440 | pub fn invert(&mut self) -> bool { 441 | unsafe { 442 | ui_sys::uiDrawMatrixInvert(&mut self.ui_matrix) != 0 443 | } 444 | } 445 | 446 | #[inline] 447 | pub fn transform_point(&self, mut point: (f64, f64)) -> (f64, f64) { 448 | unsafe { 449 | ui_sys::uiDrawMatrixTransformPoint(&self.ui_matrix as *const uiDrawMatrix as 450 | *mut uiDrawMatrix, 451 | &mut point.0, 452 | &mut point.1); 453 | point 454 | } 455 | } 456 | 457 | #[inline] 458 | pub fn transform_size(&self, mut size: (f64, f64)) -> (f64, f64) { 459 | unsafe { 460 | ui_sys::uiDrawMatrixTransformSize(&self.ui_matrix as *const uiDrawMatrix as 461 | *mut uiDrawMatrix, 462 | &mut size.0, 463 | &mut size.1); 464 | size 465 | } 466 | } 467 | } 468 | 469 | impl Mul for Matrix { 470 | type Output = Matrix; 471 | 472 | fn mul(mut self, other: Matrix) -> Matrix { 473 | self.multiply(&other); 474 | self 475 | } 476 | } 477 | 478 | pub struct FontFamilies { 479 | ui_draw_font_families: *mut uiDrawFontFamilies, 480 | } 481 | 482 | impl Drop for FontFamilies { 483 | #[inline] 484 | fn drop(&mut self) { 485 | ffi_utils::ensure_initialized(); 486 | unsafe { 487 | ui_sys::uiDrawFreeFontFamilies(self.ui_draw_font_families) 488 | } 489 | } 490 | } 491 | 492 | impl FontFamilies { 493 | #[inline] 494 | pub fn list() -> FontFamilies { 495 | ffi_utils::ensure_initialized(); 496 | unsafe { 497 | FontFamilies { 498 | ui_draw_font_families: ui_sys::uiDrawListFontFamilies(), 499 | } 500 | } 501 | } 502 | 503 | #[inline] 504 | pub fn len(&self) -> u64 { 505 | ffi_utils::ensure_initialized(); 506 | unsafe { 507 | ui_sys::uiDrawFontFamiliesNumFamilies(self.ui_draw_font_families) 508 | } 509 | } 510 | 511 | #[inline] 512 | pub fn family(&self, index: u64) -> Text { 513 | ffi_utils::ensure_initialized(); 514 | assert!(index < self.len()); 515 | unsafe { 516 | Text::new(ui_sys::uiDrawFontFamiliesFamily(self.ui_draw_font_families, index)) 517 | } 518 | } 519 | } 520 | 521 | pub mod text { 522 | use ffi_utils; 523 | use libc::c_char; 524 | use std::ffi::{CStr, CString}; 525 | use std::mem; 526 | use ui_sys::{self, uiDrawTextFont, uiDrawTextFontDescriptor, uiDrawTextLayout}; 527 | 528 | pub use ui_sys::uiDrawTextWeight as Weight; 529 | pub use ui_sys::uiDrawTextItalic as Italic; 530 | pub use ui_sys::uiDrawTextStretch as Stretch; 531 | pub use ui_sys::uiDrawTextFontMetrics as FontMetrics; 532 | 533 | pub struct FontDescriptor { 534 | family: CString, 535 | pub size: f64, 536 | pub weight: Weight, 537 | pub italic: Italic, 538 | pub stretch: Stretch, 539 | } 540 | 541 | impl FontDescriptor { 542 | #[inline] 543 | pub fn new(family: &str, size: f64, weight: Weight, italic: Italic, stretch: Stretch) 544 | -> FontDescriptor { 545 | ffi_utils::ensure_initialized(); 546 | FontDescriptor { 547 | family: CString::new(family.as_bytes().to_vec()).unwrap(), 548 | size: size, 549 | weight: weight, 550 | italic: italic, 551 | stretch: stretch, 552 | } 553 | } 554 | 555 | /// FIXME(pcwalton): Should this return an Option? 556 | #[inline] 557 | pub fn load_closest_font(&self) -> Font { 558 | ffi_utils::ensure_initialized(); 559 | unsafe { 560 | let font_descriptor = uiDrawTextFontDescriptor { 561 | Family: self.family.as_ptr(), 562 | Size: self.size, 563 | Weight: self.weight, 564 | Italic: self.italic, 565 | Stretch: self.stretch, 566 | }; 567 | Font { 568 | ui_draw_text_font: ui_sys::uiDrawLoadClosestFont(&font_descriptor), 569 | } 570 | } 571 | } 572 | 573 | #[inline] 574 | pub fn family(&self) -> &str { 575 | self.family.to_str().unwrap() 576 | } 577 | } 578 | 579 | pub struct Font { 580 | ui_draw_text_font: *mut uiDrawTextFont, 581 | } 582 | 583 | impl Drop for Font { 584 | #[inline] 585 | fn drop(&mut self) { 586 | ffi_utils::ensure_initialized(); 587 | unsafe { 588 | ui_sys::uiDrawFreeTextFont(self.ui_draw_text_font) 589 | } 590 | } 591 | } 592 | 593 | impl Font { 594 | #[inline] 595 | pub unsafe fn from_ui_draw_text_font(ui_draw_text_font: *mut uiDrawTextFont) -> Font { 596 | Font { 597 | ui_draw_text_font: ui_draw_text_font, 598 | } 599 | } 600 | 601 | #[inline] 602 | pub fn handle(&self) -> usize { 603 | ffi_utils::ensure_initialized(); 604 | unsafe { 605 | ui_sys::uiDrawTextFontHandle(self.ui_draw_text_font) 606 | } 607 | } 608 | 609 | #[inline] 610 | pub fn describe(&self) -> FontDescriptor { 611 | ffi_utils::ensure_initialized(); 612 | unsafe { 613 | let mut ui_draw_text_font_descriptor = mem::uninitialized(); 614 | ui_sys::uiDrawTextFontDescribe(self.ui_draw_text_font, 615 | &mut ui_draw_text_font_descriptor); 616 | let family = CStr::from_ptr(ui_draw_text_font_descriptor.Family).to_bytes() 617 | .to_vec(); 618 | let font_descriptor = FontDescriptor { 619 | family: CString::new(family).unwrap(), 620 | size: ui_draw_text_font_descriptor.Size, 621 | weight: ui_draw_text_font_descriptor.Weight, 622 | italic: ui_draw_text_font_descriptor.Italic, 623 | stretch: ui_draw_text_font_descriptor.Stretch, 624 | }; 625 | ui_sys::uiFreeText(ui_draw_text_font_descriptor.Family as *mut c_char); 626 | font_descriptor 627 | } 628 | } 629 | 630 | #[inline] 631 | pub fn metrics(&self) -> FontMetrics { 632 | ffi_utils::ensure_initialized(); 633 | unsafe { 634 | let mut metrics = mem::uninitialized(); 635 | ui_sys::uiDrawTextFontGetMetrics(self.ui_draw_text_font, &mut metrics); 636 | metrics 637 | } 638 | } 639 | } 640 | 641 | pub struct Layout { 642 | ui_draw_text_layout: *mut uiDrawTextLayout, 643 | } 644 | 645 | impl Drop for Layout { 646 | #[inline] 647 | fn drop(&mut self) { 648 | ffi_utils::ensure_initialized(); 649 | unsafe { 650 | ui_sys::uiDrawFreeTextLayout(self.ui_draw_text_layout) 651 | } 652 | } 653 | } 654 | 655 | impl Layout { 656 | #[inline] 657 | pub fn new(text: &str, default_font: &Font, width: f64) -> Layout { 658 | ffi_utils::ensure_initialized(); 659 | unsafe { 660 | let c_string = CString::new(text.as_bytes().to_vec()).unwrap(); 661 | Layout { 662 | ui_draw_text_layout: 663 | ui_sys::uiDrawNewTextLayout(c_string.as_ptr(), 664 | default_font.ui_draw_text_font, 665 | width), 666 | } 667 | } 668 | } 669 | 670 | #[inline] 671 | pub fn as_ui_draw_text_layout(&self) -> *mut uiDrawTextLayout { 672 | self.ui_draw_text_layout 673 | } 674 | 675 | #[inline] 676 | pub fn set_width(&self, width: f64) { 677 | ffi_utils::ensure_initialized(); 678 | unsafe { 679 | ui_sys::uiDrawTextLayoutSetWidth(self.ui_draw_text_layout, width) 680 | } 681 | } 682 | 683 | #[inline] 684 | pub fn extents(&self) -> (f64, f64) { 685 | ffi_utils::ensure_initialized(); 686 | unsafe { 687 | let mut extents = (0.0, 0.0); 688 | ui_sys::uiDrawTextLayoutExtents(self.ui_draw_text_layout, 689 | &mut extents.0, 690 | &mut extents.1); 691 | extents 692 | } 693 | } 694 | 695 | #[inline] 696 | pub fn set_color(&self, start_char: i64, end_char: i64, r: f64, g: f64, b: f64, a: f64) { 697 | ffi_utils::ensure_initialized(); 698 | unsafe { 699 | ui_sys::uiDrawTextLayoutSetColor(self.ui_draw_text_layout, 700 | start_char, 701 | end_char, 702 | r, 703 | g, 704 | b, 705 | a) 706 | } 707 | } 708 | } 709 | } 710 | 711 | -------------------------------------------------------------------------------- /ui/src/ffi_utils.rs: -------------------------------------------------------------------------------- 1 | //! Useful utility functions for calling the `libui` C bindings. 2 | 3 | use libc::{c_char, c_void}; 4 | use std::ffi::CStr; 5 | use std::mem; 6 | use std::ops::Deref; 7 | use std::sync::atomic::{ATOMIC_BOOL_INIT, AtomicBool, Ordering}; 8 | use ui_sys; 9 | 10 | static INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; 11 | 12 | #[inline] 13 | pub unsafe fn set_initialized() { 14 | assert!(!INITIALIZED.swap(true, Ordering::SeqCst)); 15 | } 16 | 17 | #[inline] 18 | pub unsafe fn unset_initialized() { 19 | INITIALIZED.store(false, Ordering::SeqCst); 20 | } 21 | 22 | #[inline] 23 | pub fn ensure_initialized() { 24 | assert!(INITIALIZED.load(Ordering::SeqCst)); 25 | } 26 | 27 | pub struct Text { 28 | ui_text: *mut c_char, 29 | } 30 | 31 | impl Drop for Text { 32 | fn drop(&mut self) { 33 | unsafe { 34 | ui_sys::uiFreeText(self.ui_text) 35 | } 36 | } 37 | } 38 | 39 | impl Deref for Text { 40 | type Target = str; 41 | fn deref(&self) -> &str { 42 | unsafe { 43 | CStr::from_ptr(self.ui_text).to_str().unwrap_or("") 44 | } 45 | } 46 | } 47 | 48 | impl Text { 49 | #[inline] 50 | pub unsafe fn new(text: *mut c_char) -> Text { 51 | debug_assert!(!text.is_null()); 52 | Text { 53 | ui_text: text, 54 | } 55 | } 56 | 57 | #[inline] 58 | pub unsafe fn optional(text: *mut c_char) -> Option { 59 | if text.is_null() { 60 | None 61 | } else { 62 | Some(Text { 63 | ui_text: text, 64 | }) 65 | } 66 | } 67 | } 68 | 69 | pub extern "C" fn void_void_callback(data: *mut c_void) { 70 | unsafe { 71 | mem::transmute::<*mut c_void, Box>>(data)() 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /ui/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Rust bindings to `libui`. 2 | //! 3 | //! Main C source repository: https://github.com/andlabs/libui 4 | //! 5 | //! Copyright © 2016 Mozilla Foundation 6 | 7 | #[macro_use] 8 | extern crate bitflags; 9 | extern crate libc; 10 | extern crate ui_sys; 11 | 12 | pub use controls::{Area, AreaDrawParams, AreaHandler, BoxControl, Button, Checkbox, ColorButton}; 13 | pub use controls::{Combobox, Control, DateTimePicker, Entry, FontButton, Group, Label}; 14 | pub use controls::{MultilineEntry, ProgressBar, RadioButtons, Separator, Slider, Spinbox, Tab}; 15 | pub use ffi_utils::Text; 16 | pub use menus::{Menu, MenuItem}; 17 | pub use ui::{InitError, InitOptions, init, main, msg_box, msg_box_error, on_should_quit}; 18 | pub use ui::{open_file, queue_main, quit, save_file, uninit}; 19 | pub use windows::Window; 20 | 21 | #[macro_use] 22 | mod controls; 23 | pub mod draw; 24 | pub mod ffi_utils; 25 | mod menus; 26 | mod ui; 27 | mod windows; 28 | 29 | -------------------------------------------------------------------------------- /ui/src/menus.rs: -------------------------------------------------------------------------------- 1 | //! Functions and types related to menus. 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 windows::Window; 8 | 9 | // NB: If there ever becomes a way to destroy menus and/or menu items, we'll need to reference 10 | // count these for memory safety. 11 | #[derive(Clone)] 12 | pub struct MenuItem { 13 | ui_menu_item: *mut uiMenuItem, 14 | } 15 | 16 | impl MenuItem { 17 | #[inline] 18 | pub fn enable(&self) { 19 | unsafe { 20 | ui_sys::uiMenuItemEnable(self.ui_menu_item) 21 | } 22 | } 23 | 24 | #[inline] 25 | pub fn disable(&self) { 26 | unsafe { 27 | ui_sys::uiMenuItemDisable(self.ui_menu_item) 28 | } 29 | } 30 | 31 | #[inline] 32 | pub fn on_clicked(&self, callback: Box) { 33 | unsafe { 34 | let mut data: Box> = Box::new(callback); 35 | ui_sys::uiMenuItemOnClicked(self.ui_menu_item, 36 | c_callback, 37 | &mut *data as *mut Box as *mut c_void); 39 | mem::forget(data); 40 | } 41 | 42 | extern "C" fn c_callback(menu_item: *mut uiMenuItem, 43 | window: *mut uiWindow, 44 | data: *mut c_void) { 45 | unsafe { 46 | let menu_item = MenuItem { 47 | ui_menu_item: menu_item, 48 | }; 49 | let window = Window::from_ui_window(window); 50 | mem::transmute::<*mut c_void, 51 | &mut Box>(data)(&menu_item, &window); 52 | mem::forget(window); 53 | } 54 | } 55 | } 56 | 57 | #[inline] 58 | pub fn checked(&self) -> bool { 59 | unsafe { 60 | ui_sys::uiMenuItemChecked(self.ui_menu_item) != 0 61 | } 62 | } 63 | 64 | #[inline] 65 | pub fn set_checked(&self, checked: bool) { 66 | unsafe { 67 | ui_sys::uiMenuItemSetChecked(self.ui_menu_item, checked as c_int) 68 | } 69 | } 70 | } 71 | 72 | // NB: If there ever becomes a way to destroy menus, we'll need to reference count these for memory 73 | // safety. 74 | #[derive(Clone)] 75 | pub struct Menu { 76 | ui_menu: *mut uiMenu, 77 | } 78 | 79 | impl Menu { 80 | #[inline] 81 | pub fn append_item(&self, name: &str) -> MenuItem { 82 | unsafe { 83 | let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); 84 | MenuItem { 85 | ui_menu_item: ui_sys::uiMenuAppendItem(self.ui_menu, c_string.as_ptr()), 86 | } 87 | } 88 | } 89 | 90 | #[inline] 91 | pub fn append_check_item(&self, name: &str) -> MenuItem { 92 | unsafe { 93 | let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); 94 | MenuItem { 95 | ui_menu_item: ui_sys::uiMenuAppendCheckItem(self.ui_menu, c_string.as_ptr()), 96 | } 97 | } 98 | } 99 | 100 | #[inline] 101 | pub fn append_quit_item(&self) -> MenuItem { 102 | unsafe { 103 | MenuItem { 104 | ui_menu_item: ui_sys::uiMenuAppendQuitItem(self.ui_menu), 105 | } 106 | } 107 | } 108 | 109 | #[inline] 110 | pub fn append_preferences_item(&self) -> MenuItem { 111 | unsafe { 112 | MenuItem { 113 | ui_menu_item: ui_sys::uiMenuAppendPreferencesItem(self.ui_menu), 114 | } 115 | } 116 | } 117 | 118 | #[inline] 119 | pub fn append_about_item(&self) -> MenuItem { 120 | unsafe { 121 | MenuItem { 122 | ui_menu_item: ui_sys::uiMenuAppendAboutItem(self.ui_menu), 123 | } 124 | } 125 | } 126 | 127 | #[inline] 128 | pub fn append_separator(&self) { 129 | unsafe { 130 | ui_sys::uiMenuAppendSeparator(self.ui_menu) 131 | } 132 | } 133 | 134 | #[inline] 135 | pub fn new(name: &str) -> Menu { 136 | unsafe { 137 | let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); 138 | Menu { 139 | ui_menu: ui_sys::uiNewMenu(c_string.as_ptr()), 140 | } 141 | } 142 | } 143 | } 144 | 145 | -------------------------------------------------------------------------------- /ui/src/ui.rs: -------------------------------------------------------------------------------- 1 | //! General functions. 2 | 3 | use ffi_utils::{self, Text}; 4 | use libc::{c_char, c_void}; 5 | use std::fmt::{self, Debug, Formatter}; 6 | use std::ffi::{CStr, CString}; 7 | use std::mem; 8 | use std::ops::Deref; 9 | use ui_sys::{self, uiInitOptions}; 10 | use windows::Window; 11 | 12 | #[derive(Clone)] 13 | pub struct InitOptions; 14 | 15 | #[inline] 16 | pub fn init(_: InitOptions) -> Result<(),InitError> { 17 | unsafe { 18 | let mut init_options = uiInitOptions { 19 | Size: mem::size_of::(), 20 | }; 21 | let err = ui_sys::uiInit(&mut init_options); 22 | if err.is_null() { 23 | ffi_utils::set_initialized(); 24 | Ok(()) 25 | } else { 26 | Err(InitError { 27 | ui_init_error: err, 28 | }) 29 | } 30 | } 31 | } 32 | 33 | #[inline] 34 | pub fn uninit() { 35 | unsafe { 36 | ffi_utils::unset_initialized(); 37 | Window::destroy_all_windows(); 38 | ui_sys::uiUninit(); 39 | } 40 | } 41 | 42 | #[inline] 43 | pub fn main() { 44 | unsafe { 45 | ui_sys::uiMain() 46 | } 47 | } 48 | 49 | #[inline] 50 | pub fn quit() { 51 | unsafe { 52 | ui_sys::uiQuit() 53 | } 54 | } 55 | 56 | pub struct InitError { 57 | ui_init_error: *const c_char, 58 | } 59 | 60 | impl Drop for InitError { 61 | fn drop(&mut self) { 62 | unsafe { 63 | ui_sys::uiFreeInitError(self.ui_init_error) 64 | } 65 | } 66 | } 67 | 68 | impl Debug for InitError { 69 | fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { 70 | (**self).fmt(f) 71 | } 72 | } 73 | 74 | impl Deref for InitError { 75 | type Target = str; 76 | fn deref(&self) -> &str { 77 | unsafe { 78 | CStr::from_ptr(self.ui_init_error).to_str().unwrap_or("") 79 | } 80 | } 81 | } 82 | 83 | #[inline] 84 | pub fn queue_main(callback: Box) { 85 | unsafe { 86 | let mut data: Box> = Box::new(callback); 87 | ui_sys::uiQueueMain(ffi_utils::void_void_callback, 88 | &mut *data as *mut Box as *mut c_void); 89 | mem::forget(data); 90 | } 91 | } 92 | 93 | #[inline] 94 | pub fn on_should_quit(callback: Box) { 95 | unsafe { 96 | let mut data: Box> = Box::new(callback); 97 | ui_sys::uiOnShouldQuit(ffi_utils::void_void_callback, 98 | &mut *data as *mut Box as *mut c_void); 99 | mem::forget(data); 100 | } 101 | } 102 | 103 | #[inline] 104 | pub fn open_file(parent: &Window) -> Option { 105 | unsafe { 106 | Text::optional(ui_sys::uiOpenFile(parent.as_ui_window())) 107 | } 108 | } 109 | 110 | #[inline] 111 | pub fn save_file(parent: &Window) -> Option { 112 | unsafe { 113 | Text::optional(ui_sys::uiSaveFile(parent.as_ui_window())) 114 | } 115 | } 116 | 117 | #[inline] 118 | pub fn msg_box(parent: &Window, title: &str, description: &str) { 119 | unsafe { 120 | let c_title = CString::new(title.as_bytes().to_vec()).unwrap(); 121 | let c_description = CString::new(description.as_bytes().to_vec()).unwrap(); 122 | ui_sys::uiMsgBox(parent.as_ui_window(), c_title.as_ptr(), c_description.as_ptr()) 123 | } 124 | } 125 | 126 | #[inline] 127 | pub fn msg_box_error(parent: &Window, title: &str, description: &str) { 128 | unsafe { 129 | let c_title = CString::new(title.as_bytes().to_vec()).unwrap(); 130 | let c_description = CString::new(description.as_bytes().to_vec()).unwrap(); 131 | ui_sys::uiMsgBoxError(parent.as_ui_window(), c_title.as_ptr(), c_description.as_ptr()) 132 | } 133 | } 134 | 135 | -------------------------------------------------------------------------------- /ui/src/windows.rs: -------------------------------------------------------------------------------- 1 | //! Functions and types related to windows. 2 | 3 | use controls::Control; 4 | use ffi_utils::{self, Text}; 5 | use libc::{c_int, c_void}; 6 | use std::cell::RefCell; 7 | use std::ffi::CString; 8 | use std::mem; 9 | use ui_sys::{self, uiControl, uiWindow}; 10 | 11 | thread_local! { 12 | static WINDOWS: RefCell> = RefCell::new(Vec::new()) 13 | } 14 | 15 | define_control!(Window, uiWindow, ui_window); 16 | 17 | impl Window { 18 | #[inline] 19 | pub fn as_ui_window(&self) -> *mut uiWindow { 20 | self.ui_window 21 | } 22 | 23 | #[inline] 24 | pub fn title(&self) -> Text { 25 | ffi_utils::ensure_initialized(); 26 | unsafe { 27 | Text::new(ui_sys::uiWindowTitle(self.ui_window)) 28 | } 29 | } 30 | 31 | #[inline] 32 | pub fn set_title(&self, title: &str) { 33 | ffi_utils::ensure_initialized(); 34 | unsafe { 35 | let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); 36 | ui_sys::uiWindowSetTitle(self.ui_window, c_string.as_ptr()) 37 | } 38 | } 39 | 40 | #[inline] 41 | pub fn on_closing(&self, callback: Box bool>) { 42 | ffi_utils::ensure_initialized(); 43 | unsafe { 44 | let mut data: Box bool>> = Box::new(callback); 45 | ui_sys::uiWindowOnClosing(self.ui_window, 46 | c_callback, 47 | &mut *data as *mut Box bool> as 48 | *mut c_void); 49 | mem::forget(data); 50 | } 51 | 52 | extern "C" fn c_callback(window: *mut uiWindow, data: *mut c_void) -> i32 { 53 | unsafe { 54 | let window = Window { 55 | ui_window: window, 56 | }; 57 | mem::transmute::<*mut c_void, 58 | Box bool>>>(data)(&window) as i32 59 | } 60 | } 61 | } 62 | 63 | #[inline] 64 | pub fn set_child(&self, child: Control) { 65 | ffi_utils::ensure_initialized(); 66 | unsafe { 67 | ui_sys::uiWindowSetChild(self.ui_window, child.as_ui_control()) 68 | } 69 | } 70 | 71 | #[inline] 72 | pub fn margined(&self) -> bool { 73 | ffi_utils::ensure_initialized(); 74 | unsafe { 75 | ui_sys::uiWindowMargined(self.ui_window) != 0 76 | } 77 | } 78 | 79 | #[inline] 80 | pub fn set_margined(&self, margined: bool) { 81 | ffi_utils::ensure_initialized(); 82 | unsafe { 83 | ui_sys::uiWindowSetMargined(self.ui_window, margined as c_int) 84 | } 85 | } 86 | 87 | #[inline] 88 | pub fn new(title: &str, width: c_int, height: c_int, has_menubar: bool) -> Window { 89 | ffi_utils::ensure_initialized(); 90 | unsafe { 91 | let c_string = CString::new(title.as_bytes().to_vec()).unwrap(); 92 | let window = Window::from_ui_window(ui_sys::uiNewWindow(c_string.as_ptr(), 93 | width, 94 | height, 95 | has_menubar as c_int)); 96 | 97 | WINDOWS.with(|windows| windows.borrow_mut().push(window.clone())); 98 | 99 | window 100 | } 101 | } 102 | 103 | #[inline] 104 | pub unsafe fn from_ui_window(window: *mut uiWindow) -> Window { 105 | Window { 106 | ui_window: window, 107 | } 108 | } 109 | 110 | pub unsafe fn destroy_all_windows() { 111 | WINDOWS.with(|windows| { 112 | let mut windows = windows.borrow_mut(); 113 | for window in windows.drain(..) { 114 | window.destroy() 115 | } 116 | }) 117 | } 118 | } 119 | 120 | --------------------------------------------------------------------------------