diff --git a/Cargo.toml b/Cargo.toml index e6714c8..cdf93bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "iris" version = "0.1.0" edition = "2024" +default-run = "test" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/testing/app.rs b/src/bin/test/app.rs similarity index 100% rename from src/testing/app.rs rename to src/bin/test/app.rs diff --git a/src/testing/assets/sungals.png b/src/bin/test/assets/sungals.png similarity index 100% rename from src/testing/assets/sungals.png rename to src/bin/test/assets/sungals.png diff --git a/src/testing/input.rs b/src/bin/test/input.rs similarity index 98% rename from src/testing/input.rs rename to src/bin/test/input.rs index ea8135c..2dfb729 100644 --- a/src/testing/input.rs +++ b/src/bin/test/input.rs @@ -1,3 +1,4 @@ +use crate::Client; use iris::{ core::{CursorState, Modifiers}, layout::Vec2, @@ -7,8 +8,6 @@ use winit::{ keyboard::{Key, NamedKey}, }; -use crate::testing::Client; - #[derive(Default)] pub struct Input { cursor: CursorState, diff --git a/src/testing/mod.rs b/src/bin/test/main.rs similarity index 99% rename from src/testing/mod.rs rename to src/bin/test/main.rs index b00af23..413f335 100644 --- a/src/testing/mod.rs +++ b/src/bin/test/main.rs @@ -1,20 +1,18 @@ -use std::sync::Arc; - use app::App; use arboard::Clipboard; use cosmic_text::Family; +use input::Input; use iris::prelude::*; -use render::Renderer; -use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::Window}; - -use crate::testing::input::Input; use len_fns::*; +use render::Renderer; +use std::sync::Arc; +use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::Window}; mod app; mod input; mod render; -pub fn main() { +fn main() { App::run(); } @@ -100,8 +98,6 @@ impl Client { .stack() .add_static(&mut ui); - let main = pad_test.pad(10).add_static(&mut ui); - let btext = |content| text(content).size(30); let text_test = ( @@ -176,6 +172,8 @@ impl Client { .span(Dir::DOWN) .add_static(&mut ui); + let main = pad_test.pad(10).add_static(&mut ui); + let switch_button = |color, to, label| { let rect = rect(color) .id_on(CursorSense::click(), move |id, ui: &mut Ui, _| { diff --git a/src/testing/render/mod.rs b/src/bin/test/render/mod.rs similarity index 100% rename from src/testing/render/mod.rs rename to src/bin/test/render/mod.rs diff --git a/src/core/position/mod.rs b/src/core/position/mod.rs index a648912..5241c90 100644 --- a/src/core/position/mod.rs +++ b/src/core/position/mod.rs @@ -1,6 +1,7 @@ mod align; mod offset; mod pad; +mod scroll; mod sized; mod span; mod stack; diff --git a/src/core/position/scroll.rs b/src/core/position/scroll.rs new file mode 100644 index 0000000..7400b9a --- /dev/null +++ b/src/core/position/scroll.rs @@ -0,0 +1,39 @@ +use crate::prelude::*; + +pub struct Scroll { + inner: WidgetId, + axis: Axis, + snap_end: bool, + amt: f32, + draw_len: f32, +} + +impl Widget for Scroll { + fn draw(&mut self, painter: &mut Painter) { + let output_len = painter.output_size().axis(self.axis); + let container_len = painter.region().axis(self.axis).len(); + let content_len = painter + .len_axis(&self.inner, self.axis) + .apply_rest() + .within_len(container_len) + .to_abs(output_len); + let container_len = container_len.to_abs(output_len); + self.draw_len = content_len; + // let region = UiRegion::FULL.offset(self.amt); + // painter.widget_within(&self.inner, region); + } + + fn desired_width(&mut self, _: &mut SizeCtx) -> Len { + Len::default() + } + + fn desired_height(&mut self, _: &mut SizeCtx) -> Len { + Len::default() + } +} + +impl Scroll { + pub fn scroll(&mut self, amt: f32) { + self.amt += amt; + } +} diff --git a/src/core/position/span.rs b/src/core/position/span.rs index eb3de80..a93b73c 100644 --- a/src/core/position/span.rs +++ b/src/core/position/span.rs @@ -11,6 +11,9 @@ impl Widget for Span { fn draw(&mut self, painter: &mut Painter) { let total = self.len_sum(&mut painter.size_ctx()); let mut start = UiScalar::rel_min(); + if painter.label() == "fricker" { + println!("redraw"); + } for child in &self.children { let mut span = UiSpan::FULL; span.start = start; @@ -88,7 +91,10 @@ impl Span { } fn desired_ortho(&mut self, ctx: &mut SizeCtx) -> Len { - // this is an awful hack to get text wrapping to work properly when in a downward span + // this is a weird hack to get text wrapping to work properly when in a downward span + // the correct solution here is to add a function to widget that lets them + // request that ctx.outer has an axis "resolved" before checking the other, + // and panicking or warning if two request opposite axis (unsolvable in that case) let outer = ctx.outer.axis(self.dir.axis); if self.dir.axis == Axis::X { // so....... this literally copies draw so that the lengths are correctly set in the diff --git a/src/core/text/edit.rs b/src/core/text/edit.rs index 340f7e5..4ed9ed5 100644 --- a/src/core/text/edit.rs +++ b/src/core/text/edit.rs @@ -26,7 +26,6 @@ impl TextEdit { .lines .iter() .map(|l| l.text()) - // why is this needed?? what?? .collect::>() .join("\n") } @@ -44,9 +43,7 @@ impl Widget for TextEdit { let size = vec2(1, self.attrs.line_height); painter.primitive_within( RectPrimitive::color(Color::WHITE), - size.align(Align::TOP_LEFT) - .offset(offset) - .within(®ion), + size.align(Align::TOP_LEFT).offset(offset).within(®ion), ); } } diff --git a/src/layout/orientation/len.rs b/src/layout/orientation/len.rs index 094e4c8..88d5c17 100644 --- a/src/layout/orientation/len.rs +++ b/src/layout/orientation/len.rs @@ -29,6 +29,12 @@ impl From<(Nx, Ny)> for Size { } } +impl From for Size { + fn from(value: Len) -> Self { + Self { x: value, y: value } + } +} + impl Size { pub const ZERO: Self = Self { x: Len::ZERO, @@ -171,10 +177,10 @@ impl std::fmt::Display for Len { write!(f, "{} abs;", self.abs)?; } if self.rel != 0.0 { - write!(f, "{} rel;", self.abs)?; + write!(f, "{} rel;", self.rel)?; } if self.rest != 0.0 { - write!(f, "{} leftover;", self.abs)?; + write!(f, "{} rest;", self.rest)?; } Ok(()) } diff --git a/src/layout/orientation/pos.rs b/src/layout/orientation/pos.rs index c0d49bc..885a329 100644 --- a/src/layout/orientation/pos.rs +++ b/src/layout/orientation/pos.rs @@ -78,7 +78,10 @@ impl UiVec2 { } pub fn to_abs(&self, rel: Vec2) -> Vec2 { - self.get_rel() * rel + self.get_abs() + Vec2 { + x: self.x.to_abs(rel.x), + y: self.y.to_abs(rel.y), + } } pub const FULL_SIZE: Self = Self::rel(Vec2::ONE); @@ -231,6 +234,10 @@ impl UiScalar { pub const fn to(&self, end: Self) -> UiSpan { UiSpan { start: *self, end } } + + pub const fn to_abs(&self, rel: f32) -> f32 { + self.rel * rel + self.abs + } } #[repr(C)] @@ -323,6 +330,14 @@ impl UiRegion { y: self.y.outside(&parent.y), } } + + pub const fn axis(&mut self, axis: Axis) -> &UiSpan { + match axis { + Axis::X => &self.x, + Axis::Y => &self.y, + } + } + pub const fn axis_mut(&mut self, axis: Axis) -> &mut UiSpan { match axis { Axis::X => &mut self.x, diff --git a/src/layout/painter.rs b/src/layout/painter.rs index ddc479a..a845bf8 100644 --- a/src/layout/painter.rs +++ b/src/layout/painter.rs @@ -29,19 +29,20 @@ pub struct PainterCtx<'a> { pub textures: &'a mut Textures, pub masks: &'a mut TrackedArena, pub text: &'a mut TextData, - pub screen_size: Vec2, + pub output_size: Vec2, pub modules: &'a mut Modules, pub cache_width: HashMap, pub cache_height: HashMap, draw_started: HashSet, } -#[derive(Default)] +#[derive(Clone, Copy, Debug, Default)] pub struct ResizeRef { x: Option<(Id, (UiVec2, Len))>, y: Option<(Id, (UiVec2, Len))>, } +#[derive(Debug)] pub struct WidgetInstance { pub id: Id, pub region: UiRegion, @@ -75,7 +76,7 @@ impl<'a> PainterCtx<'a> { layers: &mut data.layers, textures: &mut data.textures, text: &mut data.text, - screen_size: data.output_size, + output_size: data.output_size, modules: &mut data.modules, masks: &mut data.masks, cache_width: Default::default(), @@ -91,9 +92,16 @@ impl<'a> PainterCtx<'a> { let Some(active) = self.active.get(&id) else { return; }; + let mut resize = active.resize; - // TODO: this is stupid having 2 of these - if let Some((rid, (outer, old_desired))) = active.resize.x { + let finish = |s: &mut Self, resize| { + if let Some(active) = s.active.get_mut(&id) { + active.resize = resize; + } + }; + + // TODO: this is stupid having 2 of these, don't ask me what the consequences are + if let Some((rid, (outer, old_desired))) = &mut resize.x { let new_desired = SizeCtx { source: id, cache_width: &mut self.cache_width, @@ -101,25 +109,23 @@ impl<'a> PainterCtx<'a> { text: self.text, textures: self.textures, widgets: self.widgets, - outer, - output_size: self.screen_size, + outer: *outer, + output_size: self.output_size, checked_width: &mut Default::default(), checked_height: &mut Default::default(), id, } .width_inner(id); - if new_desired != old_desired { - self.redraw(rid); + if new_desired != *old_desired { + self.redraw(*rid); + *old_desired = new_desired; if self.draw_started.contains(&id) { - return; + return finish(self, resize); } } } - let Some(active) = self.active.get(&id) else { - return; - }; - if let Some((rid, (outer, old_desired))) = active.resize.y { + if let Some((rid, (outer, old_desired))) = &mut resize.y { let new_desired = SizeCtx { source: id, cache_width: &mut self.cache_width, @@ -127,17 +133,18 @@ impl<'a> PainterCtx<'a> { text: self.text, textures: self.textures, widgets: self.widgets, - outer, - output_size: self.screen_size, + outer: *outer, + output_size: self.output_size, checked_width: &mut Default::default(), checked_height: &mut Default::default(), id, } .height_inner(id); - if new_desired != old_desired { - self.redraw(rid); + if new_desired != *old_desired { + self.redraw(*rid); + *old_desired = new_desired; if self.draw_started.contains(&id) { - return; + return finish(self, resize); } } } @@ -154,7 +161,7 @@ impl<'a> PainterCtx<'a> { active.mask, Some(active.children), ); - self.active.get_mut(&id).unwrap().resize = active.resize; + finish(self, resize); } pub fn draw(&mut self, id: Id) { @@ -399,7 +406,7 @@ impl<'a, 'c> Painter<'a, 'c> { text: self.ctx.text, textures: self.ctx.textures, widgets: self.ctx.widgets, - output_size: self.ctx.screen_size, + output_size: self.ctx.output_size, checked_width: &mut self.children_width, checked_height: &mut self.children_height, cache_width: &mut self.ctx.cache_width, @@ -410,8 +417,12 @@ impl<'a, 'c> Painter<'a, 'c> { } } + pub fn output_size(&self) -> Vec2 { + self.ctx.output_size + } + pub fn px_size(&mut self) -> Vec2 { - self.region.size().to_abs(self.ctx.screen_size) + self.region.size().to_abs(self.ctx.output_size) } pub fn text_data(&mut self) -> &mut TextData { diff --git a/src/layout/texture.rs b/src/layout/texture.rs index c28e79f..b34616e 100644 --- a/src/layout/texture.rs +++ b/src/layout/texture.rs @@ -7,7 +7,7 @@ use image::{DynamicImage, GenericImageView}; use crate::{layout::Vec2, render::TexturePrimitive, util::RefCounter}; -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct TextureHandle { inner: TexturePrimitive, size: Vec2, diff --git a/src/layout/ui.rs b/src/layout/ui.rs index b4ddd84..4ece198 100644 --- a/src/layout/ui.rs +++ b/src/layout/ui.rs @@ -4,7 +4,7 @@ use crate::{ core::{TextEdit, TextEditCtx}, layout::{ IdLike, PainterCtx, PainterData, PixelRegion, StaticWidgetId, TextureHandle, Vec2, Widget, - WidgetId, WidgetLike, + WidgetId, WidgetInstance, WidgetLike, }, util::{HashSet, Id}, }; @@ -184,20 +184,11 @@ impl Ui { Some(region.to_px(self.data.output_size)) } - pub fn debug(&self, label: &str) { - for (id, inst) in &self.data.active { - let l = &self.data.widgets.data(id).unwrap().label; - if l != label { - continue; - } - println!("\"{label}\" {{"); - println!(" region: {}", inst.region); - println!( - " pixel region: {}", - inst.region.to_px(self.data.output_size) - ); - println!("}}"); - } + pub fn debug(&self, label: &str) -> impl Iterator { + self.data.active.iter().filter_map(move |(id, inst)| { + let l = &self.data.widgets.label(id); + if *l == label { Some(inst) } else { None } + }) } } diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 3d74eae..0000000 --- a/src/main.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod testing; - -fn main() { - testing::main(); -} diff --git a/src/render/primitive.rs b/src/render/primitive.rs index 3dbb1bb..62fbec1 100644 --- a/src/render/primitive.rs +++ b/src/render/primitive.rs @@ -223,7 +223,7 @@ impl RectPrimitive { } #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct TexturePrimitive { pub view_idx: u32, pub sampler_idx: u32, diff --git a/src/util/id.rs b/src/util/id.rs index 078a30b..2865e41 100644 --- a/src/util/id.rs +++ b/src/util/id.rs @@ -26,6 +26,9 @@ impl IdTracker { } impl Id { + pub(crate) fn raw(id: I) -> Self { + Self(id) + } pub fn idx(&self) -> usize { self.0.idx() } diff --git a/src/util/refcount.rs b/src/util/refcount.rs index 7e695bb..12429be 100644 --- a/src/util/refcount.rs +++ b/src/util/refcount.rs @@ -3,6 +3,7 @@ use std::sync::{ atomic::{AtomicU32, Ordering}, }; +#[derive(Debug)] pub struct RefCounter(Arc); impl RefCounter {