Browse / github.com/storytold/vectorcraft / patch
G4: Type orientation menu unchecked for mixed vertical/horizontal selection
G4: Type orientation menu unchecked for mixed vertical/horizontal selection ## Summary - Type › Orientation menu checks use the existing `shared_text_flag` on `vertical` (both Horizontal and Vertical unchecked when the selection mixes orientations). ## Tests - `type_orientation_menu_unchecked_when_shared_vertical_none` in `crates/ui-egui/src/menus/tests.rs` - `type_orientation_menu_unchecked_for_three_object_mixed_selections` in `crates/ui-egui/src/menus/tests.rs` - `shared_text_flag_vertical_three_object_selections` in `crates/ui-egui/src/panels/character/tests.rs` ## Checklist - [x] `cargo xtask ci` passes (fmt, clippy, tests, assets, brands, layers, wasm). - [ ]
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- nrq6993-a11y (imported from pull request #4324, open)
- Base
443b31b13df3a7ab611c2fe1b95e73898ed74fdd- Size
- +56 −1 in 3 files
- Review
- pending
- Shared
- 2026-10-28
- Id
2d0b11025efa2c5371cd791d
How it went
No other operator has reported using it yet.
Diff
raw · crates/ui-egui/src/menus/state.rs crates/ui-egui/src/menus/tests.rs crates/ui-egui/src/panels/character/tests.rs
@@ -38,7 +38,7 @@ pub fn checked(app: &VectorcraftApp, id: &str, p: &Value) -> Option<bool> { }; Some(match id { "type.orientation.vertical" | "type.orientation.horizontal" => {- selected_text(false).is_some_and(|t| t.vertical == (id == "type.orientation.vertical"))+ crate::panels::character::shared_text_flag(app, |t| t.vertical) == Some(id == "type.orientation.vertical") } "type.opticalMarginAlignment" => crate::panels::character::shared_text_flag(app, |t| t.optical_margin) == Some(true), "view.outline" => v.outline,@@ -255,6 +255,43 @@ fn optical_margin_alignment_menu_unchecked_when_shared_flag_none() { assert_eq!(checked(&app, id, &Value::Null), Some(true)); } +/// Type › Orientation menu checks use `shared_text_flag`; mixed values leave both unchecked.+#[test]+fn type_orientation_menu_unchecked_when_shared_vertical_none() {+ let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), crate::Services::default());+ app.run("file.new", json!({})).unwrap();+ let h = app.run("text.create", json!({"x": 10, "y": 40, "text": "H"})).unwrap()["id"].clone();+ let v = app.run("text.create", json!({"x": 10, "y": 80, "text": "V", "vertical": true})).unwrap()["id"].clone();+ app.run("select.set", json!({"ids": [h, v]})).unwrap();+ assert_eq!(crate::panels::character::shared_text_flag(&app, |t| t.vertical), None);+ assert_eq!(checked(&app, "type.orientation.vertical", &Value::Null), Some(false));+ assert_eq!(checked(&app, "type.orientation.horizontal", &Value::Null), Some(false));+ app.run("select.set", json!({"ids": [v]})).unwrap();+ assert_eq!(checked(&app, "type.orientation.vertical", &Value::Null), Some(true));+ assert_eq!(checked(&app, "type.orientation.horizontal", &Value::Null), Some(false));+}++#[test]+fn type_orientation_menu_unchecked_for_three_object_mixed_selections() {+ let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), crate::Services::default());+ app.run("file.new", json!({})).unwrap();+ let v0 = app.run("text.create", json!({"x": 10, "y": 40, "text": "v0", "vertical": true})).unwrap()["id"].clone();+ let h1 = app.run("text.create", json!({"x": 10, "y": 80, "text": "h1"})).unwrap()["id"].clone();+ let h2 = app.run("text.create", json!({"x": 10, "y": 120, "text": "h2"})).unwrap()["id"].clone();+ app.run("select.set", json!({"ids": [v0.clone(), h1.clone(), h2.clone()]})).unwrap();+ assert_eq!(checked(&app, "type.orientation.vertical", &Value::Null), Some(false));+ assert_eq!(checked(&app, "type.orientation.horizontal", &Value::Null), Some(false));+ let h0 = app.run("text.create", json!({"x": 10, "y": 160, "text": "h0"})).unwrap()["id"].clone();+ let v1 = app.run("text.create", json!({"x": 10, "y": 200, "text": "v1", "vertical": true})).unwrap()["id"].clone();+ let v2 = app.run("text.create", json!({"x": 10, "y": 240, "text": "v2", "vertical": true})).unwrap()["id"].clone();+ app.run("select.set", json!({"ids": [h0.clone(), v1.clone(), v2.clone()]})).unwrap();+ assert_eq!(checked(&app, "type.orientation.vertical", &Value::Null), Some(false));+ assert_eq!(checked(&app, "type.orientation.horizontal", &Value::Null), Some(false));+ app.run("select.set", json!({"ids": [v0.clone(), v1.clone(), v2.clone()]})).unwrap();+ assert_eq!(checked(&app, "type.orientation.vertical", &Value::Null), Some(true));+ assert_eq!(checked(&app, "type.orientation.horizontal", &Value::Null), Some(false));+}+ #[test] fn panel_ids_are_case_insensitive_and_labels_work() { assert_eq!(normalize_panel("layers"), Some("layers"));@@ -512,6 +512,24 @@ fn shared_text_flag_optical_margin_three_object_selections() { assert_eq!(shared_text_flag(&app, |t| t.optical_margin), Some(true)); } +#[test]+fn shared_text_flag_vertical_three_object_selections() {+ let mut app = VectorcraftApp::new(Session::new(), Default::default());+ app.run("file.new", json!({})).unwrap();+ let v0 = app.run("text.create", json!({"x": 10, "y": 40, "text": "v0", "vertical": true})).unwrap()["id"].clone();+ let h1 = app.run("text.create", json!({"x": 10, "y": 80, "text": "h1"})).unwrap()["id"].clone();+ let h2 = app.run("text.create", json!({"x": 10, "y": 120, "text": "h2"})).unwrap()["id"].clone();+ app.run("select.set", json!({"ids": [v0.clone(), h1.clone(), h2.clone()]})).unwrap();+ assert_eq!(shared_text_flag(&app, |t| t.vertical), None);+ let h0 = app.run("text.create", json!({"x": 10, "y": 160, "text": "h0"})).unwrap()["id"].clone();+ let v1 = app.run("text.create", json!({"x": 10, "y": 200, "text": "v1", "vertical": true})).unwrap()["id"].clone();+ let v2 = app.run("text.create", json!({"x": 10, "y": 240, "text": "v2", "vertical": true})).unwrap()["id"].clone();+ app.run("select.set", json!({"ids": [h0.clone(), v1.clone(), v2.clone()]})).unwrap();+ assert_eq!(shared_text_flag(&app, |t| t.vertical), None);+ app.run("select.set", json!({"ids": [v0.clone(), v1.clone(), v2.clone()]})).unwrap();+ assert_eq!(shared_text_flag(&app, |t| t.vertical), Some(true));+}+ /// Small Caps, Superscript and Subscript buttons and menu items stay off when the selection mixes them. #[test] fn character_mixed_small_caps_and_position_show_off() {