Type: Character Alignment — where smaller characters line up with a line's largest
Characters of different sizes on one line all sat on the Roman baseline.
Japanese layout usually lines them up by their ideographic em boxes
instead (a 16 pt 第一回 next to 32 pt 雅楽 centred on it, not sitting on
its baseline). The Character panel menu now has Character Alignment:
- `CharStyle.char_align`: Roman Baseline (as before, the default), or the
em box Top/Right, Center or Bottom/Left: a character smaller than the
line's largest moves so that its em box top, centre or bottom lines up
with the largest's (the em box from the font's vertical metrics, else
0.12 em below the baseline to 0.88 em above it). Vertical type the
same across the column (top → right). Written only when not Roman
Baseline.
- `text.setFormat {charAlign: "romanBaseline"|"emBoxTop"|"emBoxCenter"|
"emBoxBottom"}`; the menu shows the selection's setting; catalog rows
in ja and zh-hant.
- Not yet: aligning on the ICF (average character face) top and bottom.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
505f3bd7ae
commit
178ca03eba
|
|
@ -129,7 +129,7 @@ grade by behaviour against `plan/illustrator/`, not by whether a menu item exist
|
|||
- Pathfinder (10 exact curve booleans), Offset, Outline Stroke, Simplify, Clean Up, Split Into Grid, Divide Objects Below. Object › Path › Remove Anchor Points (`path.removeAnchors`) removes the direct-selected anchors without opening their paths (the Delete key still deletes them with their segments): the neighbours keep their handle directions and their facing handles are refitted so one cubic follows the two old segments, and straight sides stay straight. The Delete Anchor Point tool uses the same refit. The Control bar, the contextual task bar, the Properties quick actions and the canvas context menu offer it when anchors are selected.
|
||||
- Live effects with previewing dialogs: Distort & Transform, Path, Convert to Shape, 15 Warp styles, Round Corners, Scribble, Effect → Pathfinder (all 10 operations, live on groups; several loose objects are grouped first, in one undo step), Color Adjustments (Brightness/Contrast, Curves, Levels, Hue/Saturation, Shift to Color, Temperature/Tint, on vectors, live type and embedded images), and raster drop shadow, glows and feather. SVG and PDF export keep live effects (geometry baked; SVG raster effects as filters).
|
||||
- **Type:** Text Wrap, Type on a Path effects (Rainbow/Skew/3D Ribbon/Stair Step/Gravity), Character and Paragraph Styles (override-preserving redefine), Area Type Options (rows/columns/inset/first baseline), threaded text across any closed shapes, Fit Headline. Area type resizes like Illustrator's type areas: a bounding-box handle drag (Selection tool) or Area Type Options Width/Height size the frame and the text reflows at its size (threads too); Direct Selection drags a frame corner or edge (`text.reshapeArea`). Point type still scales. Variable fonts list every named instance as a style of their family (Figtree Light to Black and their italics, Bahnschrift, Segoe UI Variable), and the instance chosen is shaped, drawn, outlined and measured at its axis settings; PDF and SVG embed it as that instance. Variation axis sliders are not done. Hebrew and Arabic are laid out right to left with the Unicode bidirectional algorithm (embedded Latin and numbers keep their direction, lines put in visual order after wrapping) in point, area and path type, with caret, selection and arrow keys in visual order; each paragraph's direction comes from its first strong character unless Paragraph Direction sets it (Paragraph panel with Show Indic Options, `text.setFormat {direction}`), and new type aligns to the start of its direction. SVG export outlines right-to-left text.
|
||||
- **Interface languages, vertical type:** VectorCraft ▸ Language (or Preferences ▸ User Interface) picks Automatic (the system locale) or a registered language, persisted as `interfaceLanguage`. Translations come from per-language catalogs (`i18n/*.tsv`): Traditional and Simplified Chinese, Japanese and Spanish (neutral international Spanish, for every `es-*` locale) cover the whole interface, Czech and Brazilian Portuguese every menu label, Brazilian Portuguese the shell's `tl!` literals too (tested); untranslated text stays English. Japanese and Chinese glyphs come from the craft-fonts build input (release builds) or the installed fonts, Czech and Spanish ones from the bundled UI fonts. The Basic toolbar's Type button holds Vertical Type in its flyout. Vertical Type, Vertical Area Type and Vertical Type on a Path create vertical text (columns right to left, upright CJK glyphs and marks with `vert` alternates, Latin and longer numbers on their side, two- and three-digit numbers set as tate-chu-yoko in one em of the column (kept whole when justified), upright glyphs centred on the column (tracked or justified too), point type's anchor on the first column's centre line); kinsoku (the strict set) applies to horizontal and vertical Japanese, and justified Japanese lines spread their room between characters (not inside Latin words); Paragraph panel › Mojikumi Set (shown with Preferences › Type › Show East Asian Options, `text.setFormat {mojikumi}`): None or Line-end Punctuation Half Width (new type's default, as in Illustrator; older documents and imported text keep None) shares one half-em space between consecutive punctuation, sets a closing mark ending a line half width, and puts a quarter em between Japanese and Latin letters or digits; Paragraph panel menu › Top-to-Top / Bottom-to-Bottom Leading measures leading from em box top to top (area type's first line touches the frame) or from baseline to baseline; Type ▸ Type Orientation switches existing text; caret, selection, hit testing and arrow keys follow the writing direction. Vertical text exports to PDF as real text and to SVG as outlines.
|
||||
- **Interface languages, vertical type:** VectorCraft ▸ Language (or Preferences ▸ User Interface) picks Automatic (the system locale) or a registered language, persisted as `interfaceLanguage`. Translations come from per-language catalogs (`i18n/*.tsv`): Traditional and Simplified Chinese, Japanese and Spanish (neutral international Spanish, for every `es-*` locale) cover the whole interface, Czech and Brazilian Portuguese every menu label, Brazilian Portuguese the shell's `tl!` literals too (tested); untranslated text stays English. Japanese and Chinese glyphs come from the craft-fonts build input (release builds) or the installed fonts, Czech and Spanish ones from the bundled UI fonts. The Basic toolbar's Type button holds Vertical Type in its flyout. Vertical Type, Vertical Area Type and Vertical Type on a Path create vertical text (columns right to left, upright CJK glyphs and marks with `vert` alternates, Latin and longer numbers on their side, two- and three-digit numbers set as tate-chu-yoko in one em of the column (kept whole when justified), upright glyphs centred on the column (tracked or justified too), point type's anchor on the first column's centre line); kinsoku (the strict set) applies to horizontal and vertical Japanese, and justified Japanese lines spread their room between characters (not inside Latin words); Paragraph panel › Mojikumi Set (shown with Preferences › Type › Show East Asian Options, `text.setFormat {mojikumi}`): None or Line-end Punctuation Half Width (new type's default, as in Illustrator; older documents and imported text keep None) shares one half-em space between consecutive punctuation, sets a closing mark ending a line half width, and puts a quarter em between Japanese and Latin letters or digits; Paragraph panel menu › Top-to-Top / Bottom-to-Bottom Leading measures leading from em box top to top (area type's first line touches the frame) or from baseline to baseline; Character panel menu › Character Alignment lines characters smaller than the largest on their line up on the Roman baseline or the em box top/right, centre or bottom/left; Type ▸ Type Orientation switches existing text; caret, selection, hit testing and arrow keys follow the writing direction. Vertical text exports to PDF as real text and to SVG as outlines.
|
||||
- **Transparency:** opacity masks (clip/invert/disable/link), exported as SVG `<mask>` and PDF soft masks.
|
||||
- **Advanced art:** live Blends (steps/distance/smooth colour, editable spine, anchor-targeted Blend tool, faithful interpolation, knockout), Envelope Distort (warp/mesh/top object, Reset, full Envelope Options, mesh handles, Edit Contents; type, images, symbols, gradients, patterns and appearance distorted everywhere), Liquify tools with options and pen pressure, Puppet Warp with rotating pins, Perspective Grid with presets, movable planes and projected type (choosing a perspective tool shows the grid; Hide Grid hides it with the tool still chosen), Gradient Mesh, Shape Builder (stroke-only open paths and lines cut the regions they cross and enclose regions of their own; Alt deletes their pieces; filled open paths count as closed), Live Paint (every path an edge, open lines included), Image Trace (12 presets), pattern swatches with pattern editing mode, live Repeat (radial/grid/mirror).
|
||||
- **Paint and appearance (M3):**
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@ pub use setup::{Background, DocSetup, ExportText, GridSize, Quotes};
|
|||
pub use slices::{CellAlign, CellVAlign, Slice, SliceArea, SliceKind, SliceOptions, SliceSource};
|
||||
pub use style_libs::StyleLibrary;
|
||||
pub use text::{
|
||||
AreaOptions, CharPosition, CharStyle, FirstBaseline, Justify, LeadingModel, Mojikumi, ParaDirection, ParaStyle, PathEffect, ScriptMetrics,
|
||||
TabAlign, TabStop, TextKind, TextObject, TextRun, TextStyleDef, TextWrap, WrapShape,
|
||||
AreaOptions, CharAlign, CharPosition, CharStyle, FirstBaseline, Justify, LeadingModel, Mojikumi, ParaDirection, ParaStyle, PathEffect,
|
||||
ScriptMetrics, TabAlign, TabStop, TextKind, TextObject, TextRun, TextStyleDef, TextWrap, WrapShape,
|
||||
};
|
||||
pub use vectorcraft_color as color;
|
||||
pub use vectorcraft_geom as geom;
|
||||
|
|
|
|||
|
|
@ -86,6 +86,23 @@ pub struct CharStyle {
|
|||
/// size (Document Setup → Type → Small Caps); None = off.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub small_caps: Option<f64>,
|
||||
/// Character Alignment (Character panel menu): where characters smaller than the largest on
|
||||
/// their line line up with it.
|
||||
#[serde(default, rename = "charAlign", skip_serializing_if = "crate::skip::is_default")]
|
||||
pub char_align: CharAlign,
|
||||
}
|
||||
|
||||
/// Where a character smaller than the largest on its line lines up with it: on the Roman
|
||||
/// baseline, or at the top (right, in vertical type), centre or bottom (left) of the ideographic
|
||||
/// em boxes.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum CharAlign {
|
||||
#[default]
|
||||
RomanBaseline,
|
||||
EmBoxTop,
|
||||
EmBoxCenter,
|
||||
EmBoxBottom,
|
||||
}
|
||||
|
||||
/// Superscript or subscript proportions in percent of the font size (Document Setup → Type).
|
||||
|
|
@ -178,6 +195,7 @@ impl Default for CharStyle {
|
|||
stroke_miter_limit: 10.0,
|
||||
stroke_dash: None,
|
||||
position: CharPosition::Normal,
|
||||
char_align: CharAlign::RomanBaseline,
|
||||
small_caps: None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
|||
"Character / Paragraph",
|
||||
[],
|
||||
None,
|
||||
"{ids?|id?, kerning?: 1/1000 em|\"auto\", baselineShift?: pt, hScale?: %, vScale?: %, rotation?: deg, underline?, strikethrough?, allCaps?, smallCaps?: bool, position?: \"normal\"|\"superscript\"|\"subscript\" (sizes from Document Setup), leftIndent?, rightIndent?, firstLineIndent?, spaceBefore?, spaceAfter?: pt, hyphenate?: bool, mojikumi?: \"none\"|\"lineEndHalf\" (Japanese punctuation spacing), direction?: \"auto\"|\"leftToRight\"|\"rightToLeft\" (paragraph direction; auto: from each paragraph's first strong character), leadingModel?: \"romanBaseline\"|\"emBoxTop\" (leading measured baseline to baseline, or em box top to top)}",
|
||||
"{ids?|id?, kerning?: 1/1000 em|\"auto\", baselineShift?: pt, hScale?: %, vScale?: %, rotation?: deg, underline?, strikethrough?, allCaps?, smallCaps?: bool, position?: \"normal\"|\"superscript\"|\"subscript\" (sizes from Document Setup), leftIndent?, rightIndent?, firstLineIndent?, spaceBefore?, spaceAfter?: pt, hyphenate?: bool, mojikumi?: \"none\"|\"lineEndHalf\" (Japanese punctuation spacing), direction?: \"auto\"|\"leftToRight\"|\"rightToLeft\" (paragraph direction; auto: from each paragraph's first strong character), leadingModel?: \"romanBaseline\"|\"emBoxTop\" (leading measured baseline to baseline, or em box top to top), charAlign?: \"romanBaseline\"|\"emBoxTop\"|\"emBoxCenter\"|\"emBoxBottom\" (where characters smaller than the largest on their line line up with it)}",
|
||||
has_doc,
|
||||
set_format
|
||||
),
|
||||
|
|
@ -114,11 +114,22 @@ fn set_format(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
"mojikumi",
|
||||
"direction",
|
||||
"leadingModel",
|
||||
"charAlign",
|
||||
];
|
||||
if !keys.iter().any(|k| p.get(*k).is_some()) {
|
||||
return Err(bad(C, "nothing to change"));
|
||||
}
|
||||
let (position, small_caps) = super::docsetup::script_params(p, &s.doc()?.doc.setup, C)?;
|
||||
let char_align = match p.get("charAlign") {
|
||||
None => None,
|
||||
Some(v) => Some(match v.as_str() {
|
||||
Some("romanBaseline") => vectorcraft_doc::CharAlign::RomanBaseline,
|
||||
Some("emBoxTop") => vectorcraft_doc::CharAlign::EmBoxTop,
|
||||
Some("emBoxCenter") => vectorcraft_doc::CharAlign::EmBoxCenter,
|
||||
Some("emBoxBottom") => vectorcraft_doc::CharAlign::EmBoxBottom,
|
||||
_ => return Err(bad(C, "`charAlign` must be \"romanBaseline\", \"emBoxTop\", \"emBoxCenter\" or \"emBoxBottom\"")),
|
||||
}),
|
||||
};
|
||||
let mojikumi = match p.get("mojikumi") {
|
||||
None => None,
|
||||
Some(v) => Some(match v.as_str() {
|
||||
|
|
@ -179,6 +190,9 @@ fn set_format(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
if let Some(v) = small_caps {
|
||||
st.small_caps = v;
|
||||
}
|
||||
if let Some(v) = char_align {
|
||||
st.char_align = v;
|
||||
}
|
||||
}
|
||||
let para = &mut t.para;
|
||||
if let Some(v) = num("leftIndent") {
|
||||
|
|
|
|||
|
|
@ -433,6 +433,27 @@ mod area_tests {
|
|||
assert!(serde_json::to_value(&text(&s).para).unwrap().get("leading_model").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn character_alignment_is_a_character_attribute_saved_only_when_set() {
|
||||
use vectorcraft_doc::CharAlign;
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width": 400, "height": 400})).unwrap();
|
||||
let id = s.execute("text.create", &json!({"x": 10, "y": 50, "text": "雅楽"})).unwrap()["id"].as_u64().unwrap();
|
||||
let runs = |s: &Session| match &s.doc().unwrap().doc.node(NodeId(id)).unwrap().kind {
|
||||
NodeKind::Text(t) => t.runs.clone(),
|
||||
_ => panic!("text"),
|
||||
};
|
||||
assert_eq!(runs(&s)[0].style.char_align, CharAlign::RomanBaseline);
|
||||
assert!(serde_json::to_value(&runs(&s)[0].style).unwrap().get("charAlign").is_none());
|
||||
s.execute("select.set", &json!({"ids": [id]})).unwrap();
|
||||
assert!(s.execute("text.setFormat", &json!({"charAlign": "middle"})).is_err());
|
||||
s.execute("text.setFormat", &json!({"charAlign": "emBoxCenter"})).unwrap();
|
||||
assert!(runs(&s).iter().all(|r| r.style.char_align == CharAlign::EmBoxCenter));
|
||||
assert_eq!(serde_json::to_value(&runs(&s)[0].style).unwrap()["charAlign"], "emBoxCenter");
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert_eq!(runs(&s)[0].style.char_align, CharAlign::RomanBaseline);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_type_is_composed_with_line_end_half_width_punctuation() {
|
||||
use vectorcraft_doc::Mojikumi;
|
||||
|
|
|
|||
|
|
@ -320,6 +320,26 @@ fn space_japanese_and_latin(sg: &mut [SGlyph]) -> Vec<f64> {
|
|||
added
|
||||
}
|
||||
|
||||
/// The size of `g`'s em, in points.
|
||||
fn glyph_em(g: &SGlyph) -> f64 {
|
||||
g.face.units_per_em() * g.sy
|
||||
}
|
||||
|
||||
/// How far up (line space) Character Alignment `a` moves glyph `g` on a line whose largest em is
|
||||
/// `line_em`: the glyph's em box top, centre or bottom onto the line's (the em box running from
|
||||
/// its centre less half an em to its centre plus half an em above the baseline). Nothing on the
|
||||
/// Roman baseline, or for the line's largest characters.
|
||||
fn align_shift(g: &SGlyph, a: vectorcraft_doc::CharAlign, line_em: f64) -> f64 {
|
||||
use vectorcraft_doc::CharAlign;
|
||||
let k = match a {
|
||||
CharAlign::RomanBaseline => return 0.0,
|
||||
CharAlign::EmBoxTop => 0.5,
|
||||
CharAlign::EmBoxCenter => 0.0,
|
||||
CharAlign::EmBoxBottom => -0.5,
|
||||
};
|
||||
(g.face.ideographic_centre() + k) * (line_em - glyph_em(g)).max(0.0)
|
||||
}
|
||||
|
||||
/// The length an upright glyph takes down the column before tracking and justification: its
|
||||
/// vertical advance (the font's vertical metrics), else its advance, at least one em.
|
||||
fn upright_cell(g: &SGlyph) -> f64 {
|
||||
|
|
@ -1056,6 +1076,8 @@ fn flow(cx: &mut Ctx<'_>, paras: &[Range<usize>], para: &ParaStyle, regions: Opt
|
|||
};
|
||||
let li = cx.out.lines.len();
|
||||
let glyph_start = cx.out.glyphs.len();
|
||||
// Character Alignment lines smaller characters up with the line's largest em box.
|
||||
let line_em = sg.get(i..end).map_or(0.0, |line| line.iter().map(glyph_em).fold(0.0, f64::max));
|
||||
let mut x_end = start_x;
|
||||
// Tab stops are measured from the frame's left edge (point type: the origin).
|
||||
let tab_origin = if regions.is_some() { x0 } else { 0.0 };
|
||||
|
|
@ -1088,7 +1110,8 @@ fn flow(cx: &mut Ctx<'_>, paras: &[Range<usize>], para: &ParaStyle, regions: Opt
|
|||
adv += per_gap;
|
||||
}
|
||||
}
|
||||
cx.emit(g, Affine::translate((x, baseline)), Point::new(x, baseline), 0.0, adv, li);
|
||||
let y = baseline - align_shift(g, cx.style_at(g.byte).char_align, line_em);
|
||||
cx.emit(g, Affine::translate((x, y)), Point::new(x, y), 0.0, adv, li);
|
||||
x += adv;
|
||||
if j < trimmed {
|
||||
x_end = x;
|
||||
|
|
|
|||
|
|
@ -557,3 +557,31 @@ fn em_box_top_leading_hangs_lines_from_the_line_above() {
|
|||
em.lines[1].baseline - em.lines[0].baseline
|
||||
);
|
||||
}
|
||||
|
||||
/// Character Alignment: a 20 pt character next to a 40 pt one lines its em box top, centre or
|
||||
/// bottom up with the big one's (the em box from 0.12 em below the baseline to 0.88 em above it,
|
||||
/// in fonts without vertical metrics), or stays on the baseline; in vertical type the same across
|
||||
/// the column (top → right).
|
||||
#[test]
|
||||
fn character_alignment_lines_small_characters_up_with_the_largest_em_box() {
|
||||
use vectorcraft_doc::{CharAlign, TextRun};
|
||||
for vertical_type in [false, true] {
|
||||
let place = |a: CharAlign| {
|
||||
let mut t = point("", style(40.0));
|
||||
t.vertical = vertical_type;
|
||||
t.runs = vec![
|
||||
TextRun { text: "大".into(), style: style(40.0) },
|
||||
TextRun { text: "小".into(), style: CharStyle { char_align: a, ..style(20.0) } },
|
||||
];
|
||||
let l = layout(db(), &t);
|
||||
// How far the small character's origin sits above the big one's (to the right, vertical).
|
||||
let (big, small) = (l.glyphs[0].origin, l.glyphs[1].origin);
|
||||
if vertical_type { small.x - big.x } else { big.y - small.y }
|
||||
};
|
||||
let near = |a: f64, b: f64| (a - b).abs() < 0.01;
|
||||
assert!(near(place(CharAlign::RomanBaseline), 0.0), "vertical {vertical_type}");
|
||||
assert!(near(place(CharAlign::EmBoxTop), 0.88 * 20.0), "top: {}", place(CharAlign::EmBoxTop));
|
||||
assert!(near(place(CharAlign::EmBoxCenter), 0.38 * 20.0), "centre: {}", place(CharAlign::EmBoxCenter));
|
||||
assert!(near(place(CharAlign::EmBoxBottom), -0.12 * 20.0), "bottom: {}", place(CharAlign::EmBoxBottom));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,11 @@
|
|||
All Scripts すべての文字
|
||||
Any Kind すべての種類
|
||||
Bottom-to-Bottom Leading 欧文ベースライン基準の行送り
|
||||
Character Alignment 文字揃え
|
||||
Decorative 装飾
|
||||
Em Box Bottom/Left 仮想ボディの下 / 左
|
||||
Em Box Center 中央
|
||||
Em Box Top/Right 仮想ボディの上 / 右
|
||||
Favorites お気に入り
|
||||
Japanese 日本語
|
||||
Join Our Discord Discord に参加
|
||||
|
|
@ -20,6 +24,7 @@
|
|||
Mojikumi Set 文字組み
|
||||
Latin 欧文
|
||||
Monospaced 等幅
|
||||
Roman Baseline 欧文ベースライン
|
||||
Rounded 丸ゴシック
|
||||
Sans Serif / Gothic ゴシック・サンセリフ
|
||||
Script / Brush 筆書体・スクリプト
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -314,6 +314,7 @@
|
|||
Channel 色版
|
||||
Character 字元
|
||||
Character / Paragraph 字元/段落
|
||||
Character Alignment 字元對齊
|
||||
Character Rotation 字元旋轉
|
||||
Character Set: 字元集:
|
||||
Character Style 字元樣式
|
||||
|
|
@ -766,6 +767,9 @@
|
|||
Ellipse Tool 橢圓工具
|
||||
Ellipse… 橢圓形…
|
||||
Ellipsis 刪節號
|
||||
Em Box Bottom/Left 全形字框下 / 左
|
||||
Em Box Center 全形字框中央
|
||||
Em Box Top/Right 全形字框上 / 右
|
||||
Em Dash 長破折號
|
||||
Em Space 全形空格
|
||||
Embed 嵌入
|
||||
|
|
@ -2100,6 +2104,7 @@
|
|||
Right-to-Left Paragraph Direction 從右至左段落方向
|
||||
Right: 右:
|
||||
Rise… 上升…
|
||||
Roman Baseline 羅馬基線
|
||||
Roman Hanging Punctuation 羅馬懸掛標點
|
||||
Rotate 旋轉
|
||||
Rotate 90° CW 順時針旋轉 90°
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -395,6 +395,24 @@ pub fn menu(app: &mut VectorcraftApp, ui: &mut Ui) {
|
|||
menu_item(ui, tl!(l), false, false);
|
||||
}
|
||||
ui.separator();
|
||||
// Character Alignment: where characters smaller than the largest on their line line up.
|
||||
let align = s.as_ref().map(|s| s.char_align);
|
||||
ui.add_enabled_ui(has, |ui| {
|
||||
ui.menu_button(tl!("Character Alignment"), |ui| {
|
||||
use vectorcraft_doc::CharAlign;
|
||||
for (label, a, key) in [
|
||||
(tl!("Roman Baseline"), CharAlign::RomanBaseline, "romanBaseline"),
|
||||
(tl!("Em Box Top/Right"), CharAlign::EmBoxTop, "emBoxTop"),
|
||||
(tl!("Em Box Center"), CharAlign::EmBoxCenter, "emBoxCenter"),
|
||||
(tl!("Em Box Bottom/Left"), CharAlign::EmBoxBottom, "emBoxBottom"),
|
||||
] {
|
||||
if menu_item(ui, label, true, align == Some(a)) {
|
||||
format(app, json!({"charAlign": key}));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
ui.separator();
|
||||
for l in ["Standard Vertical Roman Alignment", "Tate-chu-yoko", "Fractional Widths", "System Layout", "No Break"] {
|
||||
menu_item(ui, tl!(l), false, l == "Fractional Widths");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue