Skip to content

Commit

Permalink
feat: scroll
Browse files Browse the repository at this point in the history
  • Loading branch information
ten3roberts committed Mar 24, 2024
1 parent bbd1b1d commit f3d73f0
Show file tree
Hide file tree
Showing 17 changed files with 258 additions and 95 deletions.
1 change: 0 additions & 1 deletion examples/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,4 @@ fn app() -> impl Widget {
})),
))),
))
.contain_margins(true)
}
37 changes: 37 additions & 0 deletions examples/offset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use tracing_subscriber::{
prelude::__tracing_subscriber_SubscriberExt, registry, util::SubscriberInitExt, EnvFilter,
};
use tracing_tree::HierarchicalLayer;
use violet::core::{
style::{colors::EMERALD_500, secondary_background, spacing_medium, Background, SizeExt},
unit::Unit,
widget::{Positioned, Rectangle, Stack},
Widget,
};

pub fn main() -> anyhow::Result<()> {
registry()
.with(
HierarchicalLayer::default()
.with_deferred_spans(true)
.with_span_retrace(true)
.with_indent_lines(true),
)
.with(EnvFilter::from_default_env())
.init();

violet_wgpu::AppBuilder::new().run(app())
}

fn app() -> impl Widget {
Stack::new(
Positioned::new(
Rectangle::new(EMERALD_500)
.with_min_size(Unit::px2(100.0, 100.0))
.with_margin(spacing_medium()),
)
.with_offset(Unit::px2(10.0, 10.0)),
)
.with_padding(spacing_medium())
.with_background(Background::new(secondary_background()))
}
62 changes: 62 additions & 0 deletions examples/scroll.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use flax::{components::name, FetchExt, Query};
use futures::StreamExt;
use futures_signals::signal::Mutable;
use glam::{vec2, Vec2};
use itertools::Itertools;
use palette::{FromColor, Hsva, IntoColor, Oklch, Oklcha, Srgba};
use std::time::Duration;
use tracing_subscriber::{
prelude::__tracing_subscriber_SubscriberExt, registry, util::SubscriberInitExt, EnvFilter,
};
use tracing_tree::HierarchicalLayer;
use violet::core::{
components::{self, rect, size, text},
layout::{Alignment, Direction},
style::StyleExt,
text::{FontFamily, Style, TextSegment, Weight, Wrap},
time::interval,
unit::Unit,
widget::{Button, Image, List, Rectangle, Stack, Text, WidgetExt},
Scope, StreamEffect, Widget,
};
use violet_core::{
state::{State, StateStream},
style::{
colors::{AMBER_500, EMERALD_500, TEAL_500},
danger_background, danger_item, primary_background, secondary_background, spacing_medium,
spacing_small, Background, SizeExt, ValueOrRef,
},
widget::{
card, col, label, pill, row, ContainerStyle, SliderWithLabel, StreamWidget, TextInput,
},
};

pub fn main() -> anyhow::Result<()> {
registry()
.with(
HierarchicalLayer::default()
.with_deferred_spans(true)
.with_span_retrace(true)
.with_indent_lines(true),
)
.with(EnvFilter::from_default_env())
.init();

violet_wgpu::AppBuilder::new().run(app())
}

fn app() -> impl Widget {
col((0..32)
.map(|v| {
Rectangle::new(Srgba::from_color(Oklcha::new(
0.5,
0.37,
v as f32 * 5.0,
1.0,
)))
.with_margin(spacing_small())
.with_min_size(Unit::px2(100.0, 50.0))
.with_maximize(Vec2::X)
})
.collect_vec())
}
18 changes: 11 additions & 7 deletions violet-core/src/components.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::time::Duration;

use flax::{component, Debuggable, Entity, EntityRef, Exclusive};
use glam::Vec2;
use glam::{Mat4, Vec2};
use image::DynamicImage;
use palette::Srgba;

Expand All @@ -21,19 +21,23 @@ component! {

/// Defines the outer bounds of a widget relative to its position
pub rect: Rect => [ Debuggable ],
pub screen_rect: Rect => [ Debuggable ],

/// Position relative to parent
/// Position relative to parent for layout position.
pub local_position: Vec2 => [ Debuggable ],

/// Specifies in screen space where the widget rect upper left corner is
pub screen_position: Vec2 => [ Debuggable ],

pub rotation: f32 => [ Debuggable ],

/// Offset the widget from its original position
/// Offset the widget from its original position.
///
/// This influences the layout bounds and the final position of the widget, and will move other
/// widgets around in flow layouts.
pub offset: Unit<Vec2> => [ Debuggable ],

/// Optional transform of the widget. Applied after layout
pub transform: Mat4,

pub screen_transform: Mat4,

/// Explicit widget size. This will override the intrinsic size of the widget.
///
/// The final size may be smaller if there is not enough space.
Expand Down
33 changes: 23 additions & 10 deletions violet-core/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use flax::{
component, components::child_of, entity_ids, fetch::Satisfied, filter::All, Component, Entity,
EntityIds, EntityRef, Fetch, FetchExt, Query, Topo, World,
};
use glam::Vec2;
use glam::{Mat4, Vec2, Vec3Swizzles};

/// NOTE: maybe redefine these types ourselves
pub use winit::{event, keyboard};
Expand All @@ -12,7 +12,7 @@ use winit::{
};

use crate::{
components::{rect, screen_position, screen_rect},
components::{rect, screen_transform},
scope::ScopeRef,
Frame, Rect,
};
Expand All @@ -23,7 +23,7 @@ pub struct Input {}
struct IntersectQuery {
id: EntityIds,
rect: Component<Rect>,
screen_pos: Component<Vec2>,
screen_transform: Component<Mat4>,
sticky: Satisfied<Component<()>>,
focusable: Component<()>,
}
Expand All @@ -33,7 +33,7 @@ impl IntersectQuery {
Self {
id: entity_ids(),
rect: rect(),
screen_pos: screen_position(),
screen_transform: screen_transform(),
sticky: focus_sticky().satisfied(),
focusable: focusable(),
}
Expand Down Expand Up @@ -71,9 +71,14 @@ impl InputState {
.borrow(frame.world())
.iter()
.filter_map(|item| {
let local_pos = cursor_pos - *item.screen_pos;
let local_pos = item
.screen_transform
.inverse()
.transform_point3(cursor_pos.extend(0.0))
.xy();

if item.rect.contains_point(local_pos) {
Some((item.id, (*item.screen_pos + item.rect.min)))
Some((item.id, local_pos))
} else {
None
}
Expand All @@ -94,13 +99,13 @@ impl InputState {

// Send the event to the intersected entity

if let Some((id, origin)) = intersect {
if let Some((id, local_pos)) = intersect {
let entity = frame.world().entity(id).unwrap();

let cursor = CursorMove {
modifiers: self.modifiers,
absolute_pos: self.pos,
local_pos: self.pos - origin,
local_pos,
};
if let Ok(mut on_input) = entity.get_mut(on_mouse_input()) {
let s = ScopeRef::new(frame, entity);
Expand All @@ -121,15 +126,15 @@ impl InputState {
self.pos = pos;

if let Some(entity) = &self.focused(&frame.world) {
let screen_rect = entity.get_copy(screen_rect()).unwrap_or_default();
let transform = entity.get_copy(screen_transform()).unwrap_or_default();
if let Ok(mut on_input) = entity.get_mut(on_cursor_move()) {
let s = ScopeRef::new(frame, *entity);
on_input(
&s,
CursorMove {
modifiers: self.modifiers,
absolute_pos: pos,
local_pos: pos - screen_rect.min,
local_pos: transform.inverse().transform_point3(pos.extend(0.0)).xy(),
},
);
}
Expand Down Expand Up @@ -206,6 +211,13 @@ pub struct CursorMove {
pub local_pos: Vec2,
}

#[derive(Debug, Clone)]
pub struct Scroll {
pub scroll_x: f32,
pub scroll_y: f32,
pub modifiers: ModifiersState,
}

pub struct KeyboardInput {
pub modifiers: ModifiersState,

Expand All @@ -221,4 +233,5 @@ component! {
pub on_cursor_move: InputEventHandler<CursorMove>,
pub on_mouse_input: InputEventHandler<MouseInput>,
pub on_keyboard_input: InputEventHandler<KeyboardInput>,
pub on_scroll: InputEventHandler<Scroll>,
}
2 changes: 1 addition & 1 deletion violet-core/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ pub(crate) fn apply_layout(

if let Some(value) = &cache.layout {
if validate_cached_layout(value, limits, content_area, cache.hints.relative_size) {
tracing::debug!(%entity, %value.value.rect, %value.value.can_grow, "found valid cached layout");
tracing::trace!(%entity, %value.value.rect, %value.value.can_grow, "found valid cached layout");

return value.value;
}
Expand Down
3 changes: 1 addition & 2 deletions violet-core/src/layout/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ impl StackLayout {
let mut can_grow = BVec2::FALSE;

let offset = resolve_pos(entity, content_area.size(), size);

for (entity, block) in blocks {
let block_size = block.rect.size();
let offset = content_area.min
Expand All @@ -144,8 +145,6 @@ impl StackLayout {
self.vertical_alignment.align_offset(size.y, block_size.y),
);

tracing::debug!(?offset, %entity);

aligned_bounds = aligned_bounds.merge(&StackableBounds::new(
block.rect.translate(offset),
block.margin,
Expand Down
2 changes: 1 addition & 1 deletion violet-core/src/style/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ pub fn setup_stylesheet() -> EntityBuilder {
.set(danger_item(), REDWOOD_400)
.set(interactive_active(), EMERALD_500)
.set(interactive_passive(), ZINC_800)
.set(interactive_hover(), EMERALD_800)
.set(interactive_hover(), EMERALD_400)
.set(interactive_pressed(), EMERALD_500)
.set(interactive_inactive(), ZINC_700)
// spacing
Expand Down
30 changes: 12 additions & 18 deletions violet-core/src/systems.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{
collections::HashSet,
sync::{Arc, Weak},
thread::scope,
};

use atomic_refcell::AtomicRefCell;
Expand All @@ -12,22 +11,20 @@ use flax::{
entity_ids,
events::{EventData, EventSubscriber},
filter::Or,
query::TopoBorrow,
BoxedSystem, CommandBuffer, Dfs, DfsBorrow, Entity, EntityBuilder, Fetch, FetchExt, FetchItem,
Query, QueryBorrow, System, Topo, World,
Query, QueryBorrow, System, World,
};
use glam::Vec2;
use glam::{Mat4, Vec2};

use crate::{
components::{
self, children, layout_bounds, local_position, rect, screen_position, screen_rect, text,
self, children, layout_bounds, local_position, rect, screen_transform, text, transform,
},
layout::{
apply_layout,
cache::{invalidate_widget, layout_cache, LayoutCache, LayoutUpdate},
LayoutLimits,
},
Rect,
};

pub fn hydrate_text() -> BoxedSystem {
Expand All @@ -46,9 +43,9 @@ pub fn hydrate_text() -> BoxedSystem {
pub fn widget_template(entity: &mut EntityBuilder, name: String) {
entity
.set(flax::components::name(), name)
.set_default(screen_position())
.set_default(screen_transform())
.set_default(transform())
.set_default(local_position())
.set_default(screen_rect())
.set_default(rect());
}

Expand Down Expand Up @@ -187,22 +184,19 @@ pub fn transform_system() -> BoxedSystem {
System::builder()
.with_query(
Query::new((
screen_position().as_mut(),
screen_rect().as_mut(),
rect(),
screen_transform().as_mut(),
local_position(),
transform().opt_or_default(),
))
.with_strategy(Dfs::new(child_of)),
)
.build(|mut query: DfsBorrow<_>| {
query.traverse(
&Vec2::ZERO,
|(pos, screen_rect, rect, local_pos): (&mut Vec2, &mut Rect, &Rect, &Vec2),
_,
parent_pos| {
*pos = *parent_pos + *local_pos;
*screen_rect = rect.translate(*pos);
*pos
&Mat4::IDENTITY,
|(screen_trans, local_pos, trans): (&mut Mat4, &Vec2, &Mat4), _, parent| {
*screen_trans =
*parent * *trans * Mat4::from_translation(local_pos.extend(0.0));
*screen_trans
},
);
})
Expand Down
Loading

0 comments on commit f3d73f0

Please sign in to comment.