| author | |
| committer | |
| log | 0fe456a8909d9b9991afbe28c28f915d031ca44f |
| tree | 2a4f6a8e8278499eb545761682cebed6895d558b |
| parent | a4a0ccf055b14aa599b027e96a679054fea6b5a2 |
| signature | Signed by SSH key SHA256:52mNGHRsVFBDED9IAX5pe+LRWUefqTbxEReunq21QvU |
Clover: the right-click menus' Theme, the Format menu's and palette's Customize
Theme and the Styles gallery's Customize all open the same dialog, so they and
the dialog share one name, and the Styles button's Aa icon; scoped, the dialog
reads Customize Font Styles for This Section. In the gallery it sits under a
rule, where OneNote 2010 keeps Clear Formatting, and in context menus it comes
last, under a rule. A gallery group can start under a rule, which More Symbols
gains too.
Assisted-by: claude-opus-5.59 files changed, 55 insertions(+), 16 deletions(-)
crates/snowbound/src/art.rs-2| ... | ... | @@ -110,7 +110,6 @@ pub const CLOSE_NOTEBOOK: &[&str] = art!( |
| 110 | 110 | pub const CODE: &[&str] = art!("icons/code"); |
| 111 | 111 | pub const COMMAND_PALETTE: &[&str] = art!("icons/palette", "icons/badge-command"); |
| 112 | 112 | pub const COPY_LINK: &[&str] = art!("icons/page", "icons/badge-link"); |
| 113 | pub const CUSTOMIZE_THEME: &[&str] = art!("icons/theme", "icons/badge-edit"); | |
| 114 | 113 | pub const CUSTOMIZE_TAGS: &[&str] = art!("icons/tag", "icons/badge-edit"); |
| 115 | 114 | pub const DELETE: &[&str] = art!("icons/delete"); |
| 116 | 115 | pub const EMPTY_RECYCLE_BIN: &[&str] = art!("icons/recycle-bin", "icons/badge-remove"); |
| ... | ... | @@ -195,7 +194,6 @@ pub const SNAP_TO_GRID: &[&str] = art!("icons/snap-to-grid"); |
| 195 | 194 | pub const STOP: &[&str] = art!("icons/stop"); |
| 196 | 195 | pub const SUBPAGE: &[&str] = art!("icons/subpage"); |
| 197 | 196 | pub const SYNC_NOW: &[&str] = art!("icons/sync-now"); |
| 198 | pub const THEME: &[&str] = art!("icons/theme"); | |
| 199 | 197 | pub const TO_DO: &[&str] = art!("icons/to-do"); |
| 200 | 198 | pub const UPDATE: &[&str] = art!("icons/update"); |
| 201 | 199 | pub const ZOOM_ACTUAL: &[&str] = art!("icons/zoom-actual"); |
crates/snowbound/src/background.rs+3| ... | ... | @@ -89,18 +89,21 @@ pub fn menu( |
| 89 | 89 | let groups = [ |
| 90 | 90 | ui::popup::Group { |
| 91 | 91 | heading: "Page Color", |
| 92 | ruled: false, | |
| 92 | 93 | cells: 2 + PAGE_COLORS.len(), |
| 93 | 94 | columns: COLUMNS, |
| 94 | 95 | size: SWATCH, |
| 95 | 96 | }, |
| 96 | 97 | ui::popup::Group { |
| 97 | 98 | heading: "Background", |
| 99 | ruled: false, | |
| 98 | 100 | cells: 2 + ART.len(), |
| 99 | 101 | columns: 3, |
| 100 | 102 | size: [TILE[0] + 8.0, TILE[1] + 8.0], |
| 101 | 103 | }, |
| 102 | 104 | ui::popup::Group { |
| 103 | 105 | heading: "Rule Lines", |
| 106 | ruled: false, | |
| 104 | 107 | cells: 1 + RULE_LINES.len(), |
| 105 | 108 | columns: COLUMNS, |
| 106 | 109 | size: [RULES; 2], |
crates/snowbound/src/commands.rs+1-1| ... | ... | @@ -596,7 +596,7 @@ pub const COMMANDS: &[Command] = &[ |
| 596 | 596 | row!(Id::Style(8), "Quote", NONE, NONE), |
| 597 | 597 | row!(Id::Style(9), "Code", NONE, NONE), |
| 598 | 598 | row!(Id::Style(10), "Normal", NONE, NONE), |
| 599 | row!(Id::Themes, "Customize Theme", NONE, NONE), | |
| 599 | row!(Id::Themes, "Customize Font Styles", NONE, NONE), | |
| 600 | 600 | row!(Id::CustomizeTags, "Customize Tags", NONE, NONE), |
| 601 | 601 | row!( |
| 602 | 602 | Id::RemoveTags, |
crates/snowbound/src/main.rs+3-1| ... | ... | @@ -5184,6 +5184,7 @@ fn list_gallery( |
| 5184 | 5184 | let groups = [(headings[0], recent.len()), (headings[1], count + 1)].map(|(heading, cells)| { |
| 5185 | 5185 | ui::popup::Group { |
| 5186 | 5186 | heading, |
| 5187 | ruled: false, | |
| 5187 | 5188 | cells, |
| 5188 | 5189 | columns: 5, |
| 5189 | 5190 | size, |
| ... | ... | @@ -5228,6 +5229,7 @@ fn pen_gallery( |
| 5228 | 5229 | const CELL: [f32; 2] = [40.0, 24.0]; |
| 5229 | 5230 | let groups = [ui::popup::Group { |
| 5230 | 5231 | heading: "Pens", |
| 5232 | ruled: false, | |
| 5231 | 5233 | cells: pens.len(), |
| 5232 | 5234 | columns: 5, |
| 5233 | 5235 | size: CELL, |
| ... | ... | @@ -5666,7 +5668,7 @@ fn artwork(id: commands::Id) -> Option<&'static [&'static str]> { |
| 5666 | 5668 | Cmd::Style(8) => art::QUOTE, |
| 5667 | 5669 | Cmd::Style(9) => art::CODE, |
| 5668 | 5670 | Cmd::Style(_) => art::NORMAL, |
| 5669 | Cmd::Themes => art::CUSTOMIZE_THEME, | |
| 5671 | Cmd::Themes => art::STYLES, | |
| 5670 | 5672 | Cmd::OpenShared => art::OPEN_SHARED, |
| 5671 | 5673 | Cmd::LiveShare => art::LIVE_SHARE, |
| 5672 | 5674 | Cmd::MarkdownShortcuts => art::MARKDOWN, |
crates/snowbound/src/menus.rs+11-5| ... | ... | @@ -151,7 +151,7 @@ impl Action { |
| 151 | 151 | Action::NewGroup => art::NEW_SECTION_GROUP, |
| 152 | 152 | Action::Reveal => art::FOLDER, |
| 153 | 153 | Action::Close => art::CLOSE_NOTEBOOK, |
| 154 | Action::Theme => art::THEME, | |
| 154 | Action::Theme => art::STYLES, | |
| 155 | 155 | Action::Colors => art::SECTION_COLOR, |
| 156 | 156 | Action::Sync => art::SYNC_NOW, |
| 157 | 157 | Action::NewNotebook => art::NEW_NOTEBOOK, |
| ... | ... | @@ -334,6 +334,11 @@ impl State { |
| 334 | 334 | (action, item) |
| 335 | 335 | }; |
| 336 | 336 | let nowhere = || self.destinations(target).is_empty(); |
| 337 | // Last on a page, section or notebook, under a rule. | |
| 338 | let styles = || { | |
| 339 | let title = commands::command(commands::Id::Themes).title; | |
| 340 | item(Action::Theme, title, false, true) | |
| 341 | }; | |
| 337 | 342 | match target { |
| 338 | 343 | // OneNote's Move or Copy takes a page out of the bin; nothing else changes it. |
| 339 | 344 | Target::Page { path, .. } if crate::recycle::binned(path) => vec![ |
| ... | ... | @@ -360,11 +365,11 @@ impl State { |
| 360 | 365 | item(Action::NewPage, "New Page", false, true), |
| 361 | 366 | // OneNote offers this beside New Page, which is a plain + here. |
| 362 | 367 | item(Action::NewSubpage, "New Subpage", false, false), |
| 363 | item(Action::Theme, "Theme", false, true), | |
| 364 | 368 | ]; |
| 365 | 369 | // Levels and versions are known once the section is open. |
| 366 | 370 | let Some(session) = self.session.as_ref().filter(|_| self.open(library, path)) |
| 367 | 371 | else { |
| 372 | actions.push(styles()); | |
| 368 | 373 | return actions; |
| 369 | 374 | }; |
| 370 | 375 | let pages = &session.pages; |
| ... | ... | @@ -393,6 +398,7 @@ impl State { |
| 393 | 398 | session.page_versions(*space).is_empty(), |
| 394 | 399 | true, |
| 395 | 400 | ), |
| 401 | styles(), | |
| 396 | 402 | ]); |
| 397 | 403 | actions |
| 398 | 404 | } |
| ... | ... | @@ -423,7 +429,7 @@ impl State { |
| 423 | 429 | section_file(library, path).is_none(), |
| 424 | 430 | false, |
| 425 | 431 | ), |
| 426 | item(Action::Theme, "Theme", false, false), | |
| 432 | styles(), | |
| 427 | 433 | ]); |
| 428 | 434 | } |
| 429 | 435 | actions |
| ... | ... | @@ -493,12 +499,11 @@ impl State { |
| 493 | 499 | library.folder().is_none(), |
| 494 | 500 | true, |
| 495 | 501 | ), |
| 496 | item(Action::Theme, "Theme", false, false), | |
| 497 | 502 | item( |
| 498 | 503 | Action::RecycleBin, |
| 499 | 504 | "Notebook Recycle Bin", |
| 500 | 505 | library.catalog().is_none(), |
| 501 | true, | |
| 506 | false, | |
| 502 | 507 | ), |
| 503 | 508 | item( |
| 504 | 509 | Action::Properties, |
| ... | ... | @@ -506,6 +511,7 @@ impl State { |
| 506 | 511 | library.catalog().is_none(), |
| 507 | 512 | false, |
| 508 | 513 | ), |
| 514 | styles(), | |
| 509 | 515 | ] |
| 510 | 516 | } |
| 511 | 517 | Target::Closed(_) | Target::Server(_) => { |
crates/snowbound/src/symbol.rs+2| ... | ... | @@ -82,12 +82,14 @@ pub fn gallery(ui: &mut Ui, id: Id, anchor: Anchor, symbols: &[char]) -> Option< |
| 82 | 82 | let groups = [ |
| 83 | 83 | ui::popup::Group { |
| 84 | 84 | heading: "", |
| 85 | ruled: false, | |
| 85 | 86 | cells: symbols.len(), |
| 86 | 87 | columns: 5, |
| 87 | 88 | size: [SIZE; 2], |
| 88 | 89 | }, |
| 89 | 90 | ui::popup::Group { |
| 90 | 91 | heading: "", |
| 92 | ruled: true, | |
| 91 | 93 | cells: 1, |
| 92 | 94 | columns: 1, |
| 93 | 95 | size: [5.0 * SIZE, 28.0], |
crates/snowbound/src/themes.rs+10-7| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | //! Style themes in the app (`resources/styles.md`): the page wears its own theme, else its |
| 2 | 2 | //! section's, else its notebook's, as its paragraph style objects; the Styles gallery |
| 3 | //! applies a style in the page's theme, and its Customize… opens the Themes dialog, which | |
| 4 | //! edits a notebook's own themes with a live preview and gives one to the page, the section | |
| 5 | //! or the notebook. | |
| 3 | //! applies a style in the page's theme, and its Customize Font Styles opens the dialog of | |
| 4 | //! that name, which edits a notebook's own themes with a live preview and gives one to the | |
| 5 | //! page, the section or the notebook. | |
| 6 | 6 | |
| 7 | 7 | use crate::{Library, State, filetime}; |
| 8 | 8 | use accesskit::Role; |
| ... | ... | @@ -255,12 +255,13 @@ impl State { |
| 255 | 255 | ..Spec::default() |
| 256 | 256 | }, |
| 257 | 257 | ); |
| 258 | let named = crate::commands::command(crate::commands::Id::Themes).title; | |
| 258 | 259 | if let Some(node) = ui.access(id()) { |
| 259 | node.set_label("Themes"); | |
| 260 | node.set_label(named); | |
| 260 | 261 | } |
| 261 | 262 | let title = match &dialog.targets[..] { |
| 262 | [(scope, _)] => format!("Theme for {}", scope.name()), | |
| 263 | _ => "Themes".to_owned(), | |
| 263 | [(scope, _)] => format!("{named} for {}", scope.name()), | |
| 264 | _ => named.to_owned(), | |
| 264 | 265 | }; |
| 265 | 266 | ui.leaf( |
| 266 | 267 | "title", |
| ... | ... | @@ -770,12 +771,14 @@ pub(crate) fn gallery( |
| 770 | 771 | .enumerate() |
| 771 | 772 | .map(|(at, (name, _))| ui::popup::Group { |
| 772 | 773 | heading: if at == 0 { &sheet.name } else { "" }, |
| 774 | ruled: false, | |
| 773 | 775 | cells: 1, |
| 774 | 776 | columns: 1, |
| 775 | 777 | size: row(shown_size(&sheet.styles[*name], GALLERY_LARGEST) * 1.25), |
| 776 | 778 | }) |
| 777 | 779 | .chain([ui::popup::Group { |
| 778 | 780 | heading: "", |
| 781 | ruled: true, | |
| 779 | 782 | cells: 1, |
| 780 | 783 | columns: 1, |
| 781 | 784 | size: row(16.0), |
| ... | ... | @@ -807,7 +810,7 @@ pub(crate) fn gallery( |
| 807 | 810 | "customize", |
| 808 | 811 | Spec { |
| 809 | 812 | size: [fill(), fill()], |
| 810 | text: Some("Customize"), | |
| 813 | text: Some(crate::commands::command(Cmd::Themes).title), | |
| 811 | 814 | ..Spec::default() |
| 812 | 815 | }, |
| 813 | 816 | ); |
crates/ui/src/popup.rs+24| ... | ... | @@ -1038,6 +1038,8 @@ pub fn table_picker(ui: &mut Ui, id: Id, anchor: Anchor, size: [usize; 2]) -> Op |
| 1038 | 1038 | #[derive(Clone, Copy, Debug)] |
| 1039 | 1039 | pub struct Group<'a> { |
| 1040 | 1040 | pub heading: &'a str, |
| 1041 | /// Starts under a rule, as a gallery's command after its choices. | |
| 1042 | pub ruled: bool, | |
| 1041 | 1043 | pub cells: usize, |
| 1042 | 1044 | pub columns: usize, |
| 1043 | 1045 | pub size: [f32; 2], |
| ... | ... | @@ -1096,7 +1098,29 @@ pub fn gallery( |
| 1096 | 1098 | width + 2.0 * ui.theme.menu().pad, |
| 1097 | 1099 | ); |
| 1098 | 1100 | let mut index = 0; |
| 1101 | let style = theme.menu(); | |
| 1099 | 1102 | for (number, group) in groups.iter().enumerate() { |
| 1103 | if group.ruled { | |
| 1104 | ui.open( | |
| 1105 | ("rule", number), | |
| 1106 | Spec { | |
| 1107 | size: [fill(), px(style.rule_band)], | |
| 1108 | ..Spec::default() | |
| 1109 | }, | |
| 1110 | ); | |
| 1111 | ui.leaf( | |
| 1112 | "line", | |
| 1113 | Spec { | |
| 1114 | flags: Flags::FLOAT, | |
| 1115 | size: [fill(), px(1.0)], | |
| 1116 | position: [0.0, (style.rule_band - 1.0) / 2.0], | |
| 1117 | inset: [style.rule_inset, 0.0, style.rule_inset, 0.0], | |
| 1118 | fill: Some(style.rule), | |
| 1119 | ..Spec::default() | |
| 1120 | }, | |
| 1121 | ); | |
| 1122 | ui.close(); | |
| 1123 | } | |
| 1100 | 1124 | if !group.heading.is_empty() { |
| 1101 | 1125 | ui.leaf( |
| 1102 | 1126 | ("heading", number), |
crates/ui/src/tests.rs+1| ... | ... | @@ -2911,6 +2911,7 @@ fn galleries_choose_across_their_groups_by_keys_and_clicks() { |
| 2911 | 2911 | let gallery = Id::ROOT.child("gallery"); |
| 2912 | 2912 | let groups = [("Recent", 2), ("Library", 5)].map(|(heading, cells)| popup::Group { |
| 2913 | 2913 | heading, |
| 2914 | ruled: false, | |
| 2914 | 2915 | cells, |
| 2915 | 2916 | columns: 3, |
| 2916 | 2917 | size: [30.0, 30.0], |