Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/bootstrap/src/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ impl Graphics {
let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: surface.color_attachment,
view: surface.color_attachment.view,
depth_slice: None,
resolve_target: surface.resolve_target,
resolve_target: surface.color_attachment.resolve_target,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(bg),
store: wgpu::StoreOp::Store,
Expand Down
22 changes: 18 additions & 4 deletions crates/bootstrap/src/multisampling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,15 @@ impl Multisampling {
return SurfaceInfo {
format,
sample_count,
color_attachment: view,
resolve_target: None,
color_attachment: wgpu::RenderPassColorAttachment {
view,
depth_slice: None,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
},
},
};
}

Expand All @@ -61,8 +68,15 @@ impl Multisampling {
SurfaceInfo {
format,
sample_count,
color_attachment: ms_view,
resolve_target: Some(view),
color_attachment: wgpu::RenderPassColorAttachment {
view: ms_view,
depth_slice: None,
resolve_target: Some(view),
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
},
},
}
}
}
4 changes: 2 additions & 2 deletions crates/yakui-app/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,9 @@ impl Graphics {
let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: surface.color_attachment,
view: surface.color_attachment.view,
depth_slice: None,
resolve_target: surface.resolve_target,
resolve_target: surface.color_attachment.resolve_target,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(bg),
store: wgpu::StoreOp::Store,
Expand Down
22 changes: 18 additions & 4 deletions crates/yakui-app/src/multisampling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,15 @@ impl Multisampling {
return SurfaceInfo {
format,
sample_count,
color_attachment: view,
resolve_target: None,
color_attachment: wgpu::RenderPassColorAttachment {
view,
depth_slice: None,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
},
},
};
}

Expand All @@ -61,8 +68,15 @@ impl Multisampling {
SurfaceInfo {
format,
sample_count,
color_attachment: ms_view,
resolve_target: Some(view),
color_attachment: wgpu::RenderPassColorAttachment {
view: ms_view,
depth_slice: None,
resolve_target: Some(view),
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
},
},
}
}
}
8 changes: 4 additions & 4 deletions crates/yakui-core/src/dom/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ use std::mem::replace;
use std::panic::Location;
use std::rc::Rc;

use anymap::AnyMap;
use thunderdome::Arena;

use crate::id::WidgetId;
use crate::input::InputState;
use crate::response::Response;
use crate::widget::{ErasedWidget, Widget};
use crate::Globals;

use self::dummy::DummyWidget;
use self::dynamic_scope::DynamicScope;
Expand All @@ -35,7 +35,7 @@ struct DomInner {
stack: RefCell<Vec<WidgetId>>,
removed_nodes: RefCell<Vec<WidgetId>>,
root: WidgetId,
globals: RefCell<AnyMap>,
globals: RefCell<Globals>,
pending_focus_request: RefCell<Option<WidgetId>>,
dynamic_scope: DynamicScope,
}
Expand Down Expand Up @@ -194,7 +194,7 @@ impl Dom {
F: FnOnce() -> T,
{
let mut globals = self.inner.globals.borrow_mut();
globals.entry::<T>().or_insert_with(init).clone()
globals.get(init)
}

/// Convenience method for calling [`Dom::begin_widget`] immediately
Expand Down Expand Up @@ -292,7 +292,7 @@ impl DomInner {
});

