Files
figcraft/crates/engine/src/session/new.rs
T
Filip StrajnarandClaude Opus 5.5 20f1219fbc M1: Set default properties gives new shapes and text the layer's properties (#2028)
Edit ▸ Set default properties put the selected layer's properties into the Paste properties
clipboard and did nothing else: a rectangle drawn afterwards was still the default grey, and what
Copy properties had copied was replaced.

The defaults are now kept apart (`Session::default_props`: one set for shapes, set from any layer
but text, and one for text). Rectangles, ellipses, polygons and stars drawn or clicked with their
tools take the shape defaults: fills, strokes and their settings, effects, opacity, blend and
corners (only where the shape has corners), through `apply_copied_props`, the rules Paste
properties already used (now shared). New text from the Text tool takes a text layer's fills and
font and is laid out at that size. Frames, sections, slices, lines, arrows, vectors and layers made
by commands keep their own look; the help center is silent on those. `edit.setDefaultProperties`
answers `{for: shapes|text, properties}`.

Tests: `default_props_tests::new_shapes_drawn_with_the_tools_take_the_default_properties`,
`setting_defaults_leaves_the_copied_properties_alone`,
`new_text_takes_a_text_layers_defaults_and_shapes_keep_theirs`. Docs: ui-parity.md, ROADMAP.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvG6E2LxvJ6MuFmiLA6Zqm
2026-11-06 12:55:21 +01:00

91 lines
3.5 KiB
Rust

use super::{Arc, Clipboard, DocState, Document, Prefs, Session, background, cmd, events, library, live, plugins, tools};
impl Session {
/// A session with one new document.
pub fn new() -> Self {
let mut s = Self::empty();
s.docs.push(DocState::new(Document::new("Untitled"), None));
s
}
/// A session with no documents (the home screen).
pub fn empty() -> Self {
Self {
docs: Vec::new(),
active: 0,
clipboard: Clipboard::default(),
default_props: Default::default(),
prefs: Prefs::default(),
prefs_unsaved: false,
tool: tools::ToolState::default(),
ui_requests: Vec::new(),
ui_dark: None,
journal: Vec::new(),
group_depth: 0,
closed_in_group: Vec::new(),
recent_colors: Vec::new(),
last_command: None,
message: None,
libraries: library::Cache::default(),
plugins: plugins::Runtime::default(),
live: live::Lives::default(),
background: background::Background::default(),
events: Arc::new(events::EventLog::default()),
pending_events: Vec::new(),
agent: None,
agent_presence: None,
}
}
/// The background a new file's page gets: the dark page colour while the interface is dark.
pub fn new_page_background(&self) -> figcraft_color::Color {
if self.ui_dark == Some(true) { figcraft_color::Color::DARK_PAGE } else { figcraft_color::Color::DEFAULT_PAGE }
}
/// Tell the engine the interface's theme (the UI does, every frame). The first time, a new
/// file nothing was done to yet (the one the app opened with, made before the theme was
/// known) takes the theme's page colour; later changes of theme leave existing pages alone.
pub fn set_ui_dark(&mut self, dark: bool) {
if self.ui_dark.replace(dark).is_some() || !dark {
return;
}
for ds in &mut self.docs {
let untouched = ds.path.is_none() && ds.history.undo.is_empty() && ds.history.redo.is_empty() && !ds.is_dirty() && ds.versions.is_empty();
let pages = ds.doc.pages.clone();
let blank = pages.iter().all(|p| {
ds.doc.node(*p).is_some_and(|n| {
n.children.is_empty()
&& matches!(n.kind, figcraft_doc::NodeKind::Page { background, .. } if background == figcraft_color::Color::DEFAULT_PAGE)
})
});
if !(untouched && blank) {
continue;
}
let mut doc = (*ds.doc).clone();
for p in pages {
if let Some(figcraft_doc::NodeKind::Page { background, .. }) = doc.node_mut(p).map(|n| &mut n.kind) {
*background = figcraft_color::Color::DARK_PAGE;
}
}
// Still a file without changes.
ds.doc = Arc::new(doc);
ds.saved_doc = ds.doc.clone();
ds.revision += 1;
}
}
pub fn with_document(doc: Document) -> Self {
let mut s = Self::empty();
s.docs.push(DocState::new(doc, None));
s
}
/// Files new to the session start with the View toggles the preferences keep.
pub fn apply_view_prefs(&mut self) {
for ds in self.docs.iter_mut().filter(|d| !d.view_from_prefs) {
cmd::view::apply_kept(&self.prefs, &mut ds.view);
ds.view_from_prefs = true;
}
}
}