174 lines
5.2 KiB
Rust
174 lines
5.2 KiB
Rust
use crate::{
|
|
Axis, Len, RenderedText, Size, SizeCtx, TextAttrs, TextBuffer, TextData, TextureHandle, Ui,
|
|
UiRegion, UiVec2, WidgetHandle, WidgetId,
|
|
render::{Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst},
|
|
ui::draw_state::DrawState,
|
|
util::{HashMap, Vec2},
|
|
};
|
|
|
|
/// makes your surfaces look pretty
|
|
pub struct Painter<'a, 'b, State> {
|
|
pub(super) state: &'a mut DrawState<'b, State>,
|
|
|
|
pub(super) region: UiRegion,
|
|
pub(super) mask: MaskIdx,
|
|
pub(super) textures: Vec<TextureHandle>,
|
|
pub(super) primitives: Vec<PrimitiveHandle>,
|
|
pub(super) children: Vec<WidgetId>,
|
|
pub(super) children_width: HashMap<WidgetId, (UiVec2, Len)>,
|
|
pub(super) children_height: HashMap<WidgetId, (UiVec2, Len)>,
|
|
pub layer: usize,
|
|
pub(super) id: WidgetId,
|
|
}
|
|
|
|
/// stores information for children about the highest level parent that needed their size
|
|
/// so that they can redraw the parent if their size changes
|
|
#[derive(Clone, Copy, Debug, Default)]
|
|
pub struct ResizeRef {
|
|
pub x: Option<(WidgetId, (UiVec2, Len))>,
|
|
pub y: Option<(WidgetId, (UiVec2, Len))>,
|
|
}
|
|
|
|
/// important non rendering data for retained drawing
|
|
#[derive(Debug)]
|
|
pub struct ActiveData {
|
|
pub id: WidgetId,
|
|
pub region: UiRegion,
|
|
pub parent: Option<WidgetId>,
|
|
pub textures: Vec<TextureHandle>,
|
|
pub primitives: Vec<PrimitiveHandle>,
|
|
pub children: Vec<WidgetId>,
|
|
pub resize: ResizeRef,
|
|
pub mask: MaskIdx,
|
|
pub layer: usize,
|
|
}
|
|
|
|
impl<'a, 'c, State: 'static> Painter<'a, 'c, State> {
|
|
fn primitive_at<P: Primitive>(&mut self, primitive: P, region: UiRegion) {
|
|
let h = self.state.layers.write(
|
|
self.layer,
|
|
PrimitiveInst {
|
|
id: self.id,
|
|
primitive,
|
|
region,
|
|
mask_idx: self.mask,
|
|
},
|
|
);
|
|
if self.mask != MaskIdx::NONE {
|
|
// TODO: I have no clue if this works at all :joy:
|
|
self.state.masks.push_ref(self.mask);
|
|
}
|
|
self.primitives.push(h);
|
|
}
|
|
|
|
/// Writes a primitive to be rendered
|
|
pub fn primitive<P: Primitive>(&mut self, primitive: P) {
|
|
self.primitive_at(primitive, self.region)
|
|
}
|
|
|
|
pub fn primitive_within<P: Primitive>(&mut self, primitive: P, region: UiRegion) {
|
|
self.primitive_at(primitive, region.within(&self.region));
|
|
}
|
|
|
|
pub fn set_mask(&mut self, region: UiRegion) {
|
|
assert!(self.mask == MaskIdx::NONE);
|
|
self.mask = self.state.masks.push(Mask { region });
|
|
}
|
|
|
|
/// Draws a widget within this widget's region.
|
|
pub fn widget<W: ?Sized>(&mut self, id: &WidgetHandle<State, W>) {
|
|
self.widget_at(id, self.region);
|
|
}
|
|
|
|
/// Draws a widget somewhere within this one.
|
|
/// Useful for drawing child widgets in select areas.
|
|
pub fn widget_within<W: ?Sized>(&mut self, id: &WidgetHandle<State, W>, region: UiRegion) {
|
|
self.widget_at(id, region.within(&self.region));
|
|
}
|
|
|
|
fn widget_at<W: ?Sized>(&mut self, id: &WidgetHandle<State, W>, region: UiRegion) {
|
|
self.children.push(id.id());
|
|
self.state
|
|
.draw_inner(self.layer, id.id(), region, Some(self.id), self.mask, None);
|
|
}
|
|
|
|
pub fn texture_within(&mut self, handle: &TextureHandle, region: UiRegion) {
|
|
self.textures.push(handle.clone());
|
|
self.primitive_at(handle.primitive(), region.within(&self.region));
|
|
}
|
|
|
|
pub fn texture(&mut self, handle: &TextureHandle) {
|
|
self.textures.push(handle.clone());
|
|
self.primitive(handle.primitive());
|
|
}
|
|
|
|
pub fn texture_at(&mut self, handle: &TextureHandle, region: UiRegion) {
|
|
self.textures.push(handle.clone());
|
|
self.primitive_at(handle.primitive(), region);
|
|
}
|
|
|
|
/// returns (handle, offset from top left)
|
|
pub fn render_text(&mut self, buffer: &mut TextBuffer, attrs: &TextAttrs) -> RenderedText {
|
|
self.state
|
|
.ui
|
|
.text
|
|
.draw(buffer, attrs, &mut self.state.ui.textures)
|
|
}
|
|
|
|
pub fn region(&self) -> UiRegion {
|
|
self.region
|
|
}
|
|
|
|
pub fn size<W: ?Sized>(&mut self, id: &WidgetHandle<State, W>) -> Size {
|
|
self.size_ctx().size(id)
|
|
}
|
|
|
|
pub fn len_axis<W: ?Sized>(&mut self, id: &WidgetHandle<State, W>, axis: Axis) -> Len {
|
|
match axis {
|
|
Axis::X => self.size_ctx().width(id),
|
|
Axis::Y => self.size_ctx().height(id),
|
|
}
|
|
}
|
|
|
|
pub fn output_size(&self) -> Vec2 {
|
|
self.state.output_size
|
|
}
|
|
|
|
pub fn px_size(&mut self) -> Vec2 {
|
|
self.region.size().to_abs(self.state.output_size)
|
|
}
|
|
|
|
pub fn text_data(&mut self) -> &mut TextData {
|
|
&mut self.state.text
|
|
}
|
|
|
|
pub fn child_layer(&mut self) {
|
|
self.layer = self.state.layers.child(self.layer);
|
|
}
|
|
|
|
pub fn next_layer(&mut self) {
|
|
self.layer = self.state.layers.next(self.layer);
|
|
}
|
|
|
|
pub fn label(&self) -> &str {
|
|
&self.state.widgets.data(self.id).unwrap().label
|
|
}
|
|
|
|
pub fn id(&self) -> &WidgetId {
|
|
&self.id
|
|
}
|
|
|
|
pub fn size_ctx(&mut self) -> SizeCtx<'_, State> {
|
|
self.state.size_ctx(
|
|
self.id,
|
|
self.region.size(),
|
|
self.id,
|
|
&mut self.children_width,
|
|
&mut self.children_height,
|
|
)
|
|
}
|
|
}
|
|
|
|
impl<State: 'static> Ui<State> {
|
|
}
|