diff --git a/CHANGELOG.md b/CHANGELOG.md index 04ed456e..5e1ae8d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,150 @@ # Changelog + + ## Unreleased -### Features/Changes -- Change slider widget input to a percent value and add docs for it [#276](https://github.com/lapce/floem/pull/276) + +### Features +- Add `update_state_deferred` and simplify `update_state` [#277](https://github.com/lapce/floem/pull/277) - Add flight booker example from 7gui [#280](https://github.com/lapce/floem/pull/280) - Add timer example from 7gui [#284](https://github.com/lapce/floem/pull/284) -- Add more grid properties [#285](https://github.com/lapce/floem/pull/285) -- Add `value_container` for provide `on_update` to checkbox [#290](https://github.com/lapce/floem/pull/290) -- Refactor radio button to use value container [#292](https://github.com/lapce/floem/pull/292) +- Added grid function to align with flex function [#291](https://github.com/lapce/floem/pull/291) +- Add dropdown widget [#265](https://github.com/lapce/floem/pull/265) +- Stack event handlers [#304](https://github.com/lapce/floem/pull/304) +- Add stacking classes [#305](https://github.com/lapce/floem/pull/305) +- **Add the Floem editor** [#296](https://github.com/lapce/floem/pull/296) +- Allow toggling editor gutter [#309](https://github.com/lapce/floem/pull/309) +- Add new funcs for RwSignal and Trigger [#312](https://github.com/lapce/floem/pull/312) +- Add pause and resume for animations. Add progress bar in anim examples [#327](https://github.com/lapce/floem/pull/327) +- Added simple syntax highlighting example [#342](https://github.com/lapce/floem/pull/342) +- Add recapture button to inspector [#343](https://github.com/lapce/floem/pull/343) +- Add IME phantom text properly [#373](https://github.com/lapce/floem/pull/373) +- **Add custom style methods for widgets** [#377](https://github.com/lapce/floem/pull/377) +- Add method to stack/list to add class [#378](https://github.com/lapce/floem/pull/378) +- Add start/stop for animation. Dont advance animation if paused/stopped [#386](https://github.com/lapce/floem/pull/386) +- **Add custom debug name** [#388](https://github.com/lapce/floem/pull/388) +- Remove update size [#427](https://github.com/lapce/floem/pull/427) +- Add FreeBSD support [#443](https://github.com/lapce/floem/pull/443) +- Expose setting a Window Icon [#453](https://github.com/lapce/floem/pull/453) +- Allow views to detect if they are being painted for drag and drop [#458](https://github.com/lapce/floem/pull/458) +- Support undecorated windows in `WindowConfig` [#456](https://github.com/lapce/floem/pull/456) +- Add the ability to configure mac-os specific properties to WindowConfig [#457](https://github.com/lapce/floem/pull/457) +- Add the ability for a view to resign from active state [#481](https://github.com/lapce/floem/pull/481) +- Add signal from tokio channel behind flag [#483](https://github.com/lapce/floem/pull/483) +- Add label selection [#488](https://github.com/lapce/floem/pull/488) +- inspector: Add a search box and select up and down [#510](https://github.com/lapce/floem/pull/510) +- inspector: After clicking on the image, you can use the up and down a… [#511](https://github.com/lapce/floem/pull/511) +- **support WindowEvent::DroppedFile** [#524](https://github.com/lapce/floem/pull/524) +- Add custom style trait [#535](https://github.com/lapce/floem/pull/535) +- Add conditional classes and debug names [#536](https://github.com/lapce/floem/pull/536) +- Add create_signal_from_stream function [#545](https://github.com/lapce/floem/pull/545) +- Add support for gradients/brush as background/border [#541](https://github.com/lapce/floem/pull/541) +- add custom style for scroll [#551](https://github.com/lapce/floem/pull/551) +- Add SignalGet SignalWith SignalUpdate traits [#558](https://github.com/lapce/floem/pull/558) +- **Add initial wasm support** [#527](https://github.com/lapce/floem/pull/527) +- **Keyframe Animations** [#563](https://github.com/lapce/floem/pull/563) +- View transitions [#565](https://github.com/lapce/floem/pull/565) +- **Add rich text builder** [#567](https://github.com/lapce/floem/pull/567) +- **add spring animations** [#575](https://github.com/lapce/floem/pull/575) +- allow font embolden to be customized [#579](https://github.com/lapce/floem/pull/579) +- Add transform and scale properties [#589](https://github.com/lapce/floem/pull/589) +- add mac hide buttons config [#595](https://github.com/lapce/floem/pull/595) +- allow scroll to not clip [#596](https://github.com/lapce/floem/pull/596) +- add dyn view macro [#598](https://github.com/lapce/floem/pull/598) +- toggle button new function [#602](https://github.com/lapce/floem/pull/602) +- Add scroll extension [#604](https://github.com/lapce/floem/pull/604) +- add debounce action [#627](https://github.com/lapce/floem/pull/627) +- add scroll to view on gain focus [#629](https://github.com/lapce/floem/pull/629) +- add clear app focus message and command [#632](https://github.com/lapce/floem/pull/632) +- Add Vello as a renderer backend [#635](https://github.com/lapce/floem/pull/635) +- Allow comments in style macros [#636](https://github.com/lapce/floem/pull/636) +- add text input triple click [#637](https://github.com/lapce/floem/pull/637) +- add: remove keyboard navigable [#638](https://github.com/lapce/floem/pull/638) +- add undecorated shadow option for windows [#643](https://github.com/lapce/floem/pull/643) +- add prelude [#641](https://github.com/lapce/floem/pull/641) +- add: disable default view events [#646](https://github.com/lapce/floem/pull/646) +- Add To-Do app example [#658](https://github.com/lapce/floem/pull/658) +- add text input scroll when mouse goes out of bounds [#659](https://github.com/lapce/floem/pull/659) +- add event transforms and the rotation transform [#664](https://github.com/lapce/floem/pull/664) + +## Changes +- Split the `View` trait into `View` and `Widget` [#288](https://github.com/lapce/floem/pull/288) +- Make `virtual_list` take a view [#333](https://github.com/lapce/floem/pull/333) +- automatically propagate pointer events at scroll end [#380](https://github.com/lapce/floem/pull/380) +- treat altgr as Modifier [#408](https://github.com/lapce/floem/pull/408) +- **ECS - make floem directly own all views** [#432](https://github.com/lapce/floem/pull/432) +- make default gap style one arg [#477](https://github.com/lapce/floem/pull/477) +- rename view style method to style_pass. [#478](https://github.com/lapce/floem/pull/478) +- Rename gap to row/col to more closely match web [#479](https://github.com/lapce/floem/pull/479) +- Make apply classes from context public [#512](https://github.com/lapce/floem/pull/512) +- allow font to be specified with px [#583](https://github.com/lapce/floem/pull/583) +- switch svg and button default to static [#584](https://github.com/lapce/floem/pull/584) +- Rename Tabs to Tab for clarity in the `tab` argument [#593](https://github.com/lapce/floem/pull/593) +- Make add and remove class on ViewId public [#601](https://github.com/lapce/floem/pull/601) +- rename window scale action to be consistent [#639](https://github.com/lapce/floem/pull/639) +- change on_key_* fns to provide acess to the modifiers [#642](https://github.com/lapce/floem/pull/642) +- event pass through [#667](https://github.com/lapce/floem/pull/667) ### Bug Fixes -- Fix a panic when multiple views have context menus [#275](https://github.com/lapce/floem/pull/275) -- Fix slider and add example [#279](https://github.com/lapce/floem/pull/279) +- Fixed up file dialog [#326](https://github.com/lapce/floem/pull/326) +- Stop PointerMove events going through menu [#355](https://github.com/lapce/floem/pull/355) +- Unfilled circle in vger [#372](https://github.com/lapce/floem/pull/372) +- Fix tooltip behaviour [#414](https://github.com/lapce/floem/pull/414) +- Don't crash when stroking straight lines in bezier path [#450](https://github.com/lapce/floem/pull/450) +- The most minimal fix possible for inter-window messages not being processed [#473](https://github.com/lapce/floem/pull/473) +- send theme updates [#476](https://github.com/lapce/floem/pull/476) +- fix: `checkbox` doesn't fire `.on_click_stop` in example [#516](https://github.com/lapce/floem/pull/516) +- Fix non-standard text input behavior in Windows [#544](https://github.com/lapce/floem/pull/544) +- Fix text input cursor jumping to the end [#548](https://github.com/lapce/floem/pull/548) +- fix transition layout [#570](https://github.com/lapce/floem/pull/570) +- fix scale, rename transform to translate [#590](https://github.com/lapce/floem/pull/590) +- fix clip scale [#606](https://github.com/lapce/floem/pull/606) +- Fix scroll clip to not include padding [#625](https://github.com/lapce/floem/pull/625) +- fix panic on tab nav after deleted views [#626](https://github.com/lapce/floem/pull/626) +- fix text input event propagation [#628](https://github.com/lapce/floem/pull/628) +- fix scroll bar flashing [#630](https://github.com/lapce/floem/pull/630) +- pull box shadow from extractor [#631](https://github.com/lapce/floem/pull/631) +- fixes to button transitions in default theme [#647](https://github.com/lapce/floem/pull/647) +- dont send pointer events to overlap siblings [#648](https://github.com/lapce/floem/pull/648) +- Reduce typo count [#660](https://github.com/lapce/floem/pull/660) +- fix view transition example [#662](https://github.com/lapce/floem/pull/662) ### Internal Changes -- Add `update_state_deferred` and `simplify update_state` [#277](https://github.com/lapce/floem/pull/277) +- Refactor radio button to use value container [#292](https://github.com/lapce/floem/pull/292) +- build(deps): update rfd from 0.11.4 to 0.14.0 [#345](https://github.com/lapce/floem/pull/345) +- Continue text editor pointer events [#348](https://github.com/lapce/floem/pull/348) +- Implement line-ending recognition and normalization [#353](https://github.com/lapce/floem/pull/353) +- Move Gutter Layout into Gutter Widget [#352](https://github.com/lapce/floem/pull/352) +- wrap dropdown list in a scroll view [#383](https://github.com/lapce/floem/pull/383) +- Move some editor styling to floem style props [#398](https://github.com/lapce/floem/pull/398) +- Expose the scale value from Renderer. [#444](https://github.com/lapce/floem/pull/444) +- add keyboard nav to editor view [#446](https://github.com/lapce/floem/pull/446) +- Allow types generated with `prop_extractor!` to implement `Hash`, `PartialEq`, and `Eq` trivially [#447](https://github.com/lapce/floem/pull/447) +- Expose `window_origin` from `ComputeLayoutCx` [#459](https://github.com/lapce/floem/pull/459) +- Expose view and taffy node from ViewId [#454](https://github.com/lapce/floem/pull/454) +- deps: kurbo is used via peniko. [#461](https://github.com/lapce/floem/pull/461) +- Move Selectable to the default style [#495](https://github.com/lapce/floem/pull/495) +- Editor: Scroll top, middle, and bottom [#497](https://github.com/lapce/floem/pull/497) +- improve dropdown style context [#513](https://github.com/lapce/floem/pull/513) +- docs: add examples and index page [#537](https://github.com/lapce/floem/pull/537) +- Switch to upstream cosmic-text [#539](https://github.com/lapce/floem/pull/539) +- Remove the use of `LazyLock` in places where it's not necessary [#546](https://github.com/lapce/floem/pull/546) +- Use a loop instead of recursion when handling CR to avoid stack overflow [#552](https://github.com/lapce/floem/pull/552) +- create SignalTrack trait [#562](https://github.com/lapce/floem/pull/562) +- Make sorting keymaps possible by deriving Ord. [#566](https://github.com/lapce/floem/pull/566) +- Enhance the functionality of the clipboard. [#580](https://github.com/lapce/floem/pull/580) +- tooltip improvements [#597](https://github.com/lapce/floem/pull/597) +- Add Uninitialized variant to Renderer [#608](https://github.com/lapce/floem/pull/608) +- Project docs [#614](https://github.com/lapce/floem/pull/614) +- Add docs to ViewID and methods [#615](https://github.com/lapce/floem/pull/615) +- Simplify dropdown, add constructors, add docs [#618](https://github.com/lapce/floem/pull/618) +- use f for keyframe convention [#652](https://github.com/lapce/floem/pull/652) +- document items in view [#654](https://github.com/lapce/floem/pull/654) +- document views mod [#655](https://github.com/lapce/floem/pull/655) +- document scroll [#656](https://github.com/lapce/floem/pull/656) +- document decorators [#657](https://github.com/lapce/floem/pull/657) +- `floem_vello_renderer`: Don't depend on `resvg` [#661](https://github.com/lapce/floem/pull/661) +- animations improvements [#663](https://github.com/lapce/floem/pull/663) + +## [0.1.1] diff --git a/examples/animations/Cargo.toml b/examples/animations/Cargo.toml deleted file mode 100644 index 9992c3ad..00000000 --- a/examples/animations/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "animations" -version = "0.1.0" -edition = "2021" - -[dependencies] -im.workspace = true -floem = { path = "../.." } diff --git a/examples/animations/README.md b/examples/animations/README.md deleted file mode 100644 index 59ef5ad6..00000000 --- a/examples/animations/README.md +++ /dev/null @@ -1,31 +0,0 @@ -> [!WARNING] -> **Work in progress, which is subject to frequent change.** - If you plan to add changes, please make sure you reach out in our discord first. - - The end-goal is to support reactive animations, similar to Swift UI(including spring animations). - The API we are currently aiming for looks something like this: - ```rust - let (is_hovered, set_is_hovered) = create_signal(false); - let (scroll_offset_pct, set_scroll_offset_pct) = create_signal(0.); - - scroll({ - button() - .style(|s| { - s.width(move || {50.0}) - }) - .animation(|s| { - s.width(300) - // we get animation on scroll "for free", since everything is integrated with the reactive system - .opacity(move || scroll_offset_pct) - .scale(move || is_hovered.get() {1.2} else {1.0} ) - .easing_fn(EasingFn::Cubic) - .ease_in_out() - .duration(Duration::from_secs(1)) - }) - }.on_scroll(move |scroll| { - let offset_pct = ......snip........ - set_scroll_offset_pct.update(|value| *value = offset_pct); - true - }) - ) - ``` diff --git a/examples/animations/src/main.rs b/examples/animations/src/main.rs deleted file mode 100644 index a0ac5f28..00000000 --- a/examples/animations/src/main.rs +++ /dev/null @@ -1,73 +0,0 @@ -use floem::{ - animate::Animation, - event::EventListener as EL, - peniko::Color, - reactive::{RwSignal, SignalGet, Trigger}, - unit::DurationUnitExt, - views::{empty, h_stack, Decorators}, - IntoView, -}; - -fn app_view() -> impl IntoView { - let animation = RwSignal::new( - Animation::new() - .duration(5.seconds()) - .keyframe(0, |f| f.computed_style()) - .keyframe(50, |f| { - f.style(|s| s.background(Color::BLACK).size(30, 30)) - .ease_in() - }) - .keyframe(100, |f| { - f.style(|s| s.background(Color::AQUAMARINE).size(10, 300)) - .ease_out() - }) - .repeat(true) - .auto_reverse(true), - ); - - let pause = Trigger::new(); - let resume = Trigger::new(); - - h_stack(( - empty() - .style(|s| s.background(Color::RED).size(500, 100)) - .animation(move |_| animation.get().duration(10.seconds())), - empty() - .style(|s| { - s.background(Color::BLUE) - .size(50, 100) - .border(5.) - .border_color(Color::GREEN) - }) - .animation(move |_| animation.get()) - .animation(move |a| { - a.keyframe(0, |f| f.computed_style()) - .keyframe(100, |f| { - f.style(|s| s.border(5.).border_color(Color::PURPLE)) - }) - .duration(5.seconds()) - .repeat(true) - .auto_reverse(true) - }), - empty() - .style(|s| s.background(Color::GREEN).size(100, 300)) - .animation(move |_| { - animation - .get() - .pause(move || pause.track()) - .resume(move || resume.track()) - .delay(3.seconds()) - }) - .on_event_stop(EL::PointerEnter, move |_| { - pause.notify(); - }) - .on_event_stop(EL::PointerLeave, move |_| { - resume.notify(); - }), - )) - .style(|s| s.size_full().gap(10).items_center().justify_center()) -} - -fn main() { - floem::launch(app_view); -} diff --git a/examples/draggable/Cargo.toml b/examples/draggable/Cargo.toml deleted file mode 100644 index 4cd7ca18..00000000 --- a/examples/draggable/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "draggable" -version = "0.1.0" -edition = "2021" - -[dependencies] -im.workspace = true -floem = { path = "../.." } diff --git a/examples/draggable/src/main.rs b/examples/draggable/src/main.rs deleted file mode 100644 index 9dfb168c..00000000 --- a/examples/draggable/src/main.rs +++ /dev/null @@ -1,109 +0,0 @@ -use floem::{ - keyboard::{Key, NamedKey}, - peniko::Color, - reactive::{create_rw_signal, RwSignal, SignalGet, SignalUpdate}, - style::CursorStyle, - views::{dyn_stack, label, Decorators}, - IntoView, View, -}; - -fn sortable_item( - name: &str, - sortable_items: RwSignal>, - dragger_id: RwSignal, - item_id: usize, -) -> impl IntoView { - let name = String::from(name); - let colors = [ - Color::WHITE, - Color::BEIGE, - Color::REBECCA_PURPLE, - Color::TEAL, - Color::PALE_GREEN, - Color::YELLOW, - Color::DODGER_BLUE, - Color::KHAKI, - Color::WHEAT, - Color::DARK_SALMON, - Color::HOT_PINK, - ]; - - ( - label(move || format!("Selectable item {name}")) - .style(|s| s.padding(5).width_full()) - .on_event_stop( - floem::event::EventListener::PointerDown, - |_| { /* Disable dragging for this view */ }, - ), - label(|| "drag me").style(|s| { - s.selectable(false) - .padding(2) - .cursor(CursorStyle::RowResize) - }), - ) - .draggable() - .on_event(floem::event::EventListener::DragStart, move |_| { - dragger_id.set(item_id); - floem::event::EventPropagation::Continue - }) - .on_event(floem::event::EventListener::DragOver, move |_| { - if dragger_id.get_untracked() != item_id { - let dragger_pos = sortable_items - .get() - .iter() - .position(|id| *id == dragger_id.get_untracked()) - .unwrap(); - let hover_pos = sortable_items - .get() - .iter() - .position(|id| *id == item_id) - .unwrap(); - - sortable_items.update(|items| { - items.remove(dragger_pos); - items.insert(hover_pos, dragger_id.get_untracked()); - }); - } - floem::event::EventPropagation::Continue - }) - .dragging_style(|s| { - s.box_shadow_blur(3) - .box_shadow_color(Color::rgb8(100, 100, 100)) - .box_shadow_spread(2) - }) - .style(move |s| { - s.background(colors[item_id]) - .selectable(false) - .row_gap(5) - .items_center() - .border(2) - .border_color(Color::RED) - }) -} - -fn app_view() -> impl IntoView { - let items = [ - "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", - ]; - let sortable_items = create_rw_signal((0..items.len()).collect::>()); - let dragger_id = create_rw_signal(0); - - let view = dyn_stack( - move || sortable_items.get(), - move |item_id| *item_id, - move |item_id| sortable_item(items[item_id], sortable_items, dragger_id, item_id), - ) - .style(|s| s.flex_col().column_gap(5).padding(10)) - .into_view(); - - let id = view.id(); - view.on_key_up( - Key::Named(NamedKey::F11), - |m| m.is_empty(), - move |_| id.inspect(), - ) -} - -fn main() { - floem::launch(app_view); -} diff --git a/examples/dropped_file/Cargo.toml b/examples/dropped_file/Cargo.toml deleted file mode 100644 index 3f6c500b..00000000 --- a/examples/dropped_file/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "dropped_file" -version = "0.1.0" -edition = "2021" - -[dependencies] -floem = { path = "../.." } diff --git a/examples/dropped_file/src/main.rs b/examples/dropped_file/src/main.rs deleted file mode 100644 index d4036725..00000000 --- a/examples/dropped_file/src/main.rs +++ /dev/null @@ -1,33 +0,0 @@ -use floem::{ - event::EventListener, - keyboard::{Key, NamedKey}, - unit::UnitExt, - views::{dyn_view, Decorators}, - IntoView, View, -}; - -fn app_view() -> impl IntoView { - let view = dyn_view(move || "dropped file".to_string()).style(|s| { - s.size(100.pct(), 100.pct()) - .flex_col() - .items_center() - .justify_center() - }); - - let id = view.id(); - view.on_key_up( - Key::Named(NamedKey::F11), - |m| m.is_empty(), - move |_| id.inspect(), - ) - .on_event_stop(EventListener::PointerMove, |x| { - println!("PointerMove {:?}", x.point()); - }) - .on_event_stop(EventListener::DroppedFile, |x| { - println!("DroppedFile {:?}", x); - }) -} - -fn main() { - floem::launch(app_view); -} diff --git a/src/context.rs b/src/context.rs index dee9b813..6180c60a 100644 --- a/src/context.rs +++ b/src/context.rs @@ -452,6 +452,10 @@ impl<'a> EventCx<'a> { return true; }; + if !id.state().borrow().pointer_events { + return false; + } + let layout_rect = id.layout_rect(); let Some(layout) = id.get_layout() else { return false; diff --git a/src/id.rs b/src/id.rs index 50962470..48d64d9e 100644 --- a/src/id.rs +++ b/src/id.rs @@ -534,6 +534,11 @@ impl ViewId { .remove(&event); } + /// Set if the view should process pointer events + pub fn pointer_events(&self, pointer_events: bool) { + self.state().borrow_mut().pointer_events = pointer_events; + } + /// Mark this view as a view that can be dragged /// /// You can customize the apearance of a view while dragging in the style diff --git a/src/inspector.rs b/src/inspector.rs index 68253688..cf7ab1dc 100644 --- a/src/inspector.rs +++ b/src/inspector.rs @@ -797,129 +797,140 @@ fn capture_view( ) }) .unwrap_or_default(); + let size = capture_.window_size; let contain_ids = create_rw_signal((0, Vec::::new())); - let image = img_dynamic(move || window.clone().unwrap()) - .style(move |s| { - s.margin(5.0) - .border(1.) - .border_color(Color::BLACK.multiply_alpha(0.5)) - .width(image_width + 2.0) - .height(image_height + 2.0) - .margin_bottom(21.0) - .margin_right(21.0) - }) - .keyboard_navigable() - .on_event_stop(EventListener::KeyUp, { - move |event: &Event| { - if let Event::KeyUp(key) = event { - match key.key.logical_key { - keyboard::Key::Named(NamedKey::ArrowUp) => { - let id = contain_ids.try_update(|(match_index, ids)| { - if !ids.is_empty() { - if *match_index == 0 { - *match_index = ids.len() - 1; - } else { - *match_index -= 1; - } + let image = if let Some(window) = window { + img_dynamic(move || window.clone()).into_any() + } else { + empty() + .style(move |s| s.min_width(size.width).min_height(size.height)) + .into_any() + } + .style(move |s| { + s.margin(5.0) + .border(1.) + .border_color(Color::BLACK.multiply_alpha(0.5)) + .width(image_width + 2.0) + .height(image_height + 2.0) + .margin_bottom(21.0) + .margin_right(21.0) + }) + .keyboard_navigable() + .on_event_stop(EventListener::KeyUp, { + move |event: &Event| { + if let Event::KeyUp(key) = event { + match key.key.logical_key { + keyboard::Key::Named(NamedKey::ArrowUp) => { + let id = contain_ids.try_update(|(match_index, ids)| { + if !ids.is_empty() { + if *match_index == 0 { + *match_index = ids.len() - 1; + } else { + *match_index -= 1; } - ids.get(*match_index).copied() - }); - if let Some(Some(id)) = id { - update_select_view_id(id, &capture_view, false); } + ids.get(*match_index).copied() + }); + if let Some(Some(id)) = id { + update_select_view_id(id, &capture_view, false); } - keyboard::Key::Named(NamedKey::ArrowDown) => { - let id = contain_ids.try_update(|(match_index, ids)| { - if !ids.is_empty() { - *match_index = (*match_index + 1) % ids.len(); - } - ids.get(*match_index).copied() - }); - if let Some(Some(id)) = id { - update_select_view_id(id, &capture_view, false); + } + keyboard::Key::Named(NamedKey::ArrowDown) => { + let id = contain_ids.try_update(|(match_index, ids)| { + if !ids.is_empty() { + *match_index = (*match_index + 1) % ids.len(); } + ids.get(*match_index).copied() + }); + if let Some(Some(id)) = id { + update_select_view_id(id, &capture_view, false); } - _ => {} } + _ => {} } } - }) - .on_event_stop(EventListener::PointerUp, { - let capture_ = capture_.clone(); - move |event: &Event| { - if let Event::PointerUp(e) = event { - let find_ids = capture_.root.find_all_by_pos(e.pos); - if !find_ids.is_empty() { - let first = contain_ids.try_update(|(index, ids)| { - *index = 0; - let _ = std::mem::replace(ids, find_ids); - ids.first().copied() - }); - if let Some(Some(id)) = first { - update_select_view_id(id, &capture_view, false); - } + } + }) + .on_event_stop(EventListener::PointerUp, { + let capture_ = capture_.clone(); + move |event: &Event| { + if let Event::PointerUp(e) = event { + let find_ids = capture_.root.find_all_by_pos(e.pos); + if !find_ids.is_empty() { + let first = contain_ids.try_update(|(index, ids)| { + *index = 0; + let _ = std::mem::replace(ids, find_ids); + ids.first().copied() + }); + if let Some(Some(id)) = first { + update_select_view_id(id, &capture_view, false); } } } - }) - .on_event_stop(EventListener::PointerMove, { - move |event: &Event| { - if let Event::PointerMove(e) = event { - if let Some(view) = capture_.root.find_by_pos(e.pos) { - if capture_view.highlighted.get() != Some(view.id) { - capture_view.highlighted.set(Some(view.id)); - } - } else { - capture_view.highlighted.set(None); + } + }) + .on_event_stop(EventListener::PointerMove, { + move |event: &Event| { + if let Event::PointerMove(e) = event { + if let Some(view) = capture_.root.find_by_pos(e.pos) { + if capture_view.highlighted.get() != Some(view.id) { + capture_view.highlighted.set(Some(view.id)); } + } else { + capture_view.highlighted.set(None); } } - }) - .on_event_cont(EventListener::PointerLeave, move |_| { - capture_view.highlighted.set(None) - }); - - let capture_ = capture.clone(); - let selected_overlay = empty().style(move |s| { - if let Some(view) = capture_view - .selected - .get() - .and_then(|id| capture_.root.find(id)) - { - s.absolute() - .margin_left(5.0 + view.layout.x0) - .margin_top(5.0 + view.layout.y0) - .width(view.layout.width()) - .height(view.layout.height()) - .background(Color::rgb8(186, 180, 216).multiply_alpha(0.5)) - .border_color(Color::rgb8(186, 180, 216).multiply_alpha(0.7)) - .border(1.) - } else { - s } + }) + .on_event_cont(EventListener::PointerLeave, move |_| { + capture_view.highlighted.set(None) }); let capture_ = capture.clone(); - let highlighted_overlay = empty().style(move |s| { - if let Some(view) = capture_view - .highlighted - .get() - .and_then(|id| capture_.root.find(id)) - { - s.absolute() - .margin_left(5.0 + view.layout.x0) - .margin_top(5.0 + view.layout.y0) - .width(view.layout.width()) - .height(view.layout.height()) - .background(Color::rgba8(228, 237, 216, 120)) - .border_color(Color::rgba8(75, 87, 53, 120)) - .border(1.) - } else { - s - } - }); + let selected_overlay = empty() + .style(move |s| { + if let Some(view) = capture_view + .selected + .get() + .and_then(|id| capture_.root.find(id)) + { + s.absolute() + .margin_left(5.0 + view.layout.x0) + .margin_top(5.0 + view.layout.y0) + .width(view.layout.width()) + .height(view.layout.height()) + .background(Color::rgb8(186, 180, 216).multiply_alpha(0.5)) + .border_color(Color::rgb8(186, 180, 216).multiply_alpha(0.7)) + .border(1.) + } else { + s + } + }) + .pointer_events(|| false); + + let capture_ = capture.clone(); + let highlighted_overlay = empty() + .style(move |s| { + if let Some(view) = capture_view + .highlighted + .get() + .and_then(|id| capture_.root.find(id)) + { + s.absolute() + .margin_left(5.0 + view.layout.x0) + .margin_top(5.0 + view.layout.y0) + .width(view.layout.width()) + .height(view.layout.height()) + .background(Color::rgba8(228, 237, 216, 120)) + .border_color(Color::rgba8(75, 87, 53, 120)) + .border(1.) + } else { + s + } + }) + .pointer_events(|| false); let image = stack((image, selected_overlay, highlighted_overlay)); diff --git a/src/view_state.rs b/src/view_state.rs index e07b18e9..fb1d1388 100644 --- a/src/view_state.rs +++ b/src/view_state.rs @@ -174,6 +174,7 @@ pub struct ViewState { pub(crate) is_hidden_state: IsHiddenState, pub(crate) num_waiting_animations: u16, pub(crate) disable_default_events: HashSet, + pub(crate) pointer_events: bool, pub(crate) transform: Affine, pub(crate) debug_name: SmallVec<[String; 1]>, } @@ -206,6 +207,7 @@ impl ViewState { is_hidden_state: IsHiddenState::None, num_waiting_animations: 0, disable_default_events: HashSet::new(), + pointer_events: true, transform: Affine::IDENTITY, debug_name: Default::default(), } diff --git a/src/views/decorator.rs b/src/views/decorator.rs index 3107987b..f8beedda 100644 --- a/src/views/decorator.rs +++ b/src/views/decorator.rs @@ -168,6 +168,20 @@ pub trait Decorators: IntoView + Sized { view } + /// Dynamically set if the view should process pointer events + /// + /// # Reactivity + /// This function is reactive and will re-run the function automatically in response to changes in signals + fn pointer_events(self, pointer_events: impl Fn() -> bool + 'static) -> Self::DV { + let view = self.into_view(); + let id = view.id(); + create_effect(move |_| { + let pointer_events = pointer_events(); + id.pointer_events(pointer_events); + }); + view + } + /// Mark the view as draggable fn draggable(self) -> Self::DV { let view = self.into_view(); diff --git a/vello/src/lib.rs b/vello/src/lib.rs index df5374c9..6c0cd7d1 100644 --- a/vello/src/lib.rs +++ b/vello/src/lib.rs @@ -202,18 +202,29 @@ impl Renderer for VelloRenderer { fn fill<'b>(&mut self, path: &impl Shape, brush: impl Into>, blur_radius: f64) { let brush: BrushRef<'b> = brush.into(); - if blur_radius > 0. { + if let Some(rounded) = path.as_rounded_rect() { + let BrushRef::Solid(color) = brush else { + return; + }; + let rect_radius = rounded.radii().top_left; + let rect = rounded.rect(); + self.scene.draw_blurred_rounded_rect( + self.transform.then_scale(self.window_scale), + rect, + color, + rect_radius, + blur_radius, + ); + } else if let Some(rect) = path.as_rect() { let BrushRef::Solid(color) = brush else { return; }; - let rect = path.as_rounded_rect().unwrap_or_default().rect(); - self.scene.draw_blurred_rounded_rect( self.transform.then_scale(self.window_scale), rect, color, + 0., blur_radius, - 3., ); } else { self.scene.fill(