Self {
globals: RefCell::new(AnyMap::new()),
globals: RefCell::new(Globals::new()),
nodes: RefCell::new(nodes),
removed_nodes: RefCell::new(Vec::new()),
stack: RefCell::new(Vec::new()),
Expand Down
36 changes: 36 additions & 0 deletions crates/yakui-core/src/globals.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use anymap::AnyMap;

/// Struct to hold generic global states.
///
/// See: [`crate::dom::Dom`], [`crate::paint::PaintDom`]
#[derive(Debug)]
pub struct Globals {
inner: AnyMap,
}

impl Globals {
/// Initalizes a new global-state holder.
pub fn new() -> Self {
Self {
inner: AnyMap::new(),
}
}

/// Get a piece of global state mutably or initialize it with the given function.
pub fn get_mut<T, F>(&mut self, init: F) -> &mut T
where
T: 'static,
F: FnOnce() -> T,
{
self.inner.entry::<T>().or_insert_with(init)
}

/// Get a piece of global state and clone it or initialize it with the given function.
pub fn get<T, F>(&mut self, init: F) -> T
where
T: 'static + Clone,
F: FnOnce() -> T,
{
self.inner.entry::<T>().or_insert_with(init).clone()
}
}
9 changes: 1 addition & 8 deletions crates/yakui-core/src/input/input_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,6 @@ impl InputState {

/// Signal that the mouse has moved.
fn mouse_moved(&self, dom: &Dom, layout: &LayoutDom, pos: Option<Vec2>) {
let pos = pos.map(|pos| pos - layout.unscaled_viewport().pos());

{
let mut mouse = self.mouse.borrow_mut();
mouse.position = pos;
Expand Down Expand Up @@ -553,12 +551,7 @@ fn hit_test(_dom: &Dom, layout: &LayoutDom, coords: Vec2, output: &mut Vec<Widge
continue;
};

let mut rect = layout_node.rect;
let mut node = layout_node;
while let Some(parent) = node.clipped_by {
node = layout.get(parent).unwrap();
rect = rect.constrain(node.rect);
}
let rect = layout_node.clip.constrain(layout_node.rect);

if rect.contains_point(coords) {
output.push(id);
Expand Down
116 changes: 116 additions & 0 deletions crates/yakui-core/src/layout/clipping.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use glam::Vec2;

use crate::geometry::Rect;

#[derive(Debug, Clone, Copy)]
pub(crate) struct ClipResolutionArgs {
pub parent_clip: Rect,
pub parent_rect: Rect,
pub layout_rect: Rect,
pub viewport: Rect,
}

/// Defines abstract sources of [`Rect`] for clipping resolution.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AbstractClipRect {
/// Represents the parent widget's clipping rect.
ParentClip,
/// Represents the parent widget's layout rect.
ParentRect,
/// Represents the current widget's layout rect.
LayoutRect,
/// Represents the entire viewport rect.
Viewport,
/// The provided rect.
Value(Rect),
}

impl AbstractClipRect {
/// Turns the [`AbstractClipRect`] into a concrete [`Rect`].
pub(crate) fn to_rect(
self,
ClipResolutionArgs {
parent_clip,
parent_rect,
layout_rect,
viewport,
}: ClipResolutionArgs,
) -> Rect {
match self {
AbstractClipRect::ParentClip => parent_clip,
AbstractClipRect::ParentRect => parent_rect,
AbstractClipRect::LayoutRect => layout_rect,
AbstractClipRect::Viewport => viewport,
AbstractClipRect::Value(rect) => rect,
}
}
}

/// Defines the clipping logic of clipping resolution.
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum ClipLogic {
/// No clipping logic is performed. The widget will simply reuse the parent's clipping rect.
#[default]
Pass,
/// The clipping rect will be the [`constrained`][Rect::constrain] result of the two rects.
Constrain(AbstractClipRect, AbstractClipRect),
/// If the widget is out of the [`parent`][ClipLogic::Contain::parent]'s bounds, try to push it back in first.
/// Optionally add an offset to the widget first.
Contain {
/// The rect of the supposed widget in question.
it: AbstractClipRect,
/// The rect of the supposed widget's parent.
parent: AbstractClipRect,
/// An optional pixel offset to apply to [`it`][ClipLogic::Contain::it] before containing it in the [`parent`][ClipLogic::Contain::parent]'s bounds.
offset: Vec2,
},
/// The clipping rect will be overridden to be the provided rect.
Override(AbstractClipRect),
}

impl ClipLogic {
/// Resolves the offset for the *layout rect* with the provided [`ClipLogic`].
/// Should be calculated before doing clipping rect resolution, [`None`] means "just use the original layout rect".
pub(crate) fn resolve_offset(
self,
args @ ClipResolutionArgs { viewport, .. }: ClipResolutionArgs,
) -> Option<Vec2> {
match self {
ClipLogic::Contain { it, parent, offset } => {
let it = it.to_rect(args);
let it = Rect::from_pos_size(it.pos() + offset, it.size());

// implicitly also constrain to viewport
let parent = parent.to_rect(args).constrain(viewport);

let ratio = Vec2::max(it.size() / parent.size() - Vec2::ONE, Vec2::ONE);

let offset_min = Vec2::max(parent.pos() - it.pos(), Vec2::ZERO) * ratio;
let offset_max = Vec2::max(it.max() - parent.max(), Vec2::ZERO) * ratio;

Some(offset + (-offset_max + offset_min))
}
_ => None,
}
}

/// Resolves the *clipping rect* with the provided [`ClipLogic`].
pub(crate) fn resolve_clip(
self,
args @ ClipResolutionArgs { parent_clip, .. }: ClipResolutionArgs,
) -> Rect {
match self {
ClipLogic::Pass => parent_clip,
ClipLogic::Constrain(a, b)
| ClipLogic::Contain {
it: a, parent: b, ..
} => {
let a = a.to_rect(args);
let b = b.to_rect(args);

a.constrain(b)
}
ClipLogic::Override(rect) => rect.to_rect(args),
}
}
}
Loading
Loading