1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//! # Immediate mode UI and general application architecture
//!
//! The principle of immediate more UI is that the position and dimensions of the UI elements are
//! calculated at each frame. The current state of the user interface (for example the content of
//! text boxes, if there are multiple tabs which one is the current one, etc.) is not stored within
//! widgets themselves, but in an external structure.
//! 
//! Here is how you design your code in order to work with immi:
//! 
//! - You define a custom structure that describes the state of your user interface.
//! - You define a type that implements the `immi::Draw` trait.
//! - You define a function whose purpose is to draw your user interface. Usually you want to
//!   create one function for each part of the UI instead, and call all of them in a main function.
//! 
//! There are only two objects that you store persistently:
//! 
//! - An instance of your custom struct that describes your UI.
//! - An instance of `immi::UiState`.
//! 
//! These two objects describe your user interface. They are the only state that is required.
//! 
//! At each frame, when it is time to draw your UI, you:
//! 
//! - Call `immi::draw` and pass a reference to your `immi::UiState`. You will get
//!   a `SharedDrawContext`. This object represents a context for drawing the entirety of your UI.
//! - Sometimes you need to share information between multiple user interfaces. For example in a
//!   game you sometimes have a main UI, but also small in-game overlays. A shared draw context
//!   shares data between all of these. Call `draw()` on your `SharedDrawContext` in order to
//!   obtain a `DrawContext`. You will need to pass your drawing object.
//! - Once you have a `DrawContext`, call your custom UI-drawing function, and pass the
//!   `DrawContext` by reference and your custom UI-state struct by mutable reference.
//! - The function draws the various elements and updates the UI state.
//!
//! ## Example
//!
//! ```rust
//! // Object that will allow you to draw the UI.
//! struct MyDrawer;
//! impl immi::Draw for MyDrawer {
//!     type ImageResource = str;
//!     type FontResource = str;
//! 
//!     fn draw_triangle(&mut self, _: &str, _: &immi::Matrix, _: [[f32; 2]; 3]) {}
//!     fn get_image_width_per_height(&mut self, _: &str) -> f32 { 1.0 }
//!     fn draw_text(&mut self, _: &str, _: &immi::Matrix, _: &str, _: [f32; 3]) { }
//!     fn get_text_width_per_em(&mut self, _: &str, _: &str) -> f32 { 1.0 }
//! }
//! 
//! struct MyUiState {
//!     widget1_text: String,
//!     checkbox: bool,
//! }
//! 
//! fn draw_ui(ctxt: &immi::DrawContext<MyDrawer>, ui_state: &mut MyUiState) {
//!     // ...
//! }
//! 
//! let mut immi_state = immi::UiState::default();
//! let mut my_state = MyUiState { widget1_text: String::new(), checkbox: false };
//! let mut drawer = MyDrawer;
//! 
//! loop {
//!     let ui_context = immi::draw(&mut immi_state);
//!     let ui_context = ui_context.draw(1024.0, 768.0, &mut drawer, None, false, false);
//!     draw_ui(&ui_context, &mut my_state);
//! # break;
//! }
//! ```
//!
//! # Drawing
//!
//! Once you have a `DrawContext` you can start drawing your user interface.
//!
//! A `DrawContext` represents an area of the viewport where things you should be drawn. Initially
//! this area contain the whole viewport, but you can call methods on the `DrawContext` to adjust
//! this area.
//!
//! Example:
//!
//! ```rust
//! fn draw_ui<D>(draw: immi::DrawContext<D>) where D: immi::Draw<ImageResource = str> {
//!     // draws an image on the whole screen
//!     // the bottom alignment is used if the aspect ratio of the image doesn't match the aspect
//!     // ratio of the viewport
//!     immi::widgets::image::draw(&draw, "background", &immi::Alignment::bottom());
//!
//!     // we resize the viewport so that it only covers the top half of the screen
//!     let draw = draw.vertical_rescale(0.5, &immi::VerticalAlignment::Top);
//!
//!     // draws an image on the top half of the screen
//!     immi::widgets::image::draw(&draw, "top_background", &immi::Alignment::center());
//! }
//! ```
//!
extern crate time;

pub use draw::Draw;
pub use id::WidgetId;
pub use layout::draw;
pub use layout::Alignment;
pub use layout::DrawContext;
pub use layout::SharedDrawContext;
pub use layout::HorizontalAlignment;
pub use layout::VerticalAlignment;
pub use matrix::Matrix;

mod draw;
mod id;
mod layout;
mod matrix;

pub mod animations;
pub mod widgets;

/// Contains some persistent info about the UI.
#[derive(Clone, Default, PartialEq, Eq)]
pub struct UiState {
    /// Identifier of the widget that is currently active.
    ///
    /// For example if you maintain the left button of the mouse, the element under will be active.
    /// If you then move your mouse somewhere else, the active element doesn't change.
    pub active_widget: Option<WidgetId>,
}