Compare commits

3 Commits

Author SHA1 Message Date
acd67179b7 fix mask coords... might wanna change cpu output? 2025-11-20 23:01:01 -05:00
dff72d2c43 I love control flow 2025-11-20 22:48:08 -05:00
f6f9ebbe51 tuple gaming 2025-11-20 15:56:00 -05:00
23 changed files with 156 additions and 86 deletions

View File

@@ -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

View File

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -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,

View File

@@ -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, _| {

View File

@@ -6,6 +6,7 @@ pub struct Masked {
impl Widget for Masked {
fn draw(&mut self, painter: &mut Painter) {
println!("yahoo! {}", painter.region());
painter.set_mask(painter.region());
painter.widget(&self.inner);
}

View File

@@ -7,31 +7,20 @@ pub struct Aligned {
impl Widget for Aligned {
fn draw(&mut self, painter: &mut Painter) {
let region = match self.align {
Align {
x: Some(x),
y: Some(y),
} => {
painter
.size(&self.inner)
.to_uivec2()
.align(RegionAlign { x, y })
}
Align {
x: Some(x),
y: None,
} => {
let region = match self.align.tuple() {
(Some(x), Some(y)) => painter
.size(&self.inner)
.to_uivec2()
.align(RegionAlign { x, y }),
(Some(x), None) => {
let x = painter.size_ctx().width(&self.inner).apply_rest().align(x);
UiRegion::new(x, UiSpan::FULL)
}
Align {
x: None,
y: Some(y),
} => {
(None, Some(y)) => {
let y = painter.size_ctx().height(&self.inner).apply_rest().align(y);
UiRegion::new(UiSpan::FULL, y)
}
Align { x: None, y: None } => UiRegion::FULL,
(None, None) => UiRegion::FULL,
};
painter.widget_within(&self.inner, region);
}

View File

@@ -1,6 +1,7 @@
mod align;
mod offset;
mod pad;
mod scroll;
mod sized;
mod span;
mod stack;

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -26,7 +26,6 @@ impl TextEdit {
.lines
.iter()
.map(|l| l.text())
// why is this needed?? what??
.collect::<Vec<_>>()
.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(&region),
size.align(Align::TOP_LEFT).offset(offset).within(&region),
);
}
}

View File

@@ -24,6 +24,10 @@ impl Align {
pub const TOP: CardinalAlign = CardinalAlign::TOP;
pub const V_CENTER: CardinalAlign = CardinalAlign::V_CENTER;
pub const BOT: CardinalAlign = CardinalAlign::BOT;
pub fn tuple(&self) -> (Option<AxisAlign>, Option<AxisAlign>) {
(self.x, self.y)
}
}
#[derive(Clone, Copy, PartialEq, Eq)]

View File

@@ -29,6 +29,12 @@ impl<Nx: UiNum, Ny: UiNum> From<(Nx, Ny)> for Size {
}
}
impl From<Len> 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(())
}

View File

@@ -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,

View File

@@ -29,19 +29,20 @@ pub struct PainterCtx<'a> {
pub textures: &'a mut Textures,
pub masks: &'a mut TrackedArena<Mask, u32>,
pub text: &'a mut TextData,
pub screen_size: Vec2,
pub output_size: Vec2,
pub modules: &'a mut Modules,
pub cache_width: HashMap<Id, (UiVec2, Len)>,
pub cache_height: HashMap<Id, (UiVec2, Len)>,
draw_started: HashSet<Id>,
}
#[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 {

View File

@@ -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,

View File

@@ -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<Item = &WidgetInstance> {
self.data.active.iter().filter_map(move |(id, inst)| {
let l = &self.data.widgets.label(id);
if *l == label { Some(inst) } else { None }
})
}
}

View File

@@ -1,5 +0,0 @@
mod testing;
fn main() {
testing::main();
}

View File

@@ -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,

View File

@@ -21,8 +21,18 @@ struct TextureInfo {
}
struct Mask {
top_left: UiVec2,
bot_right: UiVec2,
x: UiSpan,
y: UiSpan,
}
struct UiSpan {
start: UiScalar,
end: UiScalar,
}
struct UiScalar {
rel: f32,
abs: f32,
}
struct UiVec2 {
@@ -121,8 +131,11 @@ fn fs_main(
}
if in.mask_idx != 4294967295u {
let mask = masks[in.mask_idx];
let top_left = floor(mask.top_left.rel * window.dim) + floor(mask.top_left.abs);
let bot_right = floor(mask.bot_right.rel * window.dim) + floor(mask.bot_right.abs);
let tl = UiVec2(vec2(mask.x.start.rel, mask.y.start.rel), vec2(mask.x.start.abs, mask.y.start.abs));
let br = UiVec2(vec2(mask.x.end.rel, mask.y.end.rel), vec2(mask.x.end.abs, mask.y.end.abs));
let top_left = floor(tl.rel * window.dim) + floor(tl.abs);
let bot_right = floor(br.rel * window.dim) + floor(br.abs);
if pos.x < top_left.x || pos.x > bot_right.x || pos.y < top_left.y || pos.y > bot_right.y {
color *= 0.0;
}

View File

@@ -26,6 +26,9 @@ impl<I: IdNum> IdTracker<I> {
}
impl<I: IdNum> Id<I> {
pub(crate) fn raw(id: I) -> Self {
Self(id)
}
pub fn idx(&self) -> usize {
self.0.idx()
}

View File

@@ -3,6 +3,7 @@ use std::sync::{
atomic::{AtomicU32, Ordering},
};
#[derive(Debug)]
pub struct RefCounter(Arc<AtomicU32>);
impl RefCounter {