Fix an assortment of small bugs (#3968)
* Fix an assertion failure bug when scaling a line in the transform cage * Fix missing defaults on node gradient inputs * Fix Blend Shapes path input wire not updating to show in the UI after Layer > Blend * Fix assertion failure due to browser non-monotonic timestamp * Fix SVG renderer drawing 1px strokes as half-width when using stroke alignment * Fix incorrect appearance of the ColorInput widget when set to "none" and "disabled" * Fix lerp function in Fill enum to handle None cases correctly * Fix stroke alignment bug
This commit is contained in:
parent
865e9713ad
commit
6388a32ac5
|
|
@ -139,7 +139,8 @@ impl FrameTimeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn advance_timestamp(&mut self, next_timestamp: Duration) {
|
pub fn advance_timestamp(&mut self, next_timestamp: Duration) {
|
||||||
debug_assert!(next_timestamp >= self.timestamp);
|
// Guard against non-monotonic timestamps from the browser (Keavon observed this once in Chrome)
|
||||||
|
let next_timestamp = next_timestamp.max(self.timestamp);
|
||||||
|
|
||||||
self.prev_timestamp = Some(self.timestamp);
|
self.prev_timestamp = Some(self.timestamp);
|
||||||
self.timestamp = next_timestamp;
|
self.timestamp = next_timestamp;
|
||||||
|
|
|
||||||
|
|
@ -4005,6 +4005,14 @@ impl NodeNetworkInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(_, NodeInput::Node { node_id: upstream_node_id, .. }) => {
|
(_, NodeInput::Node { node_id: upstream_node_id, .. }) => {
|
||||||
|
// If the old input wasn't exposed but the new one is (`Node` inputs are always exposed),
|
||||||
|
// the node's port count changed, so its click targets need to be recomputed
|
||||||
|
if !old_input.is_exposed()
|
||||||
|
&& let InputConnector::Node { node_id, .. } = input_connector
|
||||||
|
{
|
||||||
|
self.unload_node_click_targets(node_id, network_path);
|
||||||
|
}
|
||||||
|
|
||||||
// Load structure if the change is to the document network and to the first or second
|
// Load structure if the change is to the document network and to the first or second
|
||||||
if network_path.is_empty() {
|
if network_path.is_empty() {
|
||||||
if matches!(input_connector, InputConnector::Export(0)) {
|
if matches!(input_connector, InputConnector::Export(0)) {
|
||||||
|
|
|
||||||
|
|
@ -212,16 +212,15 @@ impl SelectedEdges {
|
||||||
let original_from_pivot = updated - pivot; // The original vector from the point to the pivot
|
let original_from_pivot = updated - pivot; // The original vector from the point to the pivot
|
||||||
let mut scale_factor = new_from_pivot / original_from_pivot;
|
let mut scale_factor = new_from_pivot / original_from_pivot;
|
||||||
|
|
||||||
// Constrain should always scale by the same factor in x and y
|
// Constrain should always scale by the same factor in x and y.
|
||||||
|
// When one axis of `original_from_pivot` is near zero (e.g. for a line's degenerate bounding box),
|
||||||
|
// the scale factor for that axis is numerically unstable, so we copy from the more stable axis.
|
||||||
if constrain {
|
if constrain {
|
||||||
// When the point is on the pivot, we simply copy the other axis.
|
if original_from_pivot.x.abs() < original_from_pivot.y.abs() {
|
||||||
if original_from_pivot.x.abs() < 1e-5 {
|
|
||||||
scale_factor.x = scale_factor.y;
|
scale_factor.x = scale_factor.y;
|
||||||
} else if original_from_pivot.y.abs() < 1e-5 {
|
} else {
|
||||||
scale_factor.y = scale_factor.x;
|
scale_factor.y = scale_factor.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!((scale_factor.x - scale_factor.y).abs() < 1e-5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(self.left || self.right || constrain) {
|
if !(self.left || self.right || constrain) {
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@
|
||||||
background-repeat: var(--color-transparent-checkered-background-repeat);
|
background-repeat: var(--color-transparent-checkered-background-repeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.disabled).none > button {
|
&.none > button {
|
||||||
background: var(--color-none);
|
background: var(--color-none);
|
||||||
background-repeat: var(--color-none-repeat);
|
background-repeat: var(--color-none-repeat);
|
||||||
background-position: var(--color-none-position);
|
background-position: var(--color-none-position);
|
||||||
|
|
@ -132,6 +132,7 @@
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
background: var(--color-4-dimgray);
|
background: var(--color-4-dimgray);
|
||||||
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.disabled):hover > button .text-label,
|
&:not(.disabled):hover > button .text-label,
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,9 @@ macro_rules! tagged_value {
|
||||||
// Tries using the default for the tagged value type. If it not implemented, then uses the default used in document_node_types. If it is not used there, then TaggedValue::None is returned.
|
// Tries using the default for the tagged value type. If it not implemented, then uses the default used in document_node_types. If it is not used there, then TaggedValue::None is returned.
|
||||||
Some(match concrete_type.id? {
|
Some(match concrete_type.id? {
|
||||||
x if x == TypeId::of::<()>() => TaggedValue::None,
|
x if x == TypeId::of::<()>() => TaggedValue::None,
|
||||||
|
// Table-wrapped types need a single-row default with the element's default, not an empty table
|
||||||
|
x if x == TypeId::of::<Table<Color>>() => TaggedValue::Color(Table::new_from_element(Color::default())),
|
||||||
|
x if x == TypeId::of::<Table<GradientStops>>() => TaggedValue::GradientTable(Table::new_from_element(GradientStops::default())),
|
||||||
$( x if x == TypeId::of::<$ty>() => TaggedValue::$identifier(Default::default()), )*
|
$( x if x == TypeId::of::<$ty>() => TaggedValue::$identifier(Default::default()), )*
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -112,8 +112,10 @@ impl RenderExt for Stroke {
|
||||||
return String::new();
|
return String::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let default_weight = if self.align != StrokeAlign::Center && render_params.aligned_strokes { 1. / 2. } else { 1. };
|
||||||
|
|
||||||
// Set to None if the value is the SVG default
|
// Set to None if the value is the SVG default
|
||||||
let weight = (self.weight != 1.).then_some(self.weight);
|
let weight = (self.weight != default_weight).then_some(self.weight);
|
||||||
let dash_array = (!self.dash_lengths.is_empty()).then_some(self.dash_lengths());
|
let dash_array = (!self.dash_lengths.is_empty()).then_some(self.dash_lengths());
|
||||||
let dash_offset = (self.dash_offset != 0.).then_some(self.dash_offset);
|
let dash_offset = (self.dash_offset != 0.).then_some(self.dash_offset);
|
||||||
let stroke_cap = (self.cap != StrokeCap::Butt).then_some(self.cap);
|
let stroke_cap = (self.cap != StrokeCap::Butt).then_some(self.cap);
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,8 @@ impl Fill {
|
||||||
|
|
||||||
pub fn lerp(&self, other: &Self, time: f64) -> Self {
|
pub fn lerp(&self, other: &Self, time: f64) -> Self {
|
||||||
let transparent = Self::solid(Color::TRANSPARENT);
|
let transparent = Self::solid(Color::TRANSPARENT);
|
||||||
let a = if *self == Self::None { &transparent } else { self };
|
let a = if *self == Self::None && *other != Self::None { &transparent } else { self };
|
||||||
let b = if *other == Self::None { &transparent } else { other };
|
let b = if *other == Self::None && *self != Self::None { &transparent } else { other };
|
||||||
|
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(Self::Solid(a), Self::Solid(b)) => Self::Solid(a.lerp(b, time as f32)),
|
(Self::Solid(a), Self::Solid(b)) => Self::Solid(a.lerp(b, time as f32)),
|
||||||
|
|
@ -82,7 +82,7 @@ impl Fill {
|
||||||
Self::Gradient(a.lerp(b, time))
|
Self::Gradient(a.lerp(b, time))
|
||||||
}
|
}
|
||||||
(Self::Gradient(a), Self::Gradient(b)) => Self::Gradient(a.lerp(b, time)),
|
(Self::Gradient(a), Self::Gradient(b)) => Self::Gradient(a.lerp(b, time)),
|
||||||
_ => Self::None,
|
(Self::None, _) | (_, Self::None) => Self::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue