mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-13 13:52:34 +00:00
Merge pull request #2164 from TrevorBrown-dev/fix/sticky-text-size-2157
M12: a sticky's text keeps its size and the note grows taller (#2157)
This commit is contained in:
6 files changed
+79
-44
No files matched your search
@@ -7,7 +7,7 @@ use figcraft_doc::{
|
||||
use figcraft_geom::Point;
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::board::{route, sticky_font_size};
|
||||
use crate::board::{STICKY_TEXT_SIZE, route};
|
||||
use crate::collab_live_tests::Room;
|
||||
use crate::tools::{PointerEvent, PointerKind, ToolId};
|
||||
use crate::{EngineError, Session};
|
||||
@@ -77,7 +77,7 @@ fn board_commands_refuse_on_design_files_and_prototyping_refuses_on_boards() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_sticky_is_a_square_frame_whose_note_shrinks_as_it_grows() {
|
||||
fn a_sticky_is_a_square_frame_whose_note_grows_taller_as_it_fills() {
|
||||
let mut s = board();
|
||||
s.prefs.user_name = "Ada".into();
|
||||
let r = s.execute("board.sticky", &json!({"x": 10, "y": 20, "text": "Hi", "color": "blue"})).unwrap();
|
||||
@@ -88,19 +88,75 @@ fn a_sticky_is_a_square_frame_whose_note_shrinks_as_it_grows() {
|
||||
assert_eq!(n.fills[0].solid_color(), board_color("blue"));
|
||||
assert!(n.layout.is_some() && !n.effects.is_empty());
|
||||
assert_eq!(n.children.len(), 2, "the note and its author");
|
||||
assert_eq!(node(&s, note).kind.text().unwrap().style.font_size, 24.0);
|
||||
assert_eq!(node(&s, note).kind.text().unwrap().style.font_size, 18.0);
|
||||
// A click on the note picks the sticky whole.
|
||||
let doc = s.doc().unwrap();
|
||||
assert_eq!(figcraft_doc::geometry::select_target(doc, note, &[], false), st);
|
||||
// A long note takes a smaller size; a very long one grows the sticky past its square.
|
||||
// A long note keeps the size; a very long one grows the sticky past its square.
|
||||
let long = "word ".repeat(120);
|
||||
s.execute("node.set", &json!({"id": note, "props": {"characters": long}})).unwrap();
|
||||
assert_eq!(node(&s, note).kind.text().unwrap().style.font_size, sticky_font_size(&long));
|
||||
assert!(sticky_font_size(&long) < 16.0);
|
||||
assert_eq!(node(&s, note).kind.text().unwrap().style.font_size, STICKY_TEXT_SIZE);
|
||||
assert!(node(&s, st).width == 200.0 && node(&s, st).height >= 200.0);
|
||||
// Undo puts the short note and its size back.
|
||||
// Undo puts the short note back.
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert_eq!(node(&s, note).kind.text().unwrap().style.font_size, 24.0);
|
||||
assert_eq!(node(&s, note).kind.text().unwrap().style.font_size, 18.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_new_sticky_starts_at_18() {
|
||||
let mut s = board();
|
||||
for (cmd, p) in [("board.sticky", json!({"x": 0, "y": 0, "text": "Hi"})), ("board.sticky", json!({"x": 300, "y": 0}))] {
|
||||
let note = id(&s.execute(cmd, &p).unwrap(), "text");
|
||||
assert_eq!(node(&s, note).kind.text().unwrap().style.font_size, 18.0);
|
||||
}
|
||||
let next = id(&s.execute("board.nextSticky", &json!({})).unwrap(), "text");
|
||||
assert_eq!(node(&s, next).kind.text().unwrap().style.font_size, 18.0);
|
||||
assert_eq!(STICKY_TEXT_SIZE, 18.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_sticky_keeps_its_text_size_as_text_is_added() {
|
||||
// The note's growth needs text measured: without craft-fonts that is with a system font,
|
||||
// scanned here rather than by whichever test happens to run first (#333).
|
||||
figcraft_text::scan_system_fonts();
|
||||
let mut s = board();
|
||||
let r = s.execute("board.sticky", &json!({"x": 0, "y": 0, "text": "one"})).unwrap();
|
||||
let (st, note) = (id(&r, "id"), id(&r, "text"));
|
||||
let (height, text_height) = (node(&s, st).height, node(&s, note).height);
|
||||
// Typing in the note: each step is a real edit that runs the normalize pass.
|
||||
crate::board::edit_text(&mut s, st).unwrap();
|
||||
for _ in 0..9 {
|
||||
crate::textedit::key(&mut s, "Enter", false, false, false).unwrap();
|
||||
crate::textedit::insert(&mut s, "another line").unwrap();
|
||||
}
|
||||
let ten = node(&s, note).kind.text().unwrap().clone();
|
||||
assert_eq!(ten.characters.matches('\n').count(), 9, "ten lines");
|
||||
assert_eq!(ten.style.font_size, 18.0);
|
||||
assert!(node(&s, note).height > text_height, "ten lines make the text taller");
|
||||
assert!(node(&s, st).height > height, "and the note");
|
||||
assert_eq!(node(&s, st).child_layout.sizing_v, figcraft_doc::Sizing::Hug, "the note hugs its text");
|
||||
let (w, h10) = (node(&s, st).width, node(&s, st).height);
|
||||
crate::textedit::insert(&mut s, &"a long paragraph ".repeat(15)).unwrap();
|
||||
crate::textedit::end(&mut s).unwrap();
|
||||
let t = node(&s, note).kind.text().unwrap().clone();
|
||||
assert!(t.characters.chars().count() >= 250);
|
||||
assert_eq!(t.style.font_size, 18.0);
|
||||
assert!(t.runs.iter().all(|r| r.style.font_size == 18.0));
|
||||
assert_eq!(node(&s, st).width, w, "the note keeps its width");
|
||||
assert!(node(&s, st).height > h10, "and grows taller");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_sticky_saved_with_another_text_size_keeps_it() {
|
||||
let mut s = board();
|
||||
let r = s.execute("board.sticky", &json!({"x": 0, "y": 0, "text": "old"})).unwrap();
|
||||
let (st, note) = (id(&r, "id"), id(&r, "text"));
|
||||
s.execute("node.set", &json!({"id": note, "props": {"fontSize": 11}})).unwrap();
|
||||
assert_eq!(node(&s, note).kind.text().unwrap().style.font_size, 11.0);
|
||||
s.execute("node.set", &json!({"id": note, "props": {"characters": "old and now much longer than it was"}})).unwrap();
|
||||
assert_eq!(node(&s, note).kind.text().unwrap().style.font_size, 11.0, "an edit");
|
||||
s.execute("node.set", &json!({"id": st, "props": {"x": 40}})).unwrap();
|
||||
assert_eq!(node(&s, note).kind.text().unwrap().style.font_size, 11.0, "a move");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -69,8 +69,8 @@ pub(crate) use edit::{copied_items, copy_map, rejoin};
|
||||
use edit::{label_cmd, set_color, set_style};
|
||||
pub(crate) use items::add_text;
|
||||
pub use items::{CONNECTED_GAP, connected_place};
|
||||
pub use items::{STICKY_TEXT_SIZE, edit_text, owner_of_text, text_of};
|
||||
use items::{add_connected, ink_cmd, next_sticky, shape_cmd, stamp_cmd, sticky_cmd};
|
||||
pub use items::{edit_text, owner_of_text, sticky_font_size, text_of};
|
||||
pub(crate) use mindmap::settle_mind_maps;
|
||||
pub(crate) use reshape::path_handle_at;
|
||||
pub use reshape::selected_connector_handles;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use figcraft_doc::RouteEnd;
|
||||
|
||||
use super::edit::set_font_size;
|
||||
use super::items::{owner_of_text, shape_padding, sticky_font_size, text_of};
|
||||
use super::items::shape_padding;
|
||||
use super::{
|
||||
Affine, BTreeSet, BezPath, BoardItem, Connector, Document, End, NodeId, NodeKind, PathEl, Point, Rect, Routing, Shape, VectorNetwork, is_board,
|
||||
};
|
||||
@@ -9,26 +8,14 @@ use super::{
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Derived data (the normalize pass).
|
||||
|
||||
/// Before text is measured: a sticky's note takes the size its length calls for, and a resized
|
||||
/// shape keeps its text inside its outline.
|
||||
/// Before text is measured: a resized shape keeps its text inside its outline. A sticky's text
|
||||
/// keeps whatever size it has (FigJam's size is the note's own setting).
|
||||
pub(crate) fn settle_text(doc: &mut Document, before: &Document, touched: &BTreeSet<NodeId>) {
|
||||
if !is_board(doc) {
|
||||
return;
|
||||
}
|
||||
for &id in touched {
|
||||
let Some(n) = doc.node(id) else { continue };
|
||||
if let Some(owner) =
|
||||
owner_of_text(doc, id).or(Some(id)).filter(|o| doc.node(*o).is_some_and(|k| matches!(k.board, Some(BoardItem::Sticky { .. }))))
|
||||
&& let Some(t) = text_of(doc, owner)
|
||||
&& let Some(NodeKind::Text(td)) = doc.node(t).map(|k| &k.kind)
|
||||
{
|
||||
let size = sticky_font_size(&td.characters);
|
||||
let off = td.style.font_size != size || td.runs.iter().any(|r| r.style.font_size != size);
|
||||
if off && let Some(NodeKind::Text(td)) = doc.node_mut(t).map(|k| &mut k.kind) {
|
||||
set_font_size(td, size);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if let Some(BoardItem::Shape { shape }) = n.board
|
||||
&& before.node(id).is_none_or(|b| (b.width, b.height) != (n.width, n.height))
|
||||
{
|
||||
|
||||
@@ -57,18 +57,9 @@ pub(crate) fn add_text(doc: &mut Document, parent: NodeId, text: &str, size: f64
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
/// The text size a sticky's note gets: smaller the more it holds (by characters and lines, so
|
||||
/// every copy of the file picks the same size whatever fonts it has).
|
||||
pub fn sticky_font_size(text: &str) -> f64 {
|
||||
let weight = text.chars().count() + 24 * text.matches('\n').count();
|
||||
match weight {
|
||||
0..=24 => 24.0,
|
||||
25..=64 => 20.0,
|
||||
65..=140 => 16.0,
|
||||
141..=280 => 13.0,
|
||||
_ => 11.0,
|
||||
}
|
||||
}
|
||||
/// The text size of a new sticky's note, FigJam's "Small" default (measured in the web app,
|
||||
/// 2026-11-09): it never changes as the note fills, the note grows taller instead.
|
||||
pub const STICKY_TEXT_SIZE: f64 = 18.0;
|
||||
|
||||
/// A sticky note's layers: the frame, the note and (when known) its author.
|
||||
fn make_sticky(doc: &mut Document, parent: NodeId, at: (f64, f64), text: &str, color: Color, author: &str) -> Result<(NodeId, NodeId)> {
|
||||
@@ -89,7 +80,7 @@ fn make_sticky(doc: &mut Document, parent: NodeId, at: (f64, f64), text: &str, c
|
||||
n.board = Some(BoardItem::Sticky { author: author.to_string() });
|
||||
})?;
|
||||
let inner = STICKY - 2.0 * STICKY_PAD;
|
||||
let note = add_text(doc, id, text, sticky_font_size(text), INK, TextAlignH::Left, inner)?;
|
||||
let note = add_text(doc, id, text, STICKY_TEXT_SIZE, INK, TextAlignH::Left, inner)?;
|
||||
if !author.is_empty() {
|
||||
let a = add_text(doc, id, author, 10.0, AUTHOR_INK, TextAlignH::Left, inner)?;
|
||||
if let Some(n) = doc.node_mut(a) {
|
||||
|
||||
Reference in new issue
Block a user