mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-09 17:40:14 -06:00
Variables: art on a locked artboard is not bound or rewritten by a data set
Squashed from #5118 onto main.
This commit is contained in:
+42
-15
@@ -6,7 +6,7 @@ use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{Document, NodeId, NodeKind, TextKind};
|
||||
use super::{Document, LockedArtboards, NodeId, NodeKind, TextKind};
|
||||
|
||||
/// What a variable drives.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@@ -190,17 +190,32 @@ impl Document {
|
||||
}
|
||||
|
||||
/// Whether a variable may be bound to the object `id`: it is in the document, neither it nor
|
||||
/// anything above it is locked, and nothing above it is hidden. Its own visibility doesn't
|
||||
/// count, as that is what a visibility variable drives.
|
||||
/// anything above it is locked, nothing above it is hidden, and it is not on a locked artboard
|
||||
/// ([`Document::on_locked_artboard`]). Its own visibility doesn't count, as that is what a
|
||||
/// visibility variable drives.
|
||||
pub fn variable_target(&self, id: NodeId) -> bool {
|
||||
self.ancestry(id).is_some_and(|a| a.iter().all(|i| self.node(*i).is_some_and(|n| !n.locked && (n.visible || *i == id))))
|
||||
self.variable_target_with(&self.locked_artboards(), id)
|
||||
}
|
||||
|
||||
/// Whether a data set reads and rewrites the bound object `id`: it is in the document and
|
||||
/// neither it nor anything above it is locked. Hidden objects count, and so do objects in a
|
||||
/// hidden layer or group.
|
||||
/// [`Document::variable_target`] with the locked artboards `locks` of this document, measured
|
||||
/// once for many ids.
|
||||
pub fn variable_target_with(&self, locks: &LockedArtboards, id: NodeId) -> bool {
|
||||
self.ancestry(id).is_some_and(|a| a.iter().all(|i| self.node(*i).is_some_and(|n| !n.locked && (n.visible || *i == id))))
|
||||
&& !locks.holds_id(id)
|
||||
}
|
||||
|
||||
/// Whether a data set reads and rewrites the bound object `id`: it is in the document, neither
|
||||
/// it nor anything above it is locked, and it is not on a locked artboard
|
||||
/// ([`Document::on_locked_artboard`]). Hidden objects count, and so do objects in a hidden
|
||||
/// layer or group.
|
||||
pub fn dataset_target(&self, id: NodeId) -> bool {
|
||||
self.ancestry(id).is_some_and(|a| a.iter().all(|i| self.node(*i).is_some_and(|n| !n.locked)))
|
||||
self.dataset_target_with(&self.locked_artboards(), id)
|
||||
}
|
||||
|
||||
/// [`Document::dataset_target`] with the locked artboards `locks` of this document, measured
|
||||
/// once for many ids.
|
||||
pub fn dataset_target_with(&self, locks: &LockedArtboards, id: NodeId) -> bool {
|
||||
self.ancestry(id).is_some_and(|a| a.iter().all(|i| self.node(*i).is_some_and(|n| !n.locked))) && !locks.holds_id(id)
|
||||
}
|
||||
|
||||
/// The type objects of the story that the type object `id` belongs to, in thread order: the
|
||||
@@ -228,21 +243,32 @@ impl Document {
|
||||
/// Whether a data set reads and rewrites the text of the type object `id`: every frame of its
|
||||
/// story ([`Document::story_of`]) is a [`Document::dataset_target`].
|
||||
pub fn story_target(&self, id: NodeId) -> bool {
|
||||
self.story_of(id).into_iter().all(|f| self.dataset_target(f))
|
||||
self.story_target_with(&self.locked_artboards(), id)
|
||||
}
|
||||
|
||||
/// [`Document::story_target`] with the locked artboards `locks` of this document, measured
|
||||
/// once for many ids.
|
||||
pub fn story_target_with(&self, locks: &LockedArtboards, id: NodeId) -> bool {
|
||||
self.story_of(id).into_iter().all(|f| self.dataset_target_with(locks, f))
|
||||
}
|
||||
|
||||
/// What the object `id` holds for the variable of `kind`: its characters (the whole story
|
||||
/// for a frame of threaded text), whether it shows, or a linked image's path. `None` when the
|
||||
/// object is gone, is not of that kind, has no link path yet (an embedded image), or is locked
|
||||
/// or in a locked layer or group, or for text when a frame of its story is (the document's
|
||||
/// value is whatever it was left at).
|
||||
/// object is gone, is not of that kind, has no link path yet (an embedded image), or is locked,
|
||||
/// in a locked layer or group, or on a locked artboard, or for text when a frame of its story
|
||||
/// is (the document's value is whatever it was left at).
|
||||
pub fn variable_value(&self, id: NodeId, kind: VariableKind) -> Option<DataValue> {
|
||||
if !self.dataset_target(id) {
|
||||
self.variable_value_with(&self.locked_artboards(), id, kind)
|
||||
}
|
||||
|
||||
/// [`Document::variable_value`] with the locked artboards `locks` of this document.
|
||||
fn variable_value_with(&self, locks: &LockedArtboards, id: NodeId, kind: VariableKind) -> Option<DataValue> {
|
||||
if !self.dataset_target_with(locks, id) {
|
||||
return None;
|
||||
}
|
||||
let node = self.node(id)?;
|
||||
match (kind, &node.kind) {
|
||||
(VariableKind::Text, NodeKind::Text(_)) if self.story_target(id) => Some(DataValue::Text(self.story_text(id))),
|
||||
(VariableKind::Text, NodeKind::Text(_)) if self.story_target_with(locks, id) => Some(DataValue::Text(self.story_text(id))),
|
||||
(VariableKind::Visibility, _) => Some(DataValue::Visible(node.visible)),
|
||||
(VariableKind::Image, NodeKind::Image(im)) => im.link.as_ref().map(|l| DataValue::Image(l.path.clone())),
|
||||
(VariableKind::Graph, _) => node.extras().graph.as_ref().map(|g| DataValue::Graph(g.to_csv())),
|
||||
@@ -257,10 +283,11 @@ impl Document {
|
||||
/// still matches what it says.
|
||||
pub fn captured_values(&self) -> BTreeMap<String, DataValue> {
|
||||
let mut out = BTreeMap::new();
|
||||
let locks = self.locked_artboards();
|
||||
for v in &self.variables.variables {
|
||||
// An object driven by several variables of the same kind reads from the first one
|
||||
// bound, so a capture is one value per variable and applies back the same way.
|
||||
let value = self.variables.objects_of(&v.name).into_iter().find_map(|id| self.variable_value(id, v.kind));
|
||||
let value = self.variables.objects_of(&v.name).into_iter().find_map(|id| self.variable_value_with(&locks, id, v.kind));
|
||||
if let Some(value) = value {
|
||||
out.insert(v.name.clone(), value);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user