Skip to content

Commit dee0736

Browse files
committed
Improve safety and documentation.
Area event conversions can no longer panic; non-thread-safe things are no longer Send or Sync; documentation of Area and associated types is much improved. This reverts commit 0f05f6c.
1 parent 19e7734 commit dee0736

File tree

3 files changed

+80
-13
lines changed

3 files changed

+80
-13
lines changed

iui/src/controls/area.rs

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,37 @@ impl RustAreaHandler {
117117
}
118118

119119
define_control!{
120-
/// A control which takes up space on which the application can draw custom content.
120+
/// A space on which the application can draw custom content.
121+
/// Area is a Control that represents a blank canvas that a program can draw on as
122+
/// it wishes. Areas also receive keyboard and mouse events, and programs can react
123+
/// to those as they see fit. Drawing and event handling are handled through an
124+
/// instance of a type that implements `AreaHandler` that every `Area` has; see
125+
/// `AreaHandler` for details.
126+
///
127+
/// There are two types of areas. Non-scrolling areas are rectangular and have no
128+
/// scrollbars. Programs can draw on and get mouse events from any point in the
129+
/// `Area`, and the size of the Area is decided by package ui itself, according to
130+
/// the layout of controls in the Window the Area is located in and the size of said
131+
/// Window. There is no way to query the Area's size or be notified when its size
132+
/// changes; instead, you are given the area size as part of the draw and mouse event
133+
/// handlers, for use solely within those handlers.
134+
///
135+
/// Scrolling areas have horziontal and vertical scrollbars. The amount that can be
136+
/// scrolled is determined by the area's size, which is decided by the programmer
137+
/// (both when creating the Area and by a call to SetSize). Only a portion of the
138+
/// Area is visible at any time; drawing and mouse events are automatically adjusted
139+
/// to match what portion is visible, so you do not have to worry about scrolling in
140+
/// your event handlers. AreaHandler has more information.
141+
///
142+
/// The internal coordinate system of an Area is points, which are floating-point and
143+
/// device-independent. For more details, see `AreaHandler`. The size of a scrolling
144+
/// Area must be an exact integer number of points
121145
rust_type: Area,
122146
sys_type: uiArea
123147
}
124148

125149
impl Area {
150+
/// Creates a new non-scrolling area.
126151
pub fn new(ctx: &UI, area_handler: Box<AreaHandler>) -> Area {
127152
unsafe {
128153
let mut rust_area_handler = RustAreaHandler::new(ctx, area_handler);
@@ -134,6 +159,7 @@ impl Area {
134159
}
135160
}
136161

162+
/// Creates a new scrolling area.
137163
pub fn new_scrolling(
138164
ctx: &UI,
139165
area_handler: Box<AreaHandler>,
@@ -156,28 +182,58 @@ impl Area {
156182
Area { uiArea: ui_area }
157183
}
158184

159-
pub fn set_size(&self, _ctx: &UI, width: i64, height: i64) {
185+
/// Sets the size of the area in points.
186+
///
187+
/// # Unsafety
188+
/// If called on a non-scrolling `Area`, this function's behavior is undefined.
189+
pub unsafe fn set_size(&self, _ctx: &UI, width: u64, height: u64) {
190+
// TODO: Check if the area is scrolling?
160191
unsafe { ui_sys::uiAreaSetSize(self.uiArea, width, height) }
161192
}
162193

194+
/// Queues the entire `Area` to be redrawn. This function returns immediately;
195+
/// the `Area` is redrawn when the UI thread is next non-busy.
163196
pub fn queue_redraw_all(&self, _ctx: &UI) {
164197
unsafe { ui_sys::uiAreaQueueRedrawAll(self.uiArea) }
165198
}
166199

167-
pub fn scroll_to(&self, _ctx: &UI, x: f64, y: f64, width: f64, height: f64) {
200+
/// Scrolls the Area to show the given rectangle. This behavior is somewhat
201+
/// implementation defined, but you can assume that as much of the given rectangle
202+
/// as possible will be visible after this call.
203+
///
204+
/// # Unsafety
205+
/// If called on a non-scrolling `Area`, this function's behavior is undefined.
206+
pub unsafe fn scroll_to(&self, _ctx: &UI, x: f64, y: f64, width: f64, height: f64) {
207+
// TODO: Make some way to check whether the given area is scrolling or not.
168208
unsafe { ui_sys::uiAreaScrollTo(self.uiArea, x, y, width, height) }
169209
}
170210
}
171211

212+
/// Provides a drawing context that can be used to draw on an Area, and tells you
213+
/// where to draw. See `AreaHandler` for introductory information.
214+
///
215+
/// Height and width values can change at any time, without generating an event,
216+
/// so do not save them elsewhere.
217+
///
218+
/// The clipping rectangle parameters specify the only area in which drawing is allowed.
219+
/// The system will ensure nothing is drawn outside that area, but drawing is far faster
220+
/// if the program does not attempt to put things out of bounds.
172221
pub struct AreaDrawParams {
222+
/// The `DrawContext` on which to draw. See `DrawContext` for how to draw.
173223
pub context: draw::DrawContext,
174224

225+
/// The width of the `Area`, for non-scrolling `Area`s.
175226
pub area_width: f64,
227+
/// The height of the `Area`, for non-scrolling `Area`s.
176228
pub area_height: f64,
177229

230+
/// Leftmost position of the clipping rectangle.
178231
pub clip_x: f64,
232+
/// Topmost position of the clipping rectangle.
179233
pub clip_y: f64,
234+
/// Width of the clipping rectangle.
180235
pub clip_width: f64,
236+
/// Height of the clipping rectangle.
181237
pub clip_height: f64,
182238
}
183239

@@ -206,6 +262,7 @@ bitflags! {
206262
}
207263

208264
#[derive(Copy, Clone, Debug)]
265+
/// Represents a mouse event in an `Area`.
209266
pub struct AreaMouseEvent {
210267
pub x: f64,
211268
pub y: f64,
@@ -224,7 +281,6 @@ pub struct AreaMouseEvent {
224281
}
225282

226283
impl AreaMouseEvent {
227-
// TODO: check if UI is initialized?
228284
pub fn from_ui_area_mouse_event(ui_area_mouse_event: &uiAreaMouseEvent) -> AreaMouseEvent {
229285
AreaMouseEvent {
230286
x: ui_area_mouse_event.X,
@@ -234,13 +290,15 @@ impl AreaMouseEvent {
234290
down: ui_area_mouse_event.Down,
235291
up: ui_area_mouse_event.Up,
236292
count: ui_area_mouse_event.Count,
237-
modifiers: Modifiers::from_bits(ui_area_mouse_event.Modifiers as u8).unwrap(),
293+
modifiers: Modifiers::from_bits(ui_area_mouse_event.Modifiers as u8)
294+
.unwrap_or(Modifiers::empty()),
238295
held_1_to_64: ui_area_mouse_event.Held1To64,
239296
}
240297
}
241298
}
242299

243300
#[derive(Copy, Clone, Debug)]
301+
/// A keypress or key release event for an `Area`.
244302
pub struct AreaKeyEvent {
245303
pub key: u8,
246304
pub ext_key: ExtKey,
@@ -250,13 +308,14 @@ pub struct AreaKeyEvent {
250308
}
251309

252310
impl AreaKeyEvent {
253-
// TODO: check if UI is initialized?
254311
pub fn from_ui_area_key_event(ui_area_key_event: &uiAreaKeyEvent) -> AreaKeyEvent {
255312
AreaKeyEvent {
256313
key: ui_area_key_event.Key as u8,
257314
ext_key: ui_area_key_event.ExtKey,
258-
modifier: Modifiers::from_bits(ui_area_key_event.Modifier as u8).unwrap(),
259-
modifiers: Modifiers::from_bits(ui_area_key_event.Modifiers as u8).unwrap(),
315+
modifier: Modifiers::from_bits(ui_area_key_event.Modifier as u8)
316+
.unwrap_or(Modifiers::empty()),
317+
modifiers: Modifiers::from_bits(ui_area_key_event.Modifiers as u8)
318+
.unwrap_or(Modifiers::empty()),
260319
up: ui_area_key_event.Up != 0,
261320
}
262321
}

iui/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
//! After initialization, all the functionality used for creating actual UIs is in the [`controls`](controls/index.html) module.
2121
//!
2222
//! Fine-grained control of the event loop is avilable via the [`EventLoop`](struct.EventLoop.html) struct.
23+
//! Be aware the Cocoa (GUI toolkit on Mac OS) requires that the _first thread spawned_ controls
24+
//! the UI, so do _not_ spin off your UI interactions into an alternative thread. You're likely to
25+
//! have problems on Mac OS.
2326
//!
2427
//! For code examples, see the [basic](https://github.com/LeoTindall/libui-rs/blob/master/iui/examples/basic.rs) and
2528
//! [advanced](https://github.com/LeoTindall/libui-rs/blob/master/iui/examples/inputs.rs) examples or the

iui/src/ui.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ impl UI {
4545
///
4646
/// Only one libUI binding can be active at once; if multiple instances are detected,
4747
/// this function will return a [`MultipleInitError`](enum.UIError.html#variant.MultipleInitError).
48+
/// Be aware the Cocoa (GUI toolkit on Mac OS) requires that the _first thread spawned_ controls
49+
/// the UI, so do _not_ spin off your UI interactions into an alternative thread. You're likely to
50+
/// have problems on Mac OS.
4851
///
4952
/// ```
5053
/// # use iui::UI;
@@ -116,8 +119,8 @@ impl UI {
116119
unsafe { ui_sys::uiQuit() }
117120
}
118121

119-
/// Add a callback to the UI queue. These callbacks are run when the UI main() method is called,
120-
/// in the order in which they were queued.
122+
/// Queues a function to be executed on the GUI threa when next possible. Returns
123+
/// immediately, not waiting for the function to be executed.
121124
///
122125
/// # Example
123126
///
@@ -126,11 +129,9 @@ impl UI {
126129
///
127130
/// let ui = UI::init().unwrap();
128131
///
129-
/// // Let the UI exit immediately
130-
/// ui.quit();
131-
///
132132
/// ui.queue_main(|| { println!("Runs first") } );
133133
/// ui.queue_main(|| { println!("Runs second") } );
134+
/// ui.quit();
134135
/// ```
135136
pub fn queue_main<F: FnMut()>(&self, callback: F) {
136137
unsafe {
@@ -158,6 +159,10 @@ impl UI {
158159

159160
/// Provides fine-grained control over the user interface event loop, exposing the `on_tick` event
160161
/// which allows integration with other event loops, custom logic on event ticks, etc.
162+
/// Be aware the Cocoa (GUI toolkit on Mac OS) requires that the _first thread spawned_ controls
163+
/// the UI, so do _not_ spin off your UI interactions into an alternative thread. You're likely to
164+
/// have problems on Mac OS.
165+
161166
pub struct EventLoop {
162167
// This PhantomData prevents UIToken from being Send and Sync
163168
_pd: PhantomData<*mut ()>,

0 commit comments

Comments
 (0)