mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-14 19:26:56 -04:00
Find Font and Glyphs: pick fonts from the font menu (#358 follow-up)
Both switch from widgets::font_dropdown to font_menu::font_menu, so they get the same samples, favourites and filters as the Character and Properties panels. They only pick a font: the new font_menu::picked returns the choice and toggles stars, and never previews on the document. Follow-up to #339 as suggested in #364. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01BRE8ZD3p8QgYctENhnJDz3
This commit is contained in:
1 parent
18cbe007b8
commit
1d5e9cb239
4 files changed
+76
-21
No files matched your search
@@ -4,10 +4,10 @@
|
||||
use egui::Ui;
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::VectorcraftApp;
|
||||
use crate::state::Dialog;
|
||||
use crate::theme::{self, Tokens};
|
||||
use crate::widgets;
|
||||
use crate::{VectorcraftApp, font_menu};
|
||||
|
||||
/// Open the dialog.
|
||||
pub fn open(app: &mut VectorcraftApp) {
|
||||
@@ -34,6 +34,7 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) {
|
||||
let Some(mut d) = app.ui.dialog.clone() else { return };
|
||||
let t = Tokens::get(ctx);
|
||||
let list = fonts(app);
|
||||
let sample = font_menu::sample_text(app);
|
||||
let mut close = false;
|
||||
let mut act: Option<&str> = None;
|
||||
egui::Area::new(egui::Id::new("modal-dim")).order(egui::Order::Middle).fixed_pos(egui::pos2(0.0, 0.0)).show(ctx, |ui| {
|
||||
@@ -71,9 +72,11 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) {
|
||||
widgets::subheader(ui, tl!("Replace With Font"));
|
||||
let fam = d.str("family");
|
||||
ui.horizontal(|ui| {
|
||||
if let Some(f) = widgets::font_dropdown(ui, "ff-family", &fam, 220.0) {
|
||||
// Picks the font only: nothing is previewed on the document.
|
||||
let pick = font_menu::font_menu(ui, "ff-family", &fam, 220.0, sample.as_deref(), font_menu::MenuLook::of(app));
|
||||
if let Some((f, style)) = font_menu::picked(app, pick) {
|
||||
d.fields.insert("family".into(), json!(f));
|
||||
d.fields.insert("style".into(), json!(""));
|
||||
d.fields.insert("style".into(), json!(style.unwrap_or_default()));
|
||||
}
|
||||
let styles = vectorcraft_text::FontDb::global().styles(&d.str("family"));
|
||||
// "(closest)" is ours; the font's style names are shown as they are.
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
//! The font family menu of the Character and Properties panels: a search field over every family
|
||||
//! available, each row the family's name and a sample of the selected text set in it. The row
|
||||
//! under the pointer or reached with ↑/↓ previews its font on the selected text (one live
|
||||
//! interaction, nothing in the history); a click or Enter applies it as one step, Escape or
|
||||
//! closing the menu puts the text back. A star marks a favourite family, and the ★ filter lists
|
||||
//! only those. Preferences › Type › Enable in-menu font previews and Font Preview Size turn the
|
||||
//! samples off or size the rows.
|
||||
//! The font family menu of the Character, Properties and Glyphs panels and Find Font's Replace
|
||||
//! With: a search field over every family available, each row the family's name and a sample of
|
||||
//! the selected text set in it. In the Character and Properties panels the row under the pointer
|
||||
//! or reached with ↑/↓ previews its font on the selected text (one live interaction, nothing in
|
||||
//! the history); a click or Enter applies it as one step, Escape or closing the menu puts the text
|
||||
//! back. The Glyphs panel and Find Font only pick a font ([`picked`]): nothing is previewed on the
|
||||
//! document. A star marks a favourite family, and the ★ filter lists only those. Preferences ›
|
||||
//! Type › Enable in-menu font previews and Font Preview Size turn the samples off or size the
|
||||
//! rows.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
@@ -637,15 +639,7 @@ pub(crate) fn apply(app: &mut VectorcraftApp, ctx: &egui::Context, pick: FontPic
|
||||
app.sync_views();
|
||||
}
|
||||
}
|
||||
FontPick::Favorite(f) => {
|
||||
let favs = &mut app.ui.favorite_fonts;
|
||||
match favs.iter().position(|x| x.eq_ignore_ascii_case(&f)) {
|
||||
Some(i) => {
|
||||
favs.remove(i);
|
||||
}
|
||||
None => favs.push(f),
|
||||
}
|
||||
}
|
||||
FontPick::Favorite(f) => toggle_favorite(app, f),
|
||||
FontPick::Chosen(f, style) => {
|
||||
if previewing {
|
||||
app.session.cancel_interaction().ok();
|
||||
@@ -658,6 +652,31 @@ pub(crate) fn apply(app: &mut VectorcraftApp, ctx: &egui::Context, pick: FontPic
|
||||
}
|
||||
}
|
||||
|
||||
/// Star `family`, or take its star off (any case).
|
||||
fn toggle_favorite(app: &mut VectorcraftApp, family: String) {
|
||||
let favs = &mut app.ui.favorite_fonts;
|
||||
match favs.iter().position(|x| x.eq_ignore_ascii_case(&family)) {
|
||||
Some(i) => {
|
||||
favs.remove(i);
|
||||
}
|
||||
None => favs.push(family),
|
||||
}
|
||||
}
|
||||
|
||||
/// For a font menu that only picks a font and never changes the document (Find Font's Replace
|
||||
/// With, the Glyphs panel): the family (and style) chosen, if any. A star is toggled here; the
|
||||
/// highlighted row is not previewed.
|
||||
pub(crate) fn picked(app: &mut VectorcraftApp, pick: Option<FontPick>) -> Option<(String, Option<String>)> {
|
||||
match pick? {
|
||||
FontPick::Chosen(f, style) => Some((f, style)),
|
||||
FontPick::Favorite(f) => {
|
||||
toggle_favorite(app, f);
|
||||
None
|
||||
}
|
||||
FontPick::Preview(..) | FontPick::EndPreview => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// The command that sets font `family` (and `style`, else the closest the family has) on what the
|
||||
/// menus act on.
|
||||
fn font_command(app: &VectorcraftApp, family: &str, style: Option<&str>) -> (&'static str, serde_json::Value) {
|
||||
|
||||
@@ -198,8 +198,12 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
.color(t.text_dim),
|
||||
);
|
||||
ui.horizontal(|ui| {
|
||||
if let Some(f) = widgets::font_dropdown(ui, "gl-family", &family, (w * 0.6).max(80.0)) {
|
||||
let st = db.face(&f, "Regular").map_or_else(|| "Regular".into(), |face| face.style.clone());
|
||||
// Picks the font the panel browses only: nothing is previewed on the document.
|
||||
let sample = crate::font_menu::sample_text(app);
|
||||
let look = crate::font_menu::MenuLook::of(app);
|
||||
let pick = crate::font_menu::font_menu(ui, "gl-family", &family, (w * 0.6).max(80.0), sample.as_deref(), look);
|
||||
if let Some((f, style)) = crate::font_menu::picked(app, pick) {
|
||||
let st = style.unwrap_or_else(|| db.face(&f, "Regular").map_or_else(|| "Regular".into(), |face| face.style.clone()));
|
||||
set_pstate(ui.ctx(), "gl-font", Some((f, st)));
|
||||
}
|
||||
let styles = db.styles(&family);
|
||||
|
||||
@@ -241,3 +241,32 @@ fn stars_mark_favourites_and_the_preferences_size_the_rows() {
|
||||
let look = MenuLook::of(&app);
|
||||
assert!(!look.samples && look.row > 24.0, "Font Preview Size and Enable in-menu font previews");
|
||||
}
|
||||
|
||||
/// Find Font's Replace With and the Glyphs panel only pick a font: their menu's highlight never
|
||||
/// previews on the document, a choice is just returned, and a star is still toggled.
|
||||
#[test]
|
||||
fn menus_that_only_pick_a_font_leave_the_document_alone() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 300, "height": 200})).unwrap();
|
||||
let id = app.session.execute("text.create", &json!({"x": 20, "y": 50, "text": "Gagaku", "font": "Inter"})).unwrap()["id"].as_u64().unwrap();
|
||||
app.session.execute("select.set", &json!({"ids": [id]})).unwrap();
|
||||
let font = |app: &VectorcraftApp| match &app.session.active().unwrap().doc.node(vectorcraft_doc::NodeId(id)).unwrap().kind {
|
||||
NodeKind::Text(t) => t.first_style().font_family,
|
||||
_ => String::new(),
|
||||
};
|
||||
let steps = |app: &VectorcraftApp| app.session.active().unwrap().history.undo.len();
|
||||
let before = steps(&app);
|
||||
use crate::font_menu::picked;
|
||||
assert_eq!(picked(&mut app, None), None);
|
||||
assert_eq!(picked(&mut app, Some(FontPick::Preview("Source Serif 4".into(), None))), None);
|
||||
assert_eq!(picked(&mut app, Some(FontPick::EndPreview)), None);
|
||||
assert_eq!(
|
||||
picked(&mut app, Some(FontPick::Chosen("Source Serif 4".into(), Some("Bold".into())))),
|
||||
Some(("Source Serif 4".to_string(), Some("Bold".to_string())))
|
||||
);
|
||||
assert_eq!((font(&app), steps(&app)), ("Inter".to_string(), before), "nothing previewed or applied on the text");
|
||||
assert_eq!(picked(&mut app, Some(FontPick::Favorite("Inter".into()))), None);
|
||||
assert_eq!(app.ui.favorite_fonts, ["Inter"], "a star is still toggled");
|
||||
assert_eq!(picked(&mut app, Some(FontPick::Favorite("inter".into()))), None);
|
||||
assert!(app.ui.favorite_fonts.is_empty());
|
||||
}
|
||||
Reference in new issue
Block a user