-
Notifications
You must be signed in to change notification settings - Fork 120
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Make xilem_svg into a library Instead of having the demo app hardcoded, make it a library with a web_examples folder, just like its xilem_html sibling. This patch doesn't change the example or any functionality. * Migrate KurboShape to ViewExt Exports a `ViewExt` trait, and wires up types so that type inference can flow through the methods on this trait. That removes the hacky `KurboShape` workaround. * clippy * Add fill and stroke Supports very basic fill and stroke (solid colors, stroke width but no other style parameters). * rustfmt * Address review feedback Fix some cut'n'paste errors, and update README slightly.
- Loading branch information
Showing
16 changed files
with
387 additions
and
158 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Xilemsvg prototype | ||
|
||
This is a proof of concept showing how to use `xilem_core` to render interactive vector graphics into SVG DOM nodes, running in a browser. A next step would be to factor it into a library so that applications can depend on it, but at the moment the test scene is baked in. | ||
This is a proof of concept showing how to use `xilem_core` to render interactive vector graphics into SVG DOM nodes, running in a browser. It is provided as a library and some examples. | ||
|
||
The easiest way to run it is to use [Trunk]. Run `trunk serve`, then navigate the browser to the link provided (usually `http://localhost:8080`). | ||
The easiest way to run the examples is to use [Trunk]. Go into the appropriate subdirectory of `web_examples`, run `trunk serve`, then navigate the browser to the link provided (usually `http://localhost:8080`). | ||
|
||
[Trunk]: https://trunkrs.dev/ |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
// Copyright 2023 the Druid Authors. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use std::{any::Any, marker::PhantomData}; | ||
|
||
use peniko::Brush; | ||
use xilem_core::{Id, MessageResult}; | ||
|
||
use crate::{ | ||
context::{ChangeFlags, Cx}, | ||
view::{DomElement, View, ViewMarker}, | ||
}; | ||
|
||
pub struct Fill<T, V> { | ||
child: V, | ||
brush: Brush, | ||
phantom: PhantomData<T>, | ||
} | ||
|
||
pub struct Stroke<T, V> { | ||
child: V, | ||
brush: Brush, | ||
style: peniko::kurbo::Stroke, | ||
phantom: PhantomData<T>, | ||
} | ||
|
||
pub fn fill<T, V>(child: V, brush: impl Into<Brush>) -> Fill<T, V> { | ||
Fill { | ||
child, | ||
brush: brush.into(), | ||
phantom: Default::default(), | ||
} | ||
} | ||
|
||
pub fn stroke<T, V>( | ||
child: V, | ||
brush: impl Into<Brush>, | ||
style: peniko::kurbo::Stroke, | ||
) -> Stroke<T, V> { | ||
Stroke { | ||
child, | ||
brush: brush.into(), | ||
style, | ||
phantom: Default::default(), | ||
} | ||
} | ||
|
||
fn brush_to_string(brush: &Brush) -> String { | ||
match brush { | ||
Brush::Solid(color) => { | ||
if color.a == 0 { | ||
"none".into() | ||
} else { | ||
format!("#{:02x}{:02x}{:02x}", color.r, color.g, color.b) | ||
} | ||
} | ||
_ => todo!("gradients not implemented"), | ||
} | ||
} | ||
|
||
impl<T, V> ViewMarker for Fill<T, V> {} | ||
|
||
// TODO: make generic over A (probably requires Phantom) | ||
impl<T, V: View<T>> View<T> for Fill<T, V> { | ||
type State = V::State; | ||
type Element = V::Element; | ||
|
||
fn build(&self, cx: &mut Cx) -> (Id, Self::State, Self::Element) { | ||
let (id, child_state, element) = self.child.build(cx); | ||
element | ||
.as_element_ref() | ||
.set_attribute("fill", &brush_to_string(&self.brush)) | ||
.unwrap(); | ||
(id, child_state, element) | ||
} | ||
|
||
fn rebuild( | ||
&self, | ||
cx: &mut Cx, | ||
prev: &Self, | ||
id: &mut Id, | ||
state: &mut Self::State, | ||
element: &mut V::Element, | ||
) -> ChangeFlags { | ||
let prev_id = *id; | ||
let mut changed = self.child.rebuild(cx, &prev.child, id, state, element); | ||
if self.brush != prev.brush || prev_id != *id { | ||
element | ||
.as_element_ref() | ||
.set_attribute("fill", &brush_to_string(&self.brush)) | ||
.unwrap(); | ||
changed.insert(ChangeFlags::OTHER_CHANGE); | ||
} | ||
changed | ||
} | ||
|
||
fn message( | ||
&self, | ||
id_path: &[Id], | ||
state: &mut Self::State, | ||
message: Box<dyn Any>, | ||
app_state: &mut T, | ||
) -> MessageResult<()> { | ||
self.child.message(id_path, state, message, app_state) | ||
} | ||
} | ||
|
||
impl<T, V> ViewMarker for Stroke<T, V> {} | ||
|
||
// TODO: make generic over A (probably requires Phantom) | ||
impl<T, V: View<T>> View<T> for Stroke<T, V> { | ||
type State = V::State; | ||
type Element = V::Element; | ||
|
||
fn build(&self, cx: &mut Cx) -> (Id, Self::State, Self::Element) { | ||
let (id, child_state, element) = self.child.build(cx); | ||
element | ||
.as_element_ref() | ||
.set_attribute("stroke", &brush_to_string(&self.brush)) | ||
.unwrap(); | ||
element | ||
.as_element_ref() | ||
.set_attribute("stroke-width", &format!("{}", self.style.width)) | ||
.unwrap(); | ||
(id, child_state, element) | ||
} | ||
|
||
fn rebuild( | ||
&self, | ||
cx: &mut Cx, | ||
prev: &Self, | ||
id: &mut Id, | ||
state: &mut Self::State, | ||
element: &mut V::Element, | ||
) -> ChangeFlags { | ||
let prev_id = *id; | ||
let mut changed = self.child.rebuild(cx, &prev.child, id, state, element); | ||
if self.brush != prev.brush || prev_id != *id { | ||
element | ||
.as_element_ref() | ||
.set_attribute("stroke", &brush_to_string(&self.brush)) | ||
.unwrap(); | ||
changed.insert(ChangeFlags::OTHER_CHANGE); | ||
} | ||
if self.style.width != prev.style.width || prev_id != *id { | ||
element | ||
.as_element_ref() | ||
.set_attribute("stroke-width", &format!("{}", self.style.width)) | ||
.unwrap(); | ||
} | ||
changed | ||
} | ||
|
||
fn message( | ||
&self, | ||
id_path: &[Id], | ||
state: &mut Self::State, | ||
message: Box<dyn Any>, | ||
app_state: &mut T, | ||
) -> MessageResult<()> { | ||
self.child.message(id_path, state, message, app_state) | ||
} | ||
} |
Oops, something went wrong.