1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! [`Surface`](crate::surface::Surface): an area-clipped, single-layer view over a [`Grid`](crate::grid::Grid).
//!
//! `Surface` is the workspace's one grid-drawing primitive. [`Terminal`](crate::terminal::Terminal)'s
//! [`draw`](crate::terminal::Terminal::draw)/[`surface`](crate::terminal::Terminal::surface) hand out a `Surface`
//! scoped to the whole grid, and `retroglyph-ui` renders every widget into a `Surface`
//! scoped to a sub-[`Rect`](crate::grid::Rect): there is no separate stateful drawing API on `Terminal` itself.
//!
//! Place characters directly with [`put`](crate::surface::Surface::put) (or [`print`](crate::surface::Surface::print) for a
//! string, which handles newlines and wide characters), style-aware spans with
//! [`print_line`](crate::surface::Surface::print_line), or a whole styled run with
//! [`with_style`](crate::surface::Surface::with_style) so repeated calls don't need to pass the same [`Style`](crate::color::Style)
//! each time. [`clear`](crate::surface::Surface::clear)/[`clear_region`](crate::surface::Surface::clear_region) blank the active
//! layer (in full, or a rectangular region); switch layers with
//! [`on_layer`](crate::surface::Surface::on_layer). Or bypass the builder entirely and reach the [`Grid`](crate::grid::Grid)
//! directly via [`grid_mut`](crate::surface::Surface::grid_mut).
use crateTint;
use crate;
pub use StyledSurface;
/// The render target for every drawing call in the workspace: a mutable reference to a
/// [`Grid`](crate::grid::Grid) plus a fixed `layer`, scoped to an `area` and clipped to a `clip` rect.
///
/// A `Surface` is typically created once per frame, scoped to the whole drawing surface (e.g.
/// via [`Terminal::draw`](crate::terminal::Terminal::draw)), and handed to every subsystem/widget in turn;
/// each caller's own `area: Rect` (a sub-rect of the surface's own area, e.g. one produced by a
/// layout split) is relative to this surface's own `area` origin, not to the underlying grid.
/// [`Surface::put`](crate::surface::Surface::put)/[`Surface::print`](crate::surface::Surface::print)/... take coordinates in that same local space, where
/// `(0, 0)` is `area`'s top-left corner, and silently drop any write that falls outside
/// [`Surface::clip_rect`](crate::surface::Surface::clip_rect), matching the rest of the workspace's clip-on-draw policy for
/// out-of-bounds drawing.
///
/// `area` and `clip_rect` answer two different questions. `area` is the region this surface
/// *represents*: what a widget lays itself out in, and what [`width`](Self::width)/
/// [`height`](Self::height) report. `clip_rect` is the subset of `area` that is actually
/// *visible*: what every write is bounds-checked against. The two start out equal (see
/// [`Surface::new`](crate::surface::Surface::new)) and diverge once [`Surface::clip`](crate::surface::Surface::clip) or [`Surface::scope`](crate::surface::Surface::scope) is used.
///
/// [`Surface::clip`](crate::surface::Surface::clip) narrows what is visible without changing what this surface represents:
/// `clip_rect` is intersected with the given rect, `area` is untouched. [`Surface::scope`](crate::surface::Surface::scope) does
/// both: `area` becomes the given rect and `clip_rect` is intersected with it, which is what a
/// widget's own sub-surface needs when it should be laid out against a new rect but still bounded
/// by whatever was already visible. Both narrow monotonically: neither can widen `clip_rect`
/// beyond what the parent surface already allowed.
///
/// A caller that genuinely needs more than one layer at once (e.g. a modal dimming layer 0 while
/// drawing its own content on layer 1) switches layers with [`Surface::on_layer`](crate::surface::Surface::on_layer)/[`Surface::on_tier`](crate::surface::Surface::on_tier)
/// rather than being restricted to the layer it was constructed with.
/// A named z-order tier for [`Surface::on_tier`](crate::surface::Surface::on_tier), covering the split most apps with overlapping
/// UI actually need.
///
/// Layers are how overlapping UI avoids depending on draw order: a caller who paints a dropdown
/// on [`Layer::Overlay`](crate::surface::Layer::Overlay) gets it on top of the active screen regardless of whether the screen or
/// the dropdown drew first this frame, so the two don't have to agree on an ordering (contrast
/// with painting both through the same layer, where whichever call happens to run last wins).
///
/// `Layer` derives [`Ord`] over its declaration order, so `Layer::World < Layer::Hud <
/// Layer::Overlay < Layer::Debug` holds without spelling out the underlying grid layer ids --
/// the same relationship [`Surface::on_tier`](crate::surface::Surface::on_tier) relies on to keep `Layer::Debug` the top-most tier
/// no matter what else is open.
///
/// This is a convention, not a restriction: [`Surface::on_layer`](crate::surface::Surface::on_layer) still accepts any `u8`, and a
/// tile map or sprite-heavy app with its own multi-layer scheme (terrain/items/actors/...) has no
/// reason to route through `Layer` at all. `Layer` exists for the overlapping-*UI* case:
/// chrome, popups, debug HUDs, where a small, shared, named split is worth more than 256 open
/// numeric ids.
///
/// # Examples
///
/// A persistent HUD bar and a dropdown that must paint over it, in either order, because they're
/// on different tiers rather than racing to draw last:
///
/// ```
/// use retroglyph_core::color::Style;
/// use retroglyph_core::grid::{Grid, Rect};
/// use retroglyph_core::surface::{Layer, Surface};
///
/// let area = Rect::new(0, 0, 20, 5);
/// let mut grid = Grid::new(20, 5);
/// let mut surface = Surface::new(&mut grid, area, Layer::World.as_u8());
///
/// // The active screen draws on `World`.
/// surface.print((0, 0), "screen content", Style::default());
///
/// // Chrome draws on `Hud`, above the screen.
/// surface.on_tier(Layer::Hud).print((0, 0), "File Edit View", Style::default());
///
/// // A dropdown draws on `Overlay`, above the HUD: painting it before or after the two calls
/// // above makes no difference, because it's on a higher tier, not drawn later.
/// surface.on_tier(Layer::Overlay).print((0, 1), "New", Style::default());
/// ```