179 lines
5.4 KiB
Rust
179 lines
5.4 KiB
Rust
use crate::{
|
|
Axis, Len, RenderedText, Size, SizeCtx, StrongWidget, TextAttrs, TextBuffer, TextData,
|
|
TextureHandle, UiRegion, UiRenderState, UiRsc, UiScalar, UiVec2, Widget, WidgetId,
|
|
render::{GlyphPrimitive, Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst},
|
|
util::Vec2,
|
|
};
|
|
|
|
/// makes your surfaces look pretty
|
|
pub struct Painter<'a> {
|
|
pub(super) state: &'a mut UiRenderState,
|
|
pub(super) rsc: &'a mut dyn UiRsc,
|
|
|
|
pub(super) region: UiRegion,
|
|
pub(super) mask: MaskIdx,
|
|
pub(super) textures: Vec<TextureHandle>,
|
|
pub(super) primitives: Vec<PrimitiveHandle>,
|
|
pub(super) children: Vec<WidgetId>,
|
|
pub layer: usize,
|
|
pub(super) id: WidgetId,
|
|
}
|
|
|
|
impl<'a> Painter<'a> {
|
|
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.rsc.ui_mut().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.rsc.ui_mut().masks.push(Mask { region });
|
|
}
|
|
|
|
/// Draws a widget within this widget's region.
|
|
pub fn widget<W: ?Sized>(&mut self, id: &StrongWidget<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: &StrongWidget<W>, region: UiRegion) {
|
|
self.widget_at(id, region.within(&self.region));
|
|
}
|
|
|
|
fn widget_at<W: ?Sized>(&mut self, id: &StrongWidget<W>, region: UiRegion) {
|
|
self.children.push(id.id());
|
|
self.state.draw_inner(
|
|
self.layer,
|
|
id.id(),
|
|
region,
|
|
Some(self.id),
|
|
self.mask,
|
|
None,
|
|
self.rsc,
|
|
);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
pub fn render_text(
|
|
&mut self,
|
|
buffer: &mut TextBuffer,
|
|
attrs: &TextAttrs,
|
|
width: Option<f32>,
|
|
) -> RenderedText {
|
|
let ui = self.rsc.ui_mut();
|
|
ui.text.render(buffer, attrs, width, &mut ui.textures)
|
|
}
|
|
|
|
pub fn glyphs(&mut self, text: &RenderedText, origin: UiRegion) {
|
|
let flags_for = |is_color| {
|
|
if is_color {
|
|
GlyphPrimitive::IS_COLOR
|
|
} else {
|
|
0
|
|
}
|
|
};
|
|
for glyph in text.glyphs.iter() {
|
|
let mut region = origin;
|
|
region.x.end = region.x.start;
|
|
region.y.end = region.y.start;
|
|
let mut region = region.offset(UiVec2::abs(glyph.offset));
|
|
region.x.end = region.x.start + UiScalar::abs(glyph.entry.width as f32);
|
|
region.y.end = region.y.start + UiScalar::abs(glyph.entry.height as f32);
|
|
self.primitive_at(
|
|
GlyphPrimitive {
|
|
uv_min: glyph.entry.uv_min,
|
|
uv_max: glyph.entry.uv_max,
|
|
view_idx: glyph.entry.view_idx,
|
|
sampler_idx: glyph.entry.sampler_idx,
|
|
color: text.color,
|
|
flags: flags_for(glyph.entry.is_color),
|
|
},
|
|
region,
|
|
);
|
|
}
|
|
}
|
|
|
|
pub fn region(&self) -> UiRegion {
|
|
self.region
|
|
}
|
|
|
|
pub fn size<W: ?Sized + Widget>(&mut self, id: &StrongWidget<W>) -> Size {
|
|
self.size_ctx().size(id)
|
|
}
|
|
|
|
pub fn len_axis<W: ?Sized + Widget>(&mut self, id: &StrongWidget<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.rsc.ui_mut().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.rsc.widgets().data(self.id).unwrap().label
|
|
}
|
|
|
|
pub fn id(&self) -> &WidgetId {
|
|
&self.id
|
|
}
|
|
|
|
pub fn size_ctx(&mut self) -> SizeCtx<'_> {
|
|
self.state.size_ctx(self.id, self.region.size(), self.rsc)
|
|
}
|
|
}
|