Merge branch 'master' into tui_focus

This commit is contained in:
Demonthos authored and GitHub committed 2022-05-06 21:19:13 -05:00
commit a3abe3965a
16 files changed
+303 -45

No files matched your search

+232
View File
@@ -0,0 +1,232 @@
use std::fmt::Formatter;
// trying to keep values at 3 bytes
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub enum AttributeValue<'a> {
Text(&'a str),
Float32(f32),
Float64(f64),
Int32(i32),
Int64(i64),
Uint32(u32),
Uint64(u64),
Bool(bool),
Vec3Float(f32, f32, f32),
Vec3Int(i32, i32, i32),
Vec3Uint(u32, u32, u32),
Vec4Float(f32, f32, f32, f32),
Vec4Int(i32, i32, i32, i32),
Vec4Uint(u32, u32, u32, u32),
Bytes(&'a [u8]),
Any(ArbitraryAttributeValue<'a>),
}
impl<'a> AttributeValue<'a> {
pub fn is_truthy(&self) -> bool {
match self {
AttributeValue::Text(t) => *t == "true",
AttributeValue::Bool(t) => *t,
_ => false,
}
}
pub fn is_falsy(&self) -> bool {
match self {
AttributeValue::Text(t) => *t == "false",
AttributeValue::Bool(t) => !(*t),
_ => false,
}
}
}
impl<'a> std::fmt::Display for AttributeValue<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
AttributeValue::Text(a) => write!(f, "{}", a),
AttributeValue::Float32(a) => write!(f, "{}", a),
AttributeValue::Float64(a) => write!(f, "{}", a),
AttributeValue::Int32(a) => write!(f, "{}", a),
AttributeValue::Int64(a) => write!(f, "{}", a),
AttributeValue::Uint32(a) => write!(f, "{}", a),
AttributeValue::Uint64(a) => write!(f, "{}", a),
AttributeValue::Bool(a) => write!(f, "{}", a),
AttributeValue::Vec3Float(_, _, _) => todo!(),
AttributeValue::Vec3Int(_, _, _) => todo!(),
AttributeValue::Vec3Uint(_, _, _) => todo!(),
AttributeValue::Vec4Float(_, _, _, _) => todo!(),
AttributeValue::Vec4Int(_, _, _, _) => todo!(),
AttributeValue::Vec4Uint(_, _, _, _) => todo!(),
AttributeValue::Bytes(_) => todo!(),
AttributeValue::Any(_) => todo!(),
}
}
}
#[derive(Clone, Copy)]
pub struct ArbitraryAttributeValue<'a> {
pub value: &'a dyn std::any::Any,
pub cmp: fn(&'a dyn std::any::Any, &'a dyn std::any::Any) -> bool,
}
impl PartialEq for ArbitraryAttributeValue<'_> {
fn eq(&self, other: &Self) -> bool {
(self.cmp)(self.value, other.value)
}
}
impl std::fmt::Debug for ArbitraryAttributeValue<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ArbitraryAttributeValue").finish()
}
}
#[cfg(feature = "serialize")]
impl<'a> serde::Serialize for ArbitraryAttributeValue<'a> {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
panic!("ArbitraryAttributeValue should not be serialized")
}
}
#[cfg(feature = "serialize")]
impl<'de, 'a> serde::Deserialize<'de> for &'a ArbitraryAttributeValue<'a> {
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
panic!("ArbitraryAttributeValue is not deserializable!")
}
}
#[cfg(feature = "serialize")]
impl<'de, 'a> serde::Deserialize<'de> for ArbitraryAttributeValue<'a> {
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
panic!("ArbitraryAttributeValue is not deserializable!")
}
}
impl<'a> AttributeValue<'a> {
pub fn as_text(&self) -> Option<&'a str> {
match self {
AttributeValue::Text(s) => Some(s),
_ => None,
}
}
pub fn as_float32(&self) -> Option<f32> {
match self {
AttributeValue::Float32(f) => Some(*f),
_ => None,
}
}
pub fn as_float64(&self) -> Option<f64> {
match self {
AttributeValue::Float64(f) => Some(*f),
_ => None,
}
}
pub fn as_int32(&self) -> Option<i32> {
match self {
AttributeValue::Int32(i) => Some(*i),
_ => None,
}
}
pub fn as_int64(&self) -> Option<i64> {
match self {
AttributeValue::Int64(i) => Some(*i),
_ => None,
}
}
pub fn as_uint32(&self) -> Option<u32> {
match self {
AttributeValue::Uint32(i) => Some(*i),
_ => None,
}
}
pub fn as_uint64(&self) -> Option<u64> {
match self {
AttributeValue::Uint64(i) => Some(*i),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
AttributeValue::Bool(b) => Some(*b),
_ => None,
}
}
pub fn as_vec3_float(&self) -> Option<(f32, f32, f32)> {
match self {
AttributeValue::Vec3Float(x, y, z) => Some((*x, *y, *z)),
_ => None,
}
}
pub fn as_vec3_int(&self) -> Option<(i32, i32, i32)> {
match self {
AttributeValue::Vec3Int(x, y, z) => Some((*x, *y, *z)),
_ => None,
}
}
pub fn as_vec3_uint(&self) -> Option<(u32, u32, u32)> {
match self {
AttributeValue::Vec3Uint(x, y, z) => Some((*x, *y, *z)),
_ => None,
}
}
pub fn as_vec4_float(&self) -> Option<(f32, f32, f32, f32)> {
match self {
AttributeValue::Vec4Float(x, y, z, w) => Some((*x, *y, *z, *w)),
_ => None,
}
}
pub fn as_vec4_int(&self) -> Option<(i32, i32, i32, i32)> {
match self {
AttributeValue::Vec4Int(x, y, z, w) => Some((*x, *y, *z, *w)),
_ => None,
}
}
pub fn as_vec4_uint(&self) -> Option<(u32, u32, u32, u32)> {
match self {
AttributeValue::Vec4Uint(x, y, z, w) => Some((*x, *y, *z, *w)),
_ => None,
}
}
pub fn as_bytes(&self) -> Option<&[u8]> {
match self {
AttributeValue::Bytes(b) => Some(b),
_ => None,
}
}
pub fn as_any(&self) -> Option<&'a ArbitraryAttributeValue> {
match self {
AttributeValue::Any(a) => Some(a),
_ => None,
}
}
}
// #[test]
// fn test_attribute_value_size() {
// assert_eq!(std::mem::size_of::<AttributeValue<'_>>(), 24);
// }
+2
View File
@@ -2,6 +2,7 @@
#![doc = include_str!("../README.md")]
#![deny(missing_docs)]
pub(crate) mod arbitrary_value;
pub(crate) mod diff;
pub(crate) mod events;
pub(crate) mod lazynodes;
@@ -13,6 +14,7 @@ pub(crate) mod util;
pub(crate) mod virtual_dom;
pub(crate) mod innerlude {
pub use crate::arbitrary_value::*;
pub use crate::events::*;
pub use crate::lazynodes::*;
pub use crate::mutations::*;
+4 -3
View File
@@ -167,8 +167,9 @@ pub enum DomEdit<'bump> {
field: &'static str,
/// The value of the attribute.
value: &'bump str,
value: AttributeValue<'bump>,
// value: &'bump str,
/// The (optional) namespace of the attribute.
/// For instance, "style" is in the "style" namespace.
ns: Option<&'bump str>,
@@ -286,7 +287,7 @@ impl<'a> Mutations<'a> {
self.edits.push(SetText { text, root });
}
pub(crate) fn set_attribute(&mut self, attribute: &'a Attribute, root: u64) {
pub(crate) fn set_attribute(&mut self, attribute: &'a Attribute<'a>, root: u64) {
let Attribute {
name,
value,
@@ -296,7 +297,7 @@ impl<'a> Mutations<'a> {
self.edits.push(SetAttribute {
field: name,
value,
value: value.clone(),
ns: *namespace,
root,
});
+20 -2
View File
@@ -4,7 +4,7 @@
//! cheap and *very* fast to construct - building a full tree should be quick.
use crate::{
innerlude::{ComponentPtr, Element, Properties, Scope, ScopeId, ScopeState},
innerlude::{AttributeValue, ComponentPtr, Element, Properties, Scope, ScopeId, ScopeState},
lazynodes::LazyNodes,
AnyEvent, Component,
};
@@ -339,7 +339,7 @@ pub struct Attribute<'a> {
pub name: &'static str,
/// The value of the attribute.
pub value: &'a str,
pub value: AttributeValue<'a>,
/// An indication if this attribute can be ignored during diffing
///
@@ -610,6 +610,24 @@ impl<'a> NodeFactory<'a> {
is_volatile: bool,
) -> Attribute<'a> {
let (value, is_static) = self.raw_text(val);
Attribute {
name,
value: AttributeValue::Text(value),
is_static,
namespace,
is_volatile,
}
}
/// Create a new [`Attribute`] using non-arguments
pub fn custom_attr(
&self,
name: &'static str,
value: AttributeValue<'a>,
namespace: Option<&'static str>,
is_volatile: bool,
is_static: bool,
) -> Attribute<'a> {
Attribute {
name,
value,
+2 -6
View File
@@ -20,7 +20,7 @@ serde = "1.0.136"
serde_json = "1.0.79"
thiserror = "1.0.30"
log = "0.4.14"
wry = { version = "0.13.1" }
wry = { version = "0.16.0" }
futures-channel = "0.3.21"
tokio = { version = "1.16.1", features = [
"sync",
@@ -28,7 +28,7 @@ tokio = { version = "1.16.1", features = [
"rt",
"time",
], optional = true, default-features = false }
webbrowser = "0.6.0"
webbrowser = "0.7.1"
mime_guess = "2.0.3"
dunce = "1.0.2"
@@ -38,13 +38,9 @@ core-foundation = "0.9.3"
[features]
default = ["tokio_runtime"]
tokio_runtime = ["tokio"]
devtool = ["wry/devtool"]
fullscreen = ["wry/fullscreen"]
transparent = ["wry/transparent"]
tray = ["wry/tray"]
ayatana = ["wry/ayatana"]
[dev-dependencies]
+1 -1
View File
@@ -191,7 +191,7 @@ pub(super) fn handler(
SetTitle(content) => window.set_title(&content),
SetDecorations(state) => window.set_decorations(state),
DevTool => webview.devtool(),
DevTool => {}
Eval(code) => webview
.evaluate_script(code.as_str())
+1 -1
View File
@@ -200,7 +200,7 @@ pub fn launch_with_props<P: 'static + Send>(
)
} else {
// in debug, we are okay with the reload menu showing and dev tool
webview = webview.with_dev_tool(true);
webview = webview.with_devtools(true);
}
desktop.webviews.insert(window_id, webview.build().unwrap());
+4 -2
View File
@@ -186,7 +186,9 @@ impl<'a> TextRenderer<'a, '_> {
while let Some(attr) = attr_iter.next() {
match attr.namespace {
None => match attr.name {
"dangerous_inner_html" => inner_html = Some(attr.value),
"dangerous_inner_html" => {
inner_html = Some(attr.value.as_text().unwrap())
}
"allowfullscreen"
| "allowpaymentrequest"
| "async"
@@ -213,7 +215,7 @@ impl<'a> TextRenderer<'a, '_> {
| "reversed"
| "selected"
| "truespeed" => {
if attr.value != "false" {
if attr.value.is_truthy() {
write!(f, " {}=\"{}\"", attr.name, attr.value)?
}
}
+24 -20
View File
@@ -259,33 +259,37 @@ impl InnerInputState {
let old_pos = previous_mouse
.as_ref()
.map(|m| (m.0.screen_x, m.0.screen_y));
let clicked =
(!mouse.0.buttons & previous_mouse.as_ref().map(|m| m.0.buttons).unwrap_or(0)) > 0;
// the a mouse button is pressed if a button was not down and is now down
let pressed =
(mouse.0.buttons & !previous_mouse.as_ref().map(|m| m.0.buttons).unwrap_or(0)) > 0;
// the a mouse button is pressed if a button was down and is now not down
let released =
(mouse.0.buttons & !previous_mouse.map(|m| m.0.buttons).unwrap_or(0)) > 0;
(!mouse.0.buttons & previous_mouse.map(|m| m.0.buttons).unwrap_or(0)) > 0;
let wheel_delta = self.wheel.as_ref().map_or(0.0, |w| w.delta_y);
let mouse_data = &mouse.0;
let wheel_data = &self.wheel;
{
// mousemove
let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mousemove") {
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let previously_contained = old_pos
.filter(|pos| layout_contains_point(node_layout, *pos))
.is_some();
let currently_contains = layout_contains_point(node_layout, new_pos);
if old_pos != Some(new_pos) {
let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mousemove") {
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let previously_contained = old_pos
.filter(|pos| layout_contains_point(node_layout, *pos))
.is_some();
let currently_contains = layout_contains_point(node_layout, new_pos);
if currently_contains && previously_contained {
try_create_event(
"mousemove",
Arc::new(prepare_mouse_data(mouse_data, node_layout)),
&mut will_bubble,
resolved_events,
node,
dom,
);
if currently_contains && previously_contained {
try_create_event(
"mousemove",
Arc::new(prepare_mouse_data(mouse_data, node_layout)),
&mut will_bubble,
resolved_events,
node,
dom,
);
}
}
}
}
@@ -337,7 +341,7 @@ impl InnerInputState {
}
// mousedown
if clicked {
if pressed {
let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mousedown") {
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
+5 -3
View File
@@ -79,9 +79,11 @@ impl ChildDepState for StretchLayout {
}
} else {
// gather up all the styles from the attribute list
for &Attribute { name, value, .. } in node.attributes() {
assert!(SORTED_LAYOUT_ATTRS.binary_search(&name).is_ok());
apply_layout_attributes(name, value, &mut style);
for Attribute { name, value, .. } in node.attributes() {
assert!(SORTED_LAYOUT_ATTRS.binary_search(name).is_ok());
if let Some(text) = value.as_text() {
apply_layout_attributes(name, text, &mut style);
}
}
// the root node fills the entire area
+4 -2
View File
@@ -78,8 +78,10 @@ impl ParentDepState for StyleModifier {
}
// gather up all the styles from the attribute list
for &Attribute { name, value, .. } in node.attributes() {
apply_style_attributes(name, value, &mut new);
for Attribute { name, value, .. } in node.attributes() {
if let Some(text) = value.as_text() {
apply_style_attributes(name, text, &mut new);
}
}
// keep the text styling from the parent element
+1 -1
View File
@@ -14,7 +14,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"]
dioxus-core = { path = "../core", version = "^0.2.1" }
dioxus-html = { path = "../html", version = "^0.2.1", features = ["wasm-bind"] }
dioxus-interpreter-js = { path = "../interpreter", version = "^0.2.1", features = [
"web",
"web"
] }
js-sys = "0.3.56"
+1 -1
View File
@@ -146,7 +146,7 @@ impl WebsysDom {
value,
ns,
} => {
let value = serde_wasm_bindgen::to_value(value).unwrap();
let value = serde_wasm_bindgen::to_value(&value).unwrap();
self.interpreter.SetAttribute(root, field, value, ns)
}
}