From 43b2c1e8f4b6433ef7efac523cf0f35a789a8b26 Mon Sep 17 00:00:00 2001 From: DonislawDev Date: Wed, 23 Sep 2026 17:54:31 +0200 Subject: [PATCH 1/4] gui: a sentence's padding taken off by its layout rather than by a theme override inkTight wrapped every sentence that wraps - an error area under each field, the status line, captions - in a container.ThemeOverride. Fyne gives an override a new scope at construction, at CreateRenderer and at every Refresh, and keys its parsed fonts by scope, so every rebuild of a screen followed by a new string in one of those labels parsed another ~7.4 MB set of fonts that nothing frees. Measured in the real window, interleaved: 26 sets after visiting the tabs, 19 of them this override's; without it 7, and the live heap there 205 MB -> 64 MB. The layout gives the label its inner padding outside the room it is handed, so the words land and wrap where a label with no inner padding puts them. All 28 stored screens are pixel for pixel the same (the guard's tolerance is 0 on amd64 and it rewrote no picture); their trees change from an override to a container. Co-Authored-By: Claude Opus 5.5 --- internal/guard/testdata/screens/about.xml | 2078 ++++++++--------- internal/guard/testdata/screens/catalogue.xml | 1086 ++++----- .../screens/generate-chosen-by-key.xml | 28 +- .../testdata/screens/generate-chosen.xml | 28 +- .../guard/testdata/screens/generate-empty.xml | 42 +- .../testdata/screens/generate-focused.xml | 28 +- .../testdata/screens/generate-hovered.xml | 46 +- .../screens/generate-menu-hovered.xml | 28 +- .../testdata/screens/generate-menu-keyed.xml | 28 +- .../guard/testdata/screens/generate-menu.xml | 28 +- .../screens/generate-refused-both.xml | 58 +- .../screens/generate-refused-setting.xml | 42 +- .../testdata/screens/generate-refused.xml | 48 +- .../screens/generate-switch-by-key.xml | 28 +- .../guard/testdata/screens/generate-typed.xml | 42 +- .../testdata/screens/generate-unchecked.xml | 28 +- internal/guard/testdata/screens/generate.xml | 28 +- .../testdata/screens/preset-many-settings.xml | 140 +- .../testdata/screens/preset-menu-setting.xml | 98 +- .../guard/testdata/screens/preset-menu.xml | 112 +- .../guard/testdata/screens/preset-refused.xml | 116 +- internal/guard/testdata/screens/preset.xml | 112 +- .../testdata/screens/recipe-contents.xml | 42 +- .../testdata/screens/recipe-on-a-preset.xml | 28 +- .../recipe-refused-with-one-batch-filled.xml | 64 +- .../guard/testdata/screens/recipe-refused.xml | 64 +- .../testdata/screens/recipe-two-batches.xml | 28 +- internal/guard/testdata/screens/recipe.xml | 28 +- internal/gui/parts/words.go | 49 +- 29 files changed, 2006 insertions(+), 2569 deletions(-) diff --git a/internal/guard/testdata/screens/about.xml b/internal/guard/testdata/screens/about.xml index 60dfad9..50012c6 100644 --- a/internal/guard/testdata/screens/about.xml +++ b/internal/guard/testdata/screens/about.xml @@ -33,26 +33,22 @@ - - - - - Testing Files Generator 0.3.0 - + + + + Testing Files Generator 0.3.0 - - + + - - - - - Generate test files, and know how the system under test should react to them. - + + + + Generate test files, and know how the system under test should react to them. - - + + @@ -63,41 +59,35 @@ • - - - - - Choose a preset, or fill in one batch on the first screen. - - - - + + + + Choose a preset, or fill in one batch on the first screen. + + + • - - - - - Press Generate. The files and a manifest land in the output folder. - - - - + + + + Press Generate. The files and a manifest land in the output folder. + + + • - - - - - Point your test at the manifest. For every file it says what the system under test should do with it - accept it, reject it - or sanitize it - or records the outcome as unspecified, where the right answer belongs to the application's own - policy. - - - - + + + + Point your test at the manifest. For every file it says what the system under test should do with it - accept it, reject it + or sanitize it - or records the outcome as unspecified, where the right answer belongs to the application's own + policy. + + + @@ -110,28 +100,26 @@ Licence - - - - - Testing Files Generator - Copyright (C) 2026 DonislawDev - - Released under the GNU General Public License, version 3. The full text is at - https://www.gnu.org/licenses/gpl-3.0.html, and in the LICENSE file if you have the source or the full release. - - There is no warranty, to the extent the law allows. - - The files you generate are yours. Generated files, recipes and manifests are output of this program and not derived - works of it, so this licence does not reach them. You can generate fixtures, commit them and ship them inside a closed - source product with no obligation of any kind. - - Code from other projects is compiled into this program. Their licences and copyright notices are in - THIRD-PARTY-NOTICES.md, which comes with the source and with the full release. - + + + + Testing Files Generator + Copyright (C) 2026 DonislawDev + + Released under the GNU General Public License, version 3. The full text is at + https://www.gnu.org/licenses/gpl-3.0.html, and in the LICENSE file if you have the source or the full release. + + There is no warranty, to the extent the law allows. + + The files you generate are yours. Generated files, recipes and manifests are output of this program and not derived + works of it, so this licence does not reach them. You can generate fixtures, commit them and ship them inside a closed + source product with no obligation of any kind. + + Code from other projects is compiled into this program. Their licences and copyright notices are in + THIRD-PARTY-NOTICES.md, which comes with the source and with the full release. - - + + @@ -142,15 +130,13 @@ Support - - - - - Opens the support page in your browser. The tool is free and stays free - this pays for the time that goes into it. - + + + + Opens the support page in your browser. The tool is free and stays free - this pays for the time that goes into it. - - + + @@ -158,15 +144,13 @@ Donate - - - - - https://donislawdev.com/support/ - + + + + https://donislawdev.com/support/ - - + + @@ -179,904 +163,718 @@ - - - - - Go runtime and standard library - - - - - - - - - BSD-3-Clause - - - - - - - - - Copyright 2009 The Go Authors - - - - + + + + Go runtime and standard library + + + + + + + BSD-3-Clause + + + + + + + Copyright 2009 The Go Authors + + + - - - - - fyne.io/fyne/v2 - - - - - - - - - BSD-3-Clause - - - - - - - - - (C) 2018 Fyne.io developers (see AUTHORS) - - - - + + + + fyne.io/fyne/v2 + + + + + + + BSD-3-Clause + + + + + + + (C) 2018 Fyne.io developers (see AUTHORS) + + + - - - - - fyne.io/systray - - - - - - - - - Apache-2.0 - - - - - - - - - 2014 Brave New Software Project, Inc. - - - - + + + + fyne.io/systray + + + + + + + Apache-2.0 + + + + + + + 2014 Brave New Software Project, Inc. + + + - - - - - github.com/BurntSushi/toml - - - - - - - - - MIT - - - - - - - - - (c) 2013 TOML authors - - - - + + + + github.com/BurntSushi/toml + + + + + + + MIT + + + + + + + (c) 2013 TOML authors + + + - - - - - github.com/FyshOS/fancyfs - - - - - - - - - BSD-3-Clause - - - - - - - - - (C) 2025 FyshOS developers (see AUTHORS) - - - - + + + + github.com/FyshOS/fancyfs + + + + + + + BSD-3-Clause + + + + + + + (C) 2025 FyshOS developers (see AUTHORS) + + + - - - - - github.com/anthonynsimon/bild - - - - - - - - - MIT - - - - - - - - - (c) 2021 Anthony Najjar Simon - - - - + + + + github.com/anthonynsimon/bild + + + + + + + MIT + + + + + + + (c) 2021 Anthony Najjar Simon + + + - - - - - github.com/clipperhouse/uax29/v2 - - - - - - - - - MIT - - - - - - - - - (c) 2020 Matt Sherman - - - - + + + + github.com/clipperhouse/uax29/v2 + + + + + + + MIT + + + + + + + (c) 2020 Matt Sherman + + + - - - - - github.com/fsnotify/fsnotify - - - - - - - - - BSD-3-Clause - - - - - - - - - Copyright 2012 The Go Authors - - - - + + + + github.com/fsnotify/fsnotify + + + + + + + BSD-3-Clause + + + + + + + Copyright 2012 The Go Authors + + + - - - - - github.com/fyne-io/image - - - - - - - - - BSD-3-Clause - - - - - - - - - (c) 2022, Fyne.io - - - - + + + + github.com/fyne-io/image + + + + + + + BSD-3-Clause + + + + + + + (c) 2022, Fyne.io + + + - - - - - github.com/fyne-io/oksvg - - - - - - - - - BSD-3-Clause - - - - - - - - - (c) 2018, Steven R Wiley - - - - + + + + github.com/fyne-io/oksvg + + + + + + + BSD-3-Clause + + + + + + + (c) 2018, Steven R Wiley + + + - - - - - github.com/gen2brain/gav1d - - - - - - - - - BSD-2-Clause - - - - - - - - - (c) 2018-2025 VideoLAN and dav1d authors, (c) 2016 Alliance - for Open Media - - - - + + + + github.com/gen2brain/gav1d + + + + + + + BSD-2-Clause + + + + + + + (c) 2018-2025 VideoLAN and dav1d authors, (c) 2016 Alliance + for Open Media + + + - - - - - github.com/gen2brain/jxl - - - - - - - - - BSD-3-Clause - - - - - - - - - (c) the JPEG XL Project Authors - - - - + + + + github.com/gen2brain/jxl + + + + + + + BSD-3-Clause + + + + + + + (c) the JPEG XL Project Authors + + + - - - - - github.com/go-gl/gl - - - - - - - - - MIT - - - - - - - - - (c) 2014 Eric Woroshow - - - - + + + + github.com/go-gl/gl + + + + + + + MIT + + + + + + + (c) 2014 Eric Woroshow + + + - - - - - github.com/go-gl/glfw/v3.4/glfw - - - - - - - - - BSD-3-Clause - - - - - - - - - (c) 2012 The glfw3-go Authors. All rights reserved. - - - - + + + + github.com/go-gl/glfw/v3.4/glfw + + + + + + + BSD-3-Clause + + + + + + + (c) 2012 The glfw3-go Authors. All rights reserved. + + + - - - - - github.com/go-text/render - - - - - - - - - BSD-3-Clause - - - - - - - - - 2021 The go-text authors - - - - + + + + github.com/go-text/render + + + + + + + BSD-3-Clause + + + + + + + 2021 The go-text authors + + + - - - - - github.com/go-text/typesetting - - - - - - - - - BSD-3-Clause - - - - - - - - - 2021 The go-text authors - - - - + + + + github.com/go-text/typesetting + + + + + + + BSD-3-Clause + + + + + + + 2021 The go-text authors + + + - - - - - github.com/goccy/go-yaml - - - - - - - - - MIT - - - - - - - - - (c) 2019 Masaaki Goshima - - - - + + + + github.com/goccy/go-yaml + + + + + + + MIT + + + + + + + (c) 2019 Masaaki Goshima + + + - - - - - github.com/godbus/dbus/v5 - - - - - - - - - BSD-2-Clause - - - - - - - - - (c) 2013, Georg Reinke (), Google - - - - + + + + github.com/godbus/dbus/v5 + + + + + + + BSD-2-Clause + + + + + + + (c) 2013, Georg Reinke (), Google + + + - - - - - github.com/jeandeaual/go-locale - - - - - - - - - MIT - - - - - - - - - (c) 2020 Alexis Jeandeau - - - - + + + + github.com/jeandeaual/go-locale + + + + + + + MIT + + + + + + + (c) 2020 Alexis Jeandeau + + + - - - - - github.com/jsummers/gobmp - - - - - - - - - MIT - - - - - - - - - (c) 2012-2015 Jason Summers - - - - + + + + github.com/jsummers/gobmp + + + + + + + MIT + + + + + + + (c) 2012-2015 Jason Summers + + + - - - - - github.com/mattn/go-runewidth - - - - - - - - - MIT - - - - - - - - - (c) 2016 Yasuhiro Matsumoto - - - - + + + + github.com/mattn/go-runewidth + + + + + + + MIT + + + + + + + (c) 2016 Yasuhiro Matsumoto + + + - - - - - github.com/nfnt/resize - - - - - - - - - ISC - - - - - - - - - (c) 2012, Jan Schlicht - - - - + + + + github.com/nfnt/resize + + + + + + + ISC + + + + + + + (c) 2012, Jan Schlicht + + + - - - - - github.com/nicksnyder/go-i18n/v2 - - - - - - - - - MIT - - - - - - - - - (c) 2014 Nick Snyder https://github.com/nicksnyder - - - - + + + + github.com/nicksnyder/go-i18n/v2 + + + + + + + MIT + + + + + + + (c) 2014 Nick Snyder https://github.com/nicksnyder + + + - - - - - github.com/rymdport/portal - - - - - - - - - Apache-2.0 - - - - - - - - - - - - - + + + + github.com/rymdport/portal + + + + + + + Apache-2.0 + + + + + + + + + + - - - - - github.com/srwiley/oksvg - - - - - - - - - BSD-3-Clause - - - - - - - - - (c) 2018, Steven R Wiley - - - - + + + + github.com/srwiley/oksvg + + + + + + + BSD-3-Clause + + + + + + + (c) 2018, Steven R Wiley + + + - - - - - github.com/srwiley/rasterx - - - - - - - - - BSD-3-Clause - - - - - - - - - (c) 2018, Steven R Wiley - - - - + + + + github.com/srwiley/rasterx + + + + + + + BSD-3-Clause + + + + + + + (c) 2018, Steven R Wiley + + + - - - - - github.com/yuin/goldmark - - - - - - - - - MIT - - - - - - - - - (c) 2019 Yusuke Inuzuka - - - - + + + + github.com/yuin/goldmark + + + + + + + MIT + + + + + + + (c) 2019 Yusuke Inuzuka + + + - - - - - golang.org/x/image - - - - - - - - - BSD-3-Clause - - - - - - - - - 2009 The Go Authors. - - - - + + + + golang.org/x/image + + + + + + + BSD-3-Clause + + + + + + + 2009 The Go Authors. + + + - - - - - golang.org/x/net - - - - - - - - - BSD-3-Clause - - - - - - - - - 2009 The Go Authors. - - - - + + + + golang.org/x/net + + + + + + + BSD-3-Clause + + + + + + + 2009 The Go Authors. + + + - - - - - golang.org/x/sys - - - - - - - - - BSD-3-Clause - - - - - - - - - 2009 The Go Authors. - - - - + + + + golang.org/x/sys + + + + + + + BSD-3-Clause + + + + + + + 2009 The Go Authors. + + + - - - - - golang.org/x/text - - - - - - - - - BSD-3-Clause - - - - - - - - - Copyright 2009 The Go Authors - - - - + + + + golang.org/x/text + + + + + + + BSD-3-Clause + + + + + + + Copyright 2009 The Go Authors + + + @@ -1091,237 +889,189 @@ - - - - - DejaVu Sans Mono for Powerline - - - - - - - - - Bitstream-Vera - - - - - - - - - Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. - DejaVu changes are in public domain - - - - + + + + DejaVu Sans Mono for Powerline + + + + + + + Bitstream-Vera + + + + + + + Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. + DejaVu changes are in public domain + + + - - - - - EmojiOne Color - - - - - - - - - MIT - - - - - - - - - Copyright 2016 Adobe Systems Incorporated - - - - + + + + EmojiOne Color + + + + + + + MIT + + + + + + + Copyright 2016 Adobe Systems Incorporated + + + - - - - - Fyne icon set - - - - - - - - - BSD-3-Clause - - - - - - - - - (C) 2018 Fyne.io developers (see AUTHORS) - - - - + + + + Fyne icon set + + + + + + + BSD-3-Clause + + + + + + + (C) 2018 Fyne.io developers (see AUTHORS) + + + - - - - - Fyne shaders - - - - - - - - - BSD-3-Clause - - - - - - - - - (C) 2018 Fyne.io developers (see AUTHORS) - - - - + + + + Fyne shaders + + + + + + + BSD-3-Clause + + + + + + + (C) 2018 Fyne.io developers (see AUTHORS) + + + - - - - - Fyne translations - - - - - - - - - BSD-3-Clause - - - - - - - - - (C) 2018 Fyne.io developers (see AUTHORS) - - - - + + + + Fyne translations + + + + + + + BSD-3-Clause + + + + + + + (C) 2018 Fyne.io developers (see AUTHORS) + + + - - - - - Inter - - - - - - - - - OFL-1.1 - - - - - - - - - Copyright 2016 The Inter Project Authors - - - - + + + + Inter + + + + + + + OFL-1.1 + + + + + + + Copyright 2016 The Inter Project Authors + + + - - - - - Inter Symbols - - - - - - - - - OFL-1.1 - - - - - - - - - (c) 2020 The Inter Project Authors - - - - + + + + Inter Symbols + + + + + + + OFL-1.1 + + + + + + + (c) 2020 The Inter Project Authors + + + - - - - - Noto Sans - - - - - - - - - OFL-1.1 - - - - - - - - - Copyright 2015 Google Inc. All Rights Reserved. - - - - + + + + Noto Sans + + + + + + + OFL-1.1 + + + + + + + Copyright 2015 Google Inc. All Rights Reserved. + + + @@ -1336,36 +1086,30 @@ - - - - - Mesa 3D, llvmpipe software - renderer 26.2.0 - - - - - - - - - MIT AND Apache-2.0 WITH - LLVM-exception AND BSL-1.0 - - - - - - - - - Copyright (C) 1999-2007 Brian Paul, - Copyright (C) 2008 VMware, Inc. - - - - + + + + Mesa 3D, llvmpipe software + renderer 26.2.0 + + + + + + + MIT AND Apache-2.0 WITH + LLVM-exception AND BSL-1.0 + + + + + + + Copyright (C) 1999-2007 Brian Paul, + Copyright (C) 2008 VMware, Inc. + + + diff --git a/internal/guard/testdata/screens/catalogue.xml b/internal/guard/testdata/screens/catalogue.xml index 5450baf..e60b98c 100644 --- a/internal/guard/testdata/screens/catalogue.xml +++ b/internal/guard/testdata/screens/catalogue.xml @@ -4,15 +4,13 @@ - - - - - Catalogue - + + + + Catalogue - - + + @@ -1889,15 +1887,13 @@ - - - - - the first screen - + + + + the first screen - - + + @@ -2038,15 +2034,13 @@ - - - - - a size of 3 B is below the smallest png, which is 73 B - + + + + a size of 3 B is below the smallest png, which is 73 B - - + + @@ -2324,15 +2318,13 @@ - - - - - Anything - + + + + Anything - - + + @@ -2883,16 +2875,14 @@ - - - - - 10mb The exact size every file will have, to the byte. - Units count in 1024s, so 10mb is 10 485 760 B. - + + + + 10mb The exact size every file will have, to the byte. + Units count in 1024s, so 10mb is 10 485 760 B. - - + + @@ -2930,15 +2920,13 @@ - - - - - size 3 B is below the smallest png, which is 73 B - + + + + size 3 B is below the smallest png, which is 73 B - - + + @@ -2952,16 +2940,14 @@ - - - - - Write a label inside each generated file, including the ones that are far too small to hold it. Write a label inside each - generated file, including the ones that are far too small to hold it - + + + + Write a label inside each generated file, including the ones that are far too small to hold it. Write a label inside each + generated file, including the ones that are far too small to hold it - - + + @@ -2975,15 +2961,13 @@ - - - - - AVIF cannot be smaller than 311 B. Requested: 1 B - + + + + AVIF cannot be smaller than 311 B. Requested: 1 B - - + + @@ -3097,15 +3081,13 @@ - - - - - inside the fold - + + + + inside the fold - - + + @@ -3243,15 +3225,13 @@ - - - - - inside the inner fold - + + + + inside the inner fold - - + + @@ -3348,15 +3328,13 @@ - - - - - inside the inner fold - + + + + inside the inner fold - - + + @@ -3406,15 +3384,13 @@ - - - - - inside the inner fold - + + + + inside the inner fold - - + + @@ -3460,15 +3436,13 @@ - - - - - inside the fold - + + + + inside the fold - - + + @@ -3513,15 +3487,13 @@ - - - - - inside the fold - + + + + inside the fold - - + + @@ -3566,15 +3538,13 @@ - - - - - inside the fold - + + + + inside the fold - - + + @@ -3647,15 +3617,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -3688,15 +3656,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -3730,15 +3696,13 @@ - - - - - Typically finds - + + + + Typically finds - - + + @@ -3750,15 +3714,13 @@ - - - - - Every file has exactly the size you ask for, to the byte, or the run refuses before writing anything. - + + + + Every file has exactly the size you ask for, to the byte, or the run refuses before writing anything. - - + + @@ -3793,39 +3755,33 @@ • - - - - - Upload validators - + + + + Upload validators - - + + • - - - - - Size limits - + + + + Size limits - - + + • - - - - - Archive handling - + + + + Archive handling - - + + @@ -3842,28 +3798,24 @@ • - - - - - One line - + + + + One line - - + + • - - - - - Write a label inside each generated file, including the ones that are far too small to hold it Write a label inside each - generated file, including the ones that are far too small to hold it - + + + + Write a label inside each generated file, including the ones that are far too small to hold it Write a label inside each + generated file, including the ones that are far too small to hold it - - + + @@ -3899,97 +3851,79 @@ - - - - - fyne.io/fyne/v2 - + + + + fyne.io/fyne/v2 - - - - - - - BSD-3-Clause - + + + + + + BSD-3-Clause - - - - - - - (C) 2018 Fyne.io developers (see - AUTHORS) - + + + + + + (C) 2018 Fyne.io developers (see + AUTHORS) - - + + - - - - - Mesa 3D, llvmpipe software - renderer 26.2.0 - + + + + Mesa 3D, llvmpipe software + renderer 26.2.0 - - - - - - - MIT AND Apache-2.0 WITH - LLVM-exception AND BSL-1.0 - + + + + + + MIT AND Apache-2.0 WITH + LLVM-exception AND BSL-1.0 - - - - - - - Copyright (C) 1999-2007 Brian Paul, - Copyright (C) 2008 VMware, Inc. - + + + + + + Copyright (C) 1999-2007 Brian Paul, + Copyright (C) 2008 VMware, Inc. - - + + - - - - - golang.org/x/text - + + + + golang.org/x/text - - - - - - - BSD-3-Clause - + + + + + + BSD-3-Clause - - - - - - - Write a label inside each generated - file, including the ones that are far too - small to hold it - + + + + + + Write a label inside each generated + file, including the ones that are far too + small to hold it - - + + @@ -4004,34 +3938,28 @@ - - - - - Write a label inside each generated file, including the ones that are far too sma… - + + + + Write a label inside each generated file, including the ones that are far too sma… - - + + Write a label inside each generated file, including the ones that are far too small to hold it - - - - - Write a label inside each generated file, including the ones that are far too small to hold it - + + + + Write a label inside each generated file, including the ones that are far too small to hold it - - - - - - - Write a label inside each generated file, including the ones that are far too small to hold it - + + + + + + Write a label inside each generated file, including the ones that are far too small to hold it - - + + @@ -4420,15 +4348,13 @@ - - - - - size 3 B is below the smallest png, which is 73 B - + + + + size 3 B is below the smallest png, which is 73 B - - + + @@ -4457,16 +4383,14 @@ - - - - - Write a label inside each generated file, including the ones that are far too small to - hold it - + + + + Write a label inside each generated file, including the ones that are far too small to + hold it - - + + @@ -4668,15 +4592,13 @@ - - - - - The ladder of surfaces - + + + + The ladder of surfaces - - + + @@ -4838,15 +4760,13 @@ - - - - - The inks - + + + + The inks - - + + @@ -4939,15 +4859,13 @@ - - - - - What carries meaning - + + + + What carries meaning - - + + @@ -5086,15 +5004,13 @@ - - - - - What the pointer, a press and the keyboard do - + + + + What the pointer, a press and the keyboard do - - + + @@ -5256,15 +5172,13 @@ - - - - - What is written on a filled face - + + + + What is written on a filled face - - + + @@ -5376,15 +5290,13 @@ - - - - - The ladder of surfaces - + + + + The ladder of surfaces - - + + @@ -5546,15 +5458,13 @@ - - - - - The inks - + + + + The inks - - + + @@ -5647,15 +5557,13 @@ - - - - - What carries meaning - + + + + What carries meaning - - + + @@ -5794,15 +5702,13 @@ - - - - - What the pointer, a press and the keyboard do - + + + + What the pointer, a press and the keyboard do - - + + @@ -5964,15 +5870,13 @@ - - - - - What is written on a filled face - + + + + What is written on a filled face - - + + @@ -6078,136 +5982,114 @@ • - - - - - Choice - a value: one row of an open list, read back by a guard - + + + + Choice - a value: one row of an open list, read back by a guard - - + + • - - - - - Detail - data: the longer explanation of a field and the sheet it opens on - + + + + Detail - data: the longer explanation of a field and the sheet it opens on - - + + • - - - - - Field - the model of one row of a form, drawn by Fields - + + + + Field - the model of one row of a form, drawn by Fields - - + + • - - - - - Built - a value: what building a field comes to, handed to the registry in one piece - + + + + Built - a value: what building a field comes to, handed to the registry in one piece - - + + • - - - - - Tab - data: one screen and the word that leads to it, drawn by Tabs - + + + + Tab - data: one screen and the word that leads to it, drawn by Tabs - - + + • - - - - - Look - an enum: which face a Button wears, every value drawn under Button - + + + + Look - an enum: which face a Button wears, every value drawn under Button - - + + • - - - - - PointerFocus - a piece inside a control, knowing what put the keyboard there - no picture of its own - + + + + PointerFocus - a piece inside a control, knowing what put the keyboard there - no picture of its own - - + + • - - - - - Returnable - an interface: a control the window can tell it is coming back to the front, nothing of its own to draw - + + + + Returnable - an interface: a control the window can tell it is coming back to the front, nothing of its own to draw - - + + • - - - - - Shortcuts - a keyboard map: nothing to draw, and saying so is the point of this row - + + + + Shortcuts - a keyboard map: nothing to draw, and saying so is the point of this row - - + + • - - - - - GroupKind - an enum: what a group of settings is about, every value drawn under Folding as the colour of its rail - + + + + GroupKind - an enum: what a group of settings is about, every value drawn under Folding as the colour of its rail - - + + • - - - - - NameTap - an invisible target over the name beside a box to tick, so pressing the name ticks the box - nothing of its - own to draw - + + + + NameTap - an invisible target over the name beside a box to tick, so pressing the name ticks the box - nothing of its + own to draw - - + + @@ -6223,207 +6105,173 @@ • - - - - - Column - stacks children at one gap of the scale - + + + + Column - stacks children at one gap of the scale - - + + • - - - - - Row - puts fields side by side - + + + + Row - puts fields side by side - - + + • - - - - - FieldColumn - the column a screen refills at run time, stacked like a section - + + + + FieldColumn - the column a screen refills at run time, stacked like a section - - + + • - - - - - Indented - the same left edge as the fields inside a panel - + + + + Indented - the same left edge as the fields inside a panel - - + + • - - - - - Sized - one width, given - + + + + Sized - one width, given - - + + • - - - - - Numeric - the width a number needs - + + + + Numeric - the width a number needs - - + + • - - - - - Text - the width a short piece of text needs - a name, a template, a file name - + + + + Text - the width a short piece of text needs - a name, a template, a file name - - + + • - - - - - Padded - one distance of the scale round its content - + + + + Padded - one distance of the scale round its content - - + + • - - - - - Stacked - panels one under another - + + + + Stacked - panels one under another - - + + • - - - - - Screen - the readable width round a head and its sections - + + + + Screen - the readable width round a head and its sections - - + + • - - - - - BesideFields - the room to the right of the column of names - + + + + BesideFields - the room to the right of the column of names - - + + • - - - - - WithRoomForARun - the room under a form for the bar to speak into - + + + + WithRoomForARun - the room under a form for the bar to speak into - - + + • - - - - - Flush - a label kept by a screen, on the edge every other word stands on - + + + + Flush - a label kept by a screen, on the edge every other word stands on - - + + • - - - - - Clear - a shape that takes room and draws nothing - + + + + Clear - a shape that takes room and draws nothing - - + + • - - - - - Grid - lays a section's fields in columns, each taking the columns its value needs - drawn under Section - + + + + Grid - lays a section's fields in columns, each taking the columns its value needs - drawn under Section - - + + • - - - - - Wide - marks something that takes a whole row of a Grid - + + + + Wide - marks something that takes a whole row of a Grid - - + + • - - - - - ButtonRow - buttons side by side, one gap of the scale apart and centred - drawn under Section - + + + + ButtonRow - buttons side by side, one gap of the scale apart and centred - drawn under Section - - + + diff --git a/internal/guard/testdata/screens/generate-chosen-by-key.xml b/internal/guard/testdata/screens/generate-chosen-by-key.xml index 53378a3..a74e1b1 100644 --- a/internal/guard/testdata/screens/generate-chosen-by-key.xml +++ b/internal/guard/testdata/screens/generate-chosen-by-key.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -462,15 +460,13 @@ - - - - - 1 file · 10.0 MB (10 485 760 B) · png · will go to /tfg/out - + + + + 1 file · 10.0 MB (10 485 760 B) · png · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/generate-chosen.xml b/internal/guard/testdata/screens/generate-chosen.xml index 59cab24..5195493 100644 --- a/internal/guard/testdata/screens/generate-chosen.xml +++ b/internal/guard/testdata/screens/generate-chosen.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -462,15 +460,13 @@ - - - - - 1 file · 10.0 MB (10 485 760 B) · png · will go to /tfg/out - + + + + 1 file · 10.0 MB (10 485 760 B) · png · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/generate-empty.xml b/internal/guard/testdata/screens/generate-empty.xml index db2047c..9e5d459 100644 --- a/internal/guard/testdata/screens/generate-empty.xml +++ b/internal/guard/testdata/screens/generate-empty.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -180,15 +178,13 @@ - - - - - target "files" asks for 0 files. Ask for at least one - + + + + target "files" asks for 0 files. Ask for at least one - - + + @@ -474,15 +470,13 @@ - - - - - 0 files · 0 B · avif · will go to /tfg/out - + + + + 0 files · 0 B · avif · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/generate-focused.xml b/internal/guard/testdata/screens/generate-focused.xml index 04c979f..3887349 100644 --- a/internal/guard/testdata/screens/generate-focused.xml +++ b/internal/guard/testdata/screens/generate-focused.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -463,15 +461,13 @@ - - - - - 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - + + + + 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/generate-hovered.xml b/internal/guard/testdata/screens/generate-hovered.xml index 90c189a..b47a7fe 100644 --- a/internal/guard/testdata/screens/generate-hovered.xml +++ b/internal/guard/testdata/screens/generate-hovered.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -462,15 +460,13 @@ - - - - - 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - + + + + 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - - + + @@ -497,17 +493,15 @@ - - - - - Exact size of every file. Units count in 1024s, so - 10mb is 10485760 bytes. A plain number is a count - of bytes. - + + + + Exact size of every file. Units count in 1024s, so + 10mb is 10485760 bytes. A plain number is a count + of bytes. - - + + diff --git a/internal/guard/testdata/screens/generate-menu-hovered.xml b/internal/guard/testdata/screens/generate-menu-hovered.xml index 6cc8440..2459e7f 100644 --- a/internal/guard/testdata/screens/generate-menu-hovered.xml +++ b/internal/guard/testdata/screens/generate-menu-hovered.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -462,15 +460,13 @@ - - - - - 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - + + + + 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/generate-menu-keyed.xml b/internal/guard/testdata/screens/generate-menu-keyed.xml index 200cfe0..df788a6 100644 --- a/internal/guard/testdata/screens/generate-menu-keyed.xml +++ b/internal/guard/testdata/screens/generate-menu-keyed.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -462,15 +460,13 @@ - - - - - 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - + + + + 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/generate-menu.xml b/internal/guard/testdata/screens/generate-menu.xml index 40fa0b6..187206a 100644 --- a/internal/guard/testdata/screens/generate-menu.xml +++ b/internal/guard/testdata/screens/generate-menu.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -462,15 +460,13 @@ - - - - - 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - + + + + 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/generate-refused-both.xml b/internal/guard/testdata/screens/generate-refused-both.xml index a327525..d75eb80 100644 --- a/internal/guard/testdata/screens/generate-refused-both.xml +++ b/internal/guard/testdata/screens/generate-refused-both.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -154,15 +152,13 @@ - - - - - Size "abc" has no number: write something like 10mb or 1048576 - + + + + Size "abc" has no number: write something like 10mb or 1048576 - - + + @@ -191,16 +187,14 @@ - - - - - How many files is "many", which is not a whole number. - Write the digits out, such as 1 or 500 - + + + + How many files is "many", which is not a whole number. + Write the digits out, such as 1 or 500 - - + + @@ -486,15 +480,13 @@ - - - - - Files will go to /tfg/out - + + + + Files will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/generate-refused-setting.xml b/internal/guard/testdata/screens/generate-refused-setting.xml index 696f034..62dfbb9 100644 --- a/internal/guard/testdata/screens/generate-refused-setting.xml +++ b/internal/guard/testdata/screens/generate-refused-setting.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -331,15 +329,13 @@ - - - - - png: Width cannot be "99999" - it takes a whole number of pixels from 1 to 20000 - + + + + png: Width cannot be "99999" - it takes a whole number of pixels from 1 to 20000 - - + + @@ -544,15 +540,13 @@ - - - - - 1 file · 10.0 MB (10 485 760 B) · png · will go to /tfg/out - + + + + 1 file · 10.0 MB (10 485 760 B) · png · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/generate-refused.xml b/internal/guard/testdata/screens/generate-refused.xml index 2b3bdfd..17ed15c 100644 --- a/internal/guard/testdata/screens/generate-refused.xml +++ b/internal/guard/testdata/screens/generate-refused.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -154,18 +152,16 @@ - - - - - AVIF cannot be smaller than 311 B - the smallest picture this format draws codes to 303 - B at worst, and the file always carries a free box, which costs 8 B even when it holds - nothing. Requested: 1 B. Ask for 311 B or more, or set a smaller width and height, or a - lower quality - + + + + AVIF cannot be smaller than 311 B - the smallest picture this format draws codes to 303 + B at worst, and the file always carries a free box, which costs 8 B even when it holds + nothing. Requested: 1 B. Ask for 311 B or more, or set a smaller width and height, or a + lower quality - - + + @@ -484,15 +480,13 @@ - - - - - 1 file · 1 B · avif · will go to /tfg/out - + + + + 1 file · 1 B · avif · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/generate-switch-by-key.xml b/internal/guard/testdata/screens/generate-switch-by-key.xml index 4b17e1b..5c725fc 100644 --- a/internal/guard/testdata/screens/generate-switch-by-key.xml +++ b/internal/guard/testdata/screens/generate-switch-by-key.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -462,15 +460,13 @@ - - - - - 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - + + + + 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/generate-typed.xml b/internal/guard/testdata/screens/generate-typed.xml index e31c12d..f602f26 100644 --- a/internal/guard/testdata/screens/generate-typed.xml +++ b/internal/guard/testdata/screens/generate-typed.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -153,15 +151,13 @@ - - - - - Size "abc" has no number: write something like 10mb or 1048576 - + + + + Size "abc" has no number: write something like 10mb or 1048576 - - + + @@ -473,15 +469,13 @@ - - - - - Files will go to /tfg/out - + + + + Files will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/generate-unchecked.xml b/internal/guard/testdata/screens/generate-unchecked.xml index a3f14b0..d7bc9db 100644 --- a/internal/guard/testdata/screens/generate-unchecked.xml +++ b/internal/guard/testdata/screens/generate-unchecked.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -461,15 +459,13 @@ - - - - - 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - + + + + 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/generate.xml b/internal/guard/testdata/screens/generate.xml index 6dd1326..5471be6 100644 --- a/internal/guard/testdata/screens/generate.xml +++ b/internal/guard/testdata/screens/generate.xml @@ -36,15 +36,13 @@ - - - - - Single batch - + + + + Single batch - - + + @@ -462,15 +460,13 @@ - - - - - 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - + + + + 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/preset-many-settings.xml b/internal/guard/testdata/screens/preset-many-settings.xml index 3b16f3d..55b0364 100644 --- a/internal/guard/testdata/screens/preset-many-settings.xml +++ b/internal/guard/testdata/screens/preset-many-settings.xml @@ -36,15 +36,13 @@ - - - - - Presets - + + + + Presets - - + + @@ -113,96 +111,80 @@ - - - - - Does my upload form take what it should and turn the rest away? - + + + + Does my upload form take what it should and turn the rest away? - - - - - - - Typically finds: - + + + + + + Typically finds: - - + + • - - - - - a limit enforced in the browser and not on the server - + + + + a limit enforced in the browser and not on the server - - + + • - - - - - an SVG or an HTML file taken for a picture or for plain text, which is a way to get a script past a form - + + + + an SVG or an HTML file taken for a picture or for plain text, which is a way to get a script past a form - - + + • - - - - - a file checked by its extension and never opened, so a PDF named .jpg goes through - + + + + a file checked by its extension and never opened, so a PDF named .jpg goes through - - + + • - - - - - a form that reads the whole body into memory before it looks at how big it is - + + + + a form that reads the whole body into memory before it looks at how big it is - - + + • - - - - - an upload named PHOTO.JPG turned away where photo.jpg is taken, or the other way round - + + + + an upload named PHOTO.JPG turned away where photo.jpg is taken, or the other way round - - + + • - - - - - a name with spaces, brackets or characters outside ASCII written to disk unchanged - + + + + a name with spaces, brackets or characters outside ASCII written to disk unchanged - - + + @@ -532,15 +514,13 @@ - - - - - 71 files · 115.1 MB (120 639 488 B) · 6 formats · will go to /tfg/out - + + + + 71 files · 115.1 MB (120 639 488 B) · 6 formats · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/preset-menu-setting.xml b/internal/guard/testdata/screens/preset-menu-setting.xml index 42fcc20..42d36c4 100644 --- a/internal/guard/testdata/screens/preset-menu-setting.xml +++ b/internal/guard/testdata/screens/preset-menu-setting.xml @@ -36,15 +36,13 @@ - - - - - Presets - + + + + Presets - - + + @@ -113,60 +111,50 @@ - - - - - Is a size limit enforced exactly where it is declared? - + + + + Is a size limit enforced exactly where it is declared? - - - - - - - Typically finds: - + + + + + + Typically finds: - - + + • - - - - - off by one errors at the limit - + + + + off by one errors at the limit - - + + • - - - - - MB confused with MiB, which is 4.8 per cent and enough to let a file through that should not pass - + + + + MB confused with MiB, which is 4.8 per cent and enough to let a file through that should not pass - - + + • - - - - - a limit enforced in the browser and not on the server - + + + + a limit enforced in the browser and not on the server - - + + @@ -435,15 +423,13 @@ - - - - - 7 files · 70.0 MB (73 400 320 B) · pdf · will go to /tfg/out - + + + + 7 files · 70.0 MB (73 400 320 B) · pdf · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/preset-menu.xml b/internal/guard/testdata/screens/preset-menu.xml index cda8f82..35f04ad 100644 --- a/internal/guard/testdata/screens/preset-menu.xml +++ b/internal/guard/testdata/screens/preset-menu.xml @@ -36,15 +36,13 @@ - - - - - Presets - + + + + Presets - - + + @@ -113,72 +111,60 @@ - - - - - Does a file that is valid and as small as the format allows get through? - + + + + Does a file that is valid and as small as the format allows get through? - - - - - - - Typically finds: - + + + + + + Typically finds: - - + + • - - - - - a valid file turned away for being too small, where the check counts bytes instead of reading them - + + + + a valid file turned away for being too small, where the check counts bytes instead of reading them - - + + • - - - - - an empty file that brings the reader down rather than being reported - + + + + an empty file that brings the reader down rather than being reported - - + + • - - - - - a picture one pixel wide that divides by zero on the way to a thumbnail - + + + + a picture one pixel wide that divides by zero on the way to a thumbnail - - + + • - - - - - storage that reads nought bytes as a failed upload and keeps retrying - + + + + storage that reads nought bytes as a failed upload and keeps retrying - - + + @@ -379,15 +365,13 @@ - - - - - 28 files · 31.9 KB (32 667 B) · 26 formats · will go to /tfg/out - + + + + 28 files · 31.9 KB (32 667 B) · 26 formats · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/preset-refused.xml b/internal/guard/testdata/screens/preset-refused.xml index 9b359ba..c3c7434 100644 --- a/internal/guard/testdata/screens/preset-refused.xml +++ b/internal/guard/testdata/screens/preset-refused.xml @@ -36,15 +36,13 @@ - - - - - Presets - + + + + Presets - - + + @@ -113,60 +111,50 @@ - - - - - Is a size limit enforced exactly where it is declared? - + + + + Is a size limit enforced exactly where it is declared? - - - - - - - Typically finds: - + + + + + + Typically finds: - - + + • - - - - - off by one errors at the limit - + + + + off by one errors at the limit - - + + • - - - - - MB confused with MiB, which is 4.8 per cent and enough to let a file through that should not pass - + + + + MB confused with MiB, which is 4.8 per cent and enough to let a file through that should not pass - - + + • - - - - - a limit enforced in the browser and not on the server - + + + + a limit enforced in the browser and not on the server - - + + @@ -242,17 +230,15 @@ - - - - - the preset size-boundaries cannot build this set - under_1mb would be -1048064 B, and a file cannot be smaller than - nothing. Raise the Limit above 1051991 B, narrow the spread, or choose a format with a smaller minimum. The Limit - asked for was 512 B. - + + + + the preset size-boundaries cannot build this set - under_1mb would be -1048064 B, and a file cannot be smaller than + nothing. Raise the Limit above 1051991 B, narrow the spread, or choose a format with a smaller minimum. The Limit + asked for was 512 B. - - + + @@ -446,15 +432,13 @@ - - - - - Files will go to /tfg/out - + + + + Files will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/preset.xml b/internal/guard/testdata/screens/preset.xml index a16cefb..0ad5019 100644 --- a/internal/guard/testdata/screens/preset.xml +++ b/internal/guard/testdata/screens/preset.xml @@ -36,15 +36,13 @@ - - - - - Presets - + + + + Presets - - + + @@ -113,72 +111,60 @@ - - - - - Does a file that is valid and as small as the format allows get through? - + + + + Does a file that is valid and as small as the format allows get through? - - - - - - - Typically finds: - + + + + + + Typically finds: - - + + • - - - - - a valid file turned away for being too small, where the check counts bytes instead of reading them - + + + + a valid file turned away for being too small, where the check counts bytes instead of reading them - - + + • - - - - - an empty file that brings the reader down rather than being reported - + + + + an empty file that brings the reader down rather than being reported - - + + • - - - - - a picture one pixel wide that divides by zero on the way to a thumbnail - + + + + a picture one pixel wide that divides by zero on the way to a thumbnail - - + + • - - - - - storage that reads nought bytes as a failed upload and keeps retrying - + + + + storage that reads nought bytes as a failed upload and keeps retrying - - + + @@ -379,15 +365,13 @@ - - - - - 28 files · 31.9 KB (32 667 B) · 26 formats · will go to /tfg/out - + + + + 28 files · 31.9 KB (32 667 B) · 26 formats · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/recipe-contents.xml b/internal/guard/testdata/screens/recipe-contents.xml index 4687fb4..1c2a457 100644 --- a/internal/guard/testdata/screens/recipe-contents.xml +++ b/internal/guard/testdata/screens/recipe-contents.xml @@ -36,15 +36,13 @@ - - - - - Several batches - + + + + Several batches - - + + @@ -411,15 +409,13 @@ - - - - - Files inside each archive - + + + + Files inside each archive - - + + Format @@ -695,15 +691,13 @@ - - - - - Files will go to /tfg/out - + + + + Files will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/recipe-on-a-preset.xml b/internal/guard/testdata/screens/recipe-on-a-preset.xml index 11adb13..cdb66af 100644 --- a/internal/guard/testdata/screens/recipe-on-a-preset.xml +++ b/internal/guard/testdata/screens/recipe-on-a-preset.xml @@ -36,15 +36,13 @@ - - - - - Several batches - + + + + Several batches - - + + @@ -663,15 +661,13 @@ - - - - - 29 files · 10.0 MB (10 518 427 B) · 26 formats · will go to /tfg/out - + + + + 29 files · 10.0 MB (10 518 427 B) · 26 formats · will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/recipe-refused-with-one-batch-filled.xml b/internal/guard/testdata/screens/recipe-refused-with-one-batch-filled.xml index 6f6b4f8..47c32ff 100644 --- a/internal/guard/testdata/screens/recipe-refused-with-one-batch-filled.xml +++ b/internal/guard/testdata/screens/recipe-refused-with-one-batch-filled.xml @@ -36,15 +36,13 @@ - - - - - Several batches - + + + + Several batches - - + + @@ -284,17 +282,15 @@ - - - - - target 1 has no Size - every target declares its Size, which is what lets a dry run report exact numbers before anything - reaches the disk. - add size: 2mb, size-range: 1kb-8kb, a boundary, contains, or a plain number of bytes. - + + + + target 1 has no Size - every target declares its Size, which is what lets a dry run report exact numbers before anything + reaches the disk. + add size: 2mb, size-range: 1kb-8kb, a boundary, contains, or a plain number of bytes. - - + + @@ -332,17 +328,15 @@ - - - - - target 1 has no Batch name - a Batch name anchors the seed of a target, so editing one - target never moves the bytes of another. - give it a Batch name, for example id: invoices. - + + + + target 1 has no Batch name - a Batch name anchors the seed of a target, so editing one + target never moves the bytes of another. + give it a Batch name, for example id: invoices. - - + + @@ -939,15 +933,13 @@ - - - - - Files will go to /tfg/out - + + + + Files will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/recipe-refused.xml b/internal/guard/testdata/screens/recipe-refused.xml index d159e50..60c7752 100644 --- a/internal/guard/testdata/screens/recipe-refused.xml +++ b/internal/guard/testdata/screens/recipe-refused.xml @@ -36,15 +36,13 @@ - - - - - Several batches - + + + + Several batches - - + + @@ -279,17 +277,15 @@ - - - - - target 1 has no Size - every target declares its Size, which is what lets a dry run report exact numbers before anything - reaches the disk. - add size: 2mb, size-range: 1kb-8kb, a boundary, contains, or a plain number of bytes. - + + + + target 1 has no Size - every target declares its Size, which is what lets a dry run report exact numbers before anything + reaches the disk. + add size: 2mb, size-range: 1kb-8kb, a boundary, contains, or a plain number of bytes. - - + + @@ -327,17 +323,15 @@ - - - - - target 1 has no Batch name - a Batch name anchors the seed of a target, so editing one - target never moves the bytes of another. - give it a Batch name, for example id: invoices. - + + + + target 1 has no Batch name - a Batch name anchors the seed of a target, so editing one + target never moves the bytes of another. + give it a Batch name, for example id: invoices. - - + + @@ -632,15 +626,13 @@ - - - - - Files will go to /tfg/out - + + + + Files will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/recipe-two-batches.xml b/internal/guard/testdata/screens/recipe-two-batches.xml index d12eabf..7ab1938 100644 --- a/internal/guard/testdata/screens/recipe-two-batches.xml +++ b/internal/guard/testdata/screens/recipe-two-batches.xml @@ -36,15 +36,13 @@ - - - - - Several batches - + + + + Several batches - - + + @@ -912,15 +910,13 @@ - - - - - Files will go to /tfg/out - + + + + Files will go to /tfg/out - - + + diff --git a/internal/guard/testdata/screens/recipe.xml b/internal/guard/testdata/screens/recipe.xml index d824209..1793be3 100644 --- a/internal/guard/testdata/screens/recipe.xml +++ b/internal/guard/testdata/screens/recipe.xml @@ -36,15 +36,13 @@ - - - - - Several batches - + + + + Several batches - - + + @@ -599,15 +597,13 @@ - - - - - 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - + + + + 1 file · 10.0 MB (10 485 760 B) · avif · will go to /tfg/out - - + + diff --git a/internal/gui/parts/words.go b/internal/gui/parts/words.go index 5123b3a..0654eb0 100644 --- a/internal/gui/parts/words.go +++ b/internal/gui/parts/words.go @@ -35,14 +35,49 @@ func words(text string, size float32, bold bool, colour fyne.ThemeColorName) *ca // inkTight takes the toolkit's own padding off a label, so a sentence that // wraps stands on the scale like everything else. // -// A theme override rather than a widget of ours, because the label keeps -// everything a sentence needs - wrapping, the caption size, the colour an -// importance gives it - and the only thing wrong with it is the room it keeps -// around itself. The override is the toolkit's one public door into a -// subtree's theme, and it is used bare rather than wrapped in a type of ours, -// because the driver casts to it. +// A layout rather than a theme, since 2026-09-23. The label keeps everything a +// sentence needs - wrapping, the caption size, the colour an importance gives +// it - and the only thing wrong with it is the room it keeps around itself, so +// the layout gives it that room outside its own edge: one inner padding larger +// on every side and one inner padding up and to the left. The words land where +// a label with no inner padding would put them and wrap at the same width - +// all 28 stored screens came out pixel for pixel the same. +// +// It was a container.ThemeOverride until then, and that is the reason it is +// not one now. Fyne gives an override a NEW scope at construction, at +// CreateRenderer and at every Refresh, and keys its parsed fonts by scope - so +// every rebuild of a screen followed by a new string in one of these labels +// parsed another ~7.4 MB set of fonts that nothing ever frees. Measured in the +// real window: 19 of the 26 sets after visiting the tabs were this override's, +// and the live heap there went from 205 MB to 64 MB without it +// (docs/GUI-MEMORY-2026-09-23.md section 4c). func inkTight(o fyne.CanvasObject) fyne.CanvasObject { - return container.NewThemeOverride(o, noInnerPadding{Theme()}) + return container.New(inkTightLayout{}, o) +} + +// inkTightLayout places a label so that its inner padding falls outside the +// room it is given - see inkTight. A hidden label takes no room, as it did +// inside the override it replaced. +type inkTightLayout struct{} + +func (inkTightLayout) MinSize(objects []fyne.CanvasObject) fyne.Size { + pad := Theme().Size(theme.SizeNameInnerPadding) + size := fyne.NewSize(0, 0) + for _, o := range objects { + if !o.Visible() { + continue + } + size = size.Max(o.MinSize().Subtract(fyne.NewSquareSize(2 * pad))) + } + return size +} + +func (inkTightLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) { + pad := Theme().Size(theme.SizeNameInnerPadding) + for _, o := range objects { + o.Move(fyne.NewPos(-pad, -pad)) + o.Resize(size.Add(fyne.NewSquareSize(2 * pad))) + } } // Flush puts a label a screen keeps hold of on the edge every other word From ff77b858a3e86c0a05e22406e0ec856255b16b44 Mon Sep 17 00:00:00 2001 From: DonislawDev Date: Wed, 23 Sep 2026 18:10:17 +0200 Subject: [PATCH 2/4] gui: quiet words name their colour instead of standing in a theme override, and no screen holds an override any more QuietText is a rich text with the segment widget.Label builds for itself, the hint's colour in place of the disabled one (O213), drawn ink tight by the same layout as inkTight. It replaces quiet(label) - the subtitle, the caption, the note, a folded section's line and the count of bytes - which put each of them under a container.ThemeOverride: a new scope at every Refresh, and a fresh ~7.4 MB set of fonts for every new string drawn in one. Measured in the real window, interleaved with main (two runs each): - after visiting the tabs: live heap 205 MB -> 27 MB, process 287-310 MB -> 113-131 MB, font sets 26 -> 2; - ten rebuilds each followed by a new size: live 289 MB -> 30 MB, and nothing added by the rebuilds. All 28 stored screens are pixel for pixel the same. One would not have been: a folded section's line sat inside an override that stayed visible while the line was hidden, and the row kept a gap for it - the line now stands in a container that never hides, so the open head keeps its right inset. Guards read QuietText and ByteCount as words (wordsOf), and measure a line drawn ink tight by the room it was given (labelBox). New guard: TestNoScreenStandsInAThemeOverride. The open list of formats still draws its rows under one - the next change. Co-Authored-By: Claude Opus 5.5 --- internal/guard/leftedge_test.go | 4 +- internal/guard/spacingscale_test.go | 17 + internal/guard/testdata/screens/catalogue.xml | 2006 +++++++---------- .../screens/generate-chosen-by-key.xml | 34 +- .../testdata/screens/generate-chosen.xml | 34 +- .../guard/testdata/screens/generate-empty.xml | 34 +- .../testdata/screens/generate-focused.xml | 34 +- .../testdata/screens/generate-hovered.xml | 34 +- .../screens/generate-menu-hovered.xml | 34 +- .../testdata/screens/generate-menu-keyed.xml | 34 +- .../guard/testdata/screens/generate-menu.xml | 34 +- .../screens/generate-refused-both.xml | 34 +- .../screens/generate-refused-setting.xml | 42 +- .../testdata/screens/generate-refused.xml | 34 +- .../screens/generate-switch-by-key.xml | 34 +- .../guard/testdata/screens/generate-typed.xml | 34 +- .../testdata/screens/generate-unchecked.xml | 34 +- internal/guard/testdata/screens/generate.xml | 34 +- .../testdata/screens/preset-many-settings.xml | 34 +- .../testdata/screens/preset-menu-setting.xml | 34 +- .../guard/testdata/screens/preset-menu.xml | 26 +- .../guard/testdata/screens/preset-refused.xml | 34 +- internal/guard/testdata/screens/preset.xml | 26 +- .../testdata/screens/recipe-contents.xml | 60 +- .../testdata/screens/recipe-on-a-preset.xml | 60 +- .../recipe-refused-with-one-batch-filled.xml | 90 +- .../guard/testdata/screens/recipe-refused.xml | 60 +- .../testdata/screens/recipe-two-batches.xml | 90 +- internal/guard/testdata/screens/recipe.xml | 60 +- internal/guard/themescope_test.go | 66 + internal/guard/words_test.go | 24 + internal/gui/catalogue/words.go | 2 +- internal/gui/parts/bytecount.go | 8 +- internal/gui/parts/field.go | 13 +- internal/gui/parts/fields.go | 7 +- internal/gui/parts/folding.go | 16 +- internal/gui/parts/parts.go | 56 +- internal/gui/parts/quiet.go | 95 + internal/gui/parts/words.go | 12 - 39 files changed, 1388 insertions(+), 2030 deletions(-) create mode 100644 internal/guard/themescope_test.go create mode 100644 internal/gui/parts/quiet.go diff --git a/internal/guard/leftedge_test.go b/internal/guard/leftedge_test.go index 0f70a00..a2f06db 100644 --- a/internal/guard/leftedge_test.go +++ b/internal/guard/leftedge_test.go @@ -138,7 +138,9 @@ func TestTheActionBarSpeaksOnTheSameEdgeAsTheForm(t *testing.T) { if status == nil { t.Fatal("the bar is not naming the destination at rest, so this guard read the wrong tree") } - at, found := absoluteOf(generate, status) + // Measured where its words are, which labelBox knows for a line drawn + // ink tight - the label itself stands one padding to the left of them. + at, found := labelBox(generate, status.Text) if !found { t.Fatal("the status line is not on the screen it was found in") } diff --git a/internal/guard/spacingscale_test.go b/internal/guard/spacingscale_test.go index 0eb52f1..2feec5f 100644 --- a/internal/guard/spacingscale_test.go +++ b/internal/guard/spacingscale_test.go @@ -239,17 +239,34 @@ func gapBelowField(t *testing.T, screen fyne.CanvasObject, above, below string) // // Found by the text on the label rather than by a position handed in, because // a guard given coordinates would be a copy of the layout it is checking. +// +// A sentence drawn ink tight (parts.inkTight) is measured by the room it was +// given, not by the label. Since 2026-09-23 the layout places the label one +// inner padding up and left and one larger on every side, so its padding falls +// outside the room and its words land on the room's edge - the label's own +// box is where its padding is, and the room is where the ink is, exactly +// where the label stood when a theme override took the padding off instead. func labelBox(screen fyne.CanvasObject, words string) (band, bool) { found := band{} ok := false + tight := map[fyne.CanvasObject]band{} atAbsolute(screen, func(o fyne.CanvasObject, at fyne.Position) { if ok { return } + if room, is := o.(*fyne.Container); is && len(room.Objects) == 1 { + if p := room.Objects[0].Position(); p.X < 0 && p.X == p.Y { + tight[room.Objects[0]] = band{X: at.X, Y: at.Y, Width: room.Size().Width, Height: room.Size().Height} + } + } shown, is := wordsOf(o) if !is || shown != words { return } + if room, drawnTight := tight[o]; drawnTight { + found, ok = room, true + return + } found, ok = band{X: at.X, Y: at.Y, Width: o.Size().Width, Height: o.Size().Height}, true }) return found, ok diff --git a/internal/guard/testdata/screens/catalogue.xml b/internal/guard/testdata/screens/catalogue.xml index e60b98c..38fc683 100644 --- a/internal/guard/testdata/screens/catalogue.xml +++ b/internal/guard/testdata/screens/catalogue.xml @@ -11,12 +11,10 @@ - + - - - Every part of the window, in every state it has. - + + Every part of the window, in every state it has. @@ -29,12 +27,10 @@ Button - + - - - primary at rest - + + primary at rest @@ -47,12 +43,10 @@ - + - - - primary under the pointer - + + primary under the pointer @@ -65,12 +59,10 @@ - + - - - primary pressed - + + primary pressed @@ -83,12 +75,10 @@ - + - - - primary holding the keyboard - + + primary holding the keyboard @@ -101,12 +91,10 @@ - + - - - secondary at rest - + + secondary at rest @@ -119,12 +107,10 @@ - + - - - secondary under the pointer - + + secondary under the pointer @@ -137,12 +123,10 @@ - + - - - secondary pressed - + + secondary pressed @@ -155,12 +139,10 @@ - + - - - secondary holding the keyboard - + + secondary holding the keyboard @@ -173,12 +155,10 @@ - + - - - secondary disabled - + + secondary disabled @@ -191,12 +171,10 @@ - + - - - quiet at rest - + + quiet at rest @@ -209,12 +187,10 @@ - + - - - quiet under the pointer - + + quiet under the pointer @@ -227,12 +203,10 @@ - + - - - quiet pressed - + + quiet pressed @@ -245,12 +219,10 @@ - + - - - quiet holding the keyboard - + + quiet holding the keyboard @@ -263,12 +235,10 @@ - + - - - quiet disabled - + + quiet disabled @@ -281,12 +251,10 @@ - + - - - long text - + + long text @@ -299,12 +267,10 @@ - + - - - glyph at rest - + + glyph at rest @@ -317,12 +283,10 @@ - + - - - glyph under the pointer - + + glyph under the pointer @@ -335,12 +299,10 @@ - + - - - glyph holding the keyboard - + + glyph holding the keyboard @@ -353,12 +315,10 @@ - + - - - glyph disabled - + + glyph disabled @@ -381,12 +341,10 @@ Chooser - + - - - at rest - + + at rest @@ -406,12 +364,10 @@ - + - - - chosen - + + chosen @@ -431,12 +387,10 @@ - + - - - holding the keyboard - + + holding the keyboard @@ -459,12 +413,10 @@ - + - - - refused - + + refused @@ -487,12 +439,10 @@ - + - - - disabled - + + disabled @@ -512,12 +462,10 @@ - + - - - long value - + + long value @@ -537,12 +485,10 @@ - + - - - every format, showing the kind of its value - + + every format, showing the kind of its value @@ -573,12 +519,10 @@ Entry - + - - - empty, with its hint - + + empty, with its hint @@ -598,12 +542,10 @@ - + - - - typed - + + typed @@ -620,12 +562,10 @@ - + - - - holding the keyboard - + + holding the keyboard @@ -643,12 +583,10 @@ - + - - - disabled - + + disabled @@ -665,12 +603,10 @@ - + - - - long text - + + long text @@ -697,12 +633,10 @@ Toggle - + - - - off - + + off @@ -715,12 +649,10 @@ - + - - - on - + + on @@ -734,12 +666,10 @@ - + - - - under the pointer - + + under the pointer @@ -752,12 +682,10 @@ - + - - - holding the keyboard - + + holding the keyboard @@ -771,12 +699,10 @@ - + - - - disabled - + + disabled @@ -799,12 +725,10 @@ Segments - + - - - first chosen - + + first chosen @@ -823,12 +747,10 @@ - + - - - middle chosen - + + middle chosen @@ -846,12 +768,10 @@ - + - - - holding the keyboard - + + holding the keyboard @@ -870,12 +790,10 @@ - + - - - the last one under the pointer - + + the last one under the pointer @@ -894,12 +812,10 @@ - + - - - frozen, middle chosen - + + frozen, middle chosen @@ -917,12 +833,10 @@ - + - - - long words - + + long words @@ -951,12 +865,10 @@ OpenList - + - - - a few values, one chosen - + + a few values, one chosen @@ -1009,12 +921,10 @@ - + - - - nothing chosen yet - + + nothing chosen yet @@ -1066,12 +976,10 @@ - + - - - more values than a short window shows at once - + + more values than a short window shows at once @@ -1149,12 +1057,10 @@ - + - - - every value with the kind of thing it is - + + every value with the kind of thing it is @@ -1300,12 +1206,10 @@ - + - - - a long value - + + a long value @@ -1349,12 +1253,10 @@ - + - - - every format, under the heading of its kind, with a box to filter - + + every format, under the heading of its kind, with a box to filter @@ -1512,12 +1414,10 @@ - + - - - typed into, with the letters that matched in bold - + + typed into, with the letters that matched in bold @@ -1686,12 +1586,10 @@ - + - - - typed into, with nothing left - + + typed into, with nothing left @@ -1747,12 +1645,10 @@ Tabs - + - - - the strip, first word chosen - + + the strip, first word chosen @@ -1781,12 +1677,10 @@ - + - - - a word under the pointer - + + a word under the pointer @@ -1815,12 +1709,10 @@ - + - - - a word holding the keyboard - + + a word holding the keyboard @@ -1849,12 +1741,10 @@ - + - - - the strip with its screens under it - + + the strip with its screens under it @@ -1897,12 +1787,10 @@ - + - - - long words - + + long words @@ -1931,12 +1819,10 @@ Fields - + - - - a row - + + a row @@ -1965,12 +1851,10 @@ - + - - - a row that has to be filled in - + + a row that has to be filled in @@ -2002,12 +1886,10 @@ - + - - - a row the run refused - + + a row the run refused @@ -2045,12 +1927,10 @@ - + - - - a row frozen while a run goes - + + a row frozen while a run goes @@ -2079,12 +1959,10 @@ - + - - - a box to tick with its name beside it - + + a box to tick with its name beside it @@ -2107,12 +1985,10 @@ - + - - - a box to tick beside a named field, level with its box - + + a box to tick beside a named field, level with its box @@ -2163,12 +2039,10 @@ - + - - - a named control with no setting behind it - + + a named control with no setting behind it @@ -2192,12 +2066,10 @@ - + - - - a table: the names once over the columns, cells under them - + + a table: the names once over the columns, cells under them @@ -2307,12 +2179,10 @@ - + - - - a row of arbitrary cells - + + a row of arbitrary cells @@ -2348,12 +2218,10 @@ - + - - - a long name - + + a long name @@ -2393,12 +2261,10 @@ PropertyField - + - - - a number with a range - + + a number with a range @@ -2441,12 +2307,10 @@ - + - - - a choice from a closed set - + + a choice from a closed set @@ -2485,12 +2349,10 @@ - + - - - a yes or no - + + a yes or no @@ -2524,12 +2386,10 @@ - + - - - a size - + + a size @@ -2564,12 +2424,10 @@ - + - - - - + + @@ -2581,12 +2439,10 @@ - + - - - free text - + + free text @@ -2639,12 +2495,10 @@ ByteCount - + - - - a size counted out - + + a size counted out @@ -2669,12 +2523,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -2682,12 +2534,10 @@ - + - - - nothing to count yet - + + nothing to count yet @@ -2715,12 +2565,10 @@ - + - - - - + + @@ -2728,12 +2576,10 @@ - + - - - a large size - + + a large size @@ -2758,12 +2604,10 @@ - + - - - 2 147 483 648 B - + + 2 147 483 648 B @@ -2781,12 +2625,10 @@ Tips - + - - - the button beside a name - + + the button beside a name @@ -2827,12 +2669,10 @@ - + - - - the button under the pointer - + + the button under the pointer @@ -2899,23 +2739,19 @@ ErrorArea - + - - - silent - + + silent - + - - - one line - + + one line @@ -2930,12 +2766,10 @@ - + - - - a long message - + + a long message @@ -2951,12 +2785,10 @@ - + - - - offering the fix it asks for - + + offering the fix it asks for @@ -2988,12 +2820,10 @@ Progress - + - - - nothing done yet - + + nothing done yet @@ -3003,12 +2833,10 @@ - + - - - half done - + + half done @@ -3018,12 +2846,10 @@ - + - - - done - + + done @@ -3043,12 +2869,10 @@ Folding - + - - - open - + + open @@ -3069,10 +2893,8 @@ Notes for the manifest - - - - + + @@ -3094,12 +2916,10 @@ - + - - - closed - + + closed @@ -3120,10 +2940,8 @@ Notes for the manifest - - - - + + @@ -3136,12 +2954,10 @@ - + - - - closed, saying what it holds - + + closed, saying what it holds @@ -3162,15 +2978,15 @@ Settings for png - - - - - width 800, height 600 + + + + + width 800, height 600 - - - + + + @@ -3183,12 +2999,10 @@ - + - - - inner, open - + + inner, open @@ -3213,10 +3027,8 @@ Advanced - - - - + + @@ -3239,12 +3051,10 @@ - + - - - inner, closed - + + inner, closed @@ -3269,10 +3079,8 @@ Advanced - - - - + + @@ -3286,12 +3094,10 @@ - + - - - inner, a damage's settings - + + inner, a damage's settings @@ -3316,10 +3122,8 @@ Settings for zero-head - - - - + + @@ -3342,12 +3146,10 @@ - + - - - inner, notes for the manifest - + + inner, notes for the manifest @@ -3372,10 +3174,8 @@ Notes for the manifest - - - - + + @@ -3398,12 +3198,10 @@ - + - - - a long title - + + a long title @@ -3424,10 +3222,8 @@ Write a label inside each generated file, including the ones that are far too small to hold it - - - - + + @@ -3449,12 +3245,10 @@ - + - - - the head under the pointer - + + the head under the pointer @@ -3475,10 +3269,8 @@ Notes for the manifest - - - - + + @@ -3500,12 +3292,10 @@ - + - - - the head holding the keyboard - + + the head holding the keyboard @@ -3526,10 +3316,8 @@ Notes for the manifest - - - - + + @@ -3551,12 +3339,10 @@ - + - - - shut, the head under the pointer - + + shut, the head under the pointer @@ -3577,15 +3363,15 @@ Settings for png - - - - - width 800, height 600 + + + + + width 800, height 600 - - - + + + @@ -3608,12 +3394,10 @@ Title - + - - - the title of a screen - + + the title of a screen @@ -3626,32 +3410,26 @@ - + - - - the sentence under a title - + + the sentence under a title - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. - + - - - a title with its sentence - + + a title with its sentence @@ -3663,36 +3441,30 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. - + - - - the name of a field - + + the name of a field Output directory - + - - - the name of a block inside a section - + + the name of a block inside a section @@ -3705,12 +3477,10 @@ - + - - - a paragraph - + + a paragraph @@ -3723,32 +3493,26 @@ - + - - - a note that has to stay visible - + + a note that has to stay visible - + - - - The limit of 100 000 files is this tool's, not the disk's. - + + The limit of 100 000 files is this tool's, not the disk's. - + - - - a list of short statements - + + a list of short statements @@ -3786,12 +3550,10 @@ - + - - - a list whose items do not fit on one line - + + a list whose items do not fit on one line @@ -3820,32 +3582,26 @@ - + - - - a caption, the smallest rank - + + a caption, the smallest rank - + - - - 10 485 760 B - + + 10 485 760 B - + - - - a table of three columns, the last one wrapping - + + a table of three columns, the last one wrapping @@ -3928,12 +3684,10 @@ - + - - - a long line at every rank - + + a long line at every rank @@ -3960,12 +3714,10 @@ - + - - - Write a label inside each generated file, including the ones that are far too small to hold it - + + Write a label inside each generated file, including the ones that are far too small to hold it @@ -3982,12 +3734,10 @@ Section - + - - - a section of two rows - + + a section of two rows @@ -4051,12 +3801,10 @@ - + - - - a section with a line across it - + + a section with a line across it @@ -4122,12 +3870,10 @@ - + - - - the bar a run starts from - + + the bar a run starts from @@ -4167,12 +3913,10 @@ - + - - - fields in columns, each as wide as its value needs - + + fields in columns, each as wide as its value needs @@ -4307,12 +4051,10 @@ - + - - - a row with a refusal under it - + + a row with a refusal under it @@ -4425,12 +4167,10 @@ - + - - - a section with a long title - + + a section with a long title @@ -4504,12 +4244,10 @@ Swatch - + - - - a surface near the bottom of the ladder - + + a surface near the bottom of the ladder @@ -4518,12 +4256,10 @@ - + - - - a surface near the top of it - + + a surface near the top of it @@ -4532,12 +4268,10 @@ - + - - - a colour that carries meaning - + + a colour that carries meaning @@ -4546,12 +4280,10 @@ - + - - - an ink, which is nearly white - + + an ink, which is nearly white @@ -4560,12 +4292,10 @@ - + - - - something the toolkit blends, laid over a panel first - + + something the toolkit blends, laid over a panel first @@ -4583,12 +4313,10 @@ Palette, as this window draws it - + - - - Every colour the window paints with, measured against what it is drawn on. - + + Every colour the window paints with, measured against what it is drawn on. @@ -4602,21 +4330,17 @@ - + - - - background - the page the window stands on - + + background - the page the window stands on - + - - - #1E1E20 - + + #1E1E20 @@ -4625,21 +4349,17 @@ - + - - - panel - the surface a section is drawn on - + + panel - the surface a section is drawn on - + - - - #2B2B2F - 17.7 L*, +6.3 from the page - + + #2B2B2F - 17.7 L*, +6.3 from the page @@ -4648,21 +4368,17 @@ - + - - - inputBackground - the fill of a box to type in - + + inputBackground - the fill of a box to type in - + - - - #39393F - 24.2 L*, +6.5 from the panel - + + #39393F - 24.2 L*, +6.5 from the panel @@ -4671,21 +4387,17 @@ - + - - - button - the face of a button that is not the main one - + + button - the face of a button that is not the main one - + - - - #48484E - 30.8 L*, +6.6 from a box to type in - + + #48484E - 30.8 L*, +6.6 from a box to type in @@ -4694,21 +4406,17 @@ - + - - - separator - a line that separates and says nothing else - + + separator - a line that separates and says nothing else - + - - - #48484E - 30.8 L*, +13.1 from the panel - + + #48484E - 30.8 L*, +13.1 from the panel @@ -4717,21 +4425,17 @@ - + - - - menuBackground - what an open list floats on - + + menuBackground - what an open list floats on - + - - - #57575F - 37.2 L*, +13.1 from a box to type in - + + #57575F - 37.2 L*, +13.1 from a box to type in @@ -4740,21 +4444,17 @@ - + - - - inputBorder - the edge that says where the typing goes - + + inputBorder - the edge that says where the typing goes - + - - - #65656D - 43.0 L*, +18.9 from its own fill - + + #65656D - 43.0 L*, +18.9 from its own fill @@ -4770,21 +4470,17 @@ - + - - - foreground - a value, and everything read at rest - + + foreground - a value, and everything read at rest - + - - - #E6E6E8 - 5.74:1 on an open list - + + #E6E6E8 - 5.74:1 on an open list @@ -4793,21 +4489,17 @@ - + - - - label - the name of a field, a step quieter than its value - + + label - the name of a field, a step quieter than its value - + - - - #D3D3D7 - 9.45:1 on a panel - + + #D3D3D7 - 9.45:1 on a panel @@ -4816,21 +4508,17 @@ - + - - - disabled - a value in a box switched off for the length of a run - + + disabled - a value in a box switched off for the length of a run - + - - - #C7C7CC - 6.81:1 on a box to type in - + + #C7C7CC - 6.81:1 on a box to type in @@ -4839,21 +4527,17 @@ - + - - - placeholder - a hint in a box nobody has typed in - + + placeholder - a hint in a box nobody has typed in - + - - - #A2A2A9 - 4.52:1 on a box to type in - + + #A2A2A9 - 4.52:1 on a box to type in @@ -4869,21 +4553,17 @@ - + - - - primary - the action a screen is for, and the line round a focused control - + + primary - the action a screen is for, and the line round a focused control - + - - - #5AB3F2 - 7.26:1 on the page - + + #5AB3F2 - 7.26:1 on the page @@ -4892,21 +4572,17 @@ - + - - - hyperlink - a link, the same blue as the action - + + hyperlink - a link, the same blue as the action - + - - - #5AB3F2 - 7.26:1 on the page - + + #5AB3F2 - 7.26:1 on the page @@ -4915,21 +4591,17 @@ - + - - - error - a refusal, and a file that failed - + + error - a refusal, and a file that failed - + - - - #F48F8D - 7.26:1 on the page - + + #F48F8D - 7.26:1 on the page @@ -4938,21 +4610,17 @@ - + - - - success - a run that wrote everything it promised - + + success - a run that wrote everything it promised - + - - - #42C260 - 7.23:1 on the page - + + #42C260 - 7.23:1 on the page @@ -4961,21 +4629,17 @@ - + - - - warning - a run that wrote files and skipped some - + + warning - a run that wrote files and skipped some - + - - - #DAA131 - 7.23:1 on the page - + + #DAA131 - 7.23:1 on the page @@ -4984,21 +4648,17 @@ - + - - - selection - the row or the segment somebody chose - + + selection - the row or the segment somebody chose - + - - - #224B69 - 30.4 L*, +19.0 from the page - + + #224B69 - 30.4 L*, +19.0 from the page @@ -5014,21 +4674,17 @@ - + - - - hover - what the pointer does to a dark face - + + hover - what the pointer does to a dark face - + - - - #FFFFFF at 0x22 - over the page it comes to #3C3C3D, 25.4 L*, a move of +14.0 - + + #FFFFFF at 0x22 - over the page it comes to #3C3C3D, 25.4 L*, a move of +14.0 @@ -5037,21 +4693,17 @@ - + - - - pressed - what a press does to a dark face - + + pressed - what a press does to a dark face - + - - - #FFFFFF at 0x40 - over a button's face it comes to #76767A, 49.7 L*, a move of +19.0 - + + #FFFFFF at 0x40 - over a button's face it comes to #76767A, 49.7 L*, a move of +19.0 @@ -5060,21 +4712,17 @@ - + - - - lift - what the pointer does to the filled main button - + + lift - what the pointer does to the filled main button - + - - - #FFFFFF at 0x66 - over the main button it comes to #9CD2F8, 81.6 L*, a move of +11.6 - + + #FFFFFF at 0x66 - over the main button it comes to #9CD2F8, 81.6 L*, a move of +11.6 @@ -5083,21 +4731,17 @@ - + - - - shade - what a press does to the filled main button - + + shade - what a press does to the filled main button - + - - - #000000 at 0x33 - over the main button it comes to #488FC2, 57.0 L*, a move of -13.0 - + + #000000 at 0x33 - over the main button it comes to #488FC2, 57.0 L*, a move of -13.0 @@ -5106,21 +4750,17 @@ - + - - - focus - the wash the toolkit lays over a control the keyboard is in - + + focus - the wash the toolkit lays over a control the keyboard is in - + - - - #00A5F0 at 0x66 - over a box to type in it comes to #226486, 39.9 L*, a move of +15.8 - + + #00A5F0 at 0x66 - over a box to type in it comes to #226486, 39.9 L*, a move of +15.8 @@ -5129,21 +4769,17 @@ - + - - - tipshade - the shade an explanation casts on the form under it - + + tipshade - the shade an explanation casts on the form under it - + - - - #000000 at 0x66 - over a panel it comes to #19191C, 9.3 L*, a move of -8.4 - + + #000000 at 0x66 - over a panel it comes to #19191C, 9.3 L*, a move of -8.4 @@ -5152,21 +4788,17 @@ - + - - - shadow - what a popup casts - nothing here, on purpose - + + shadow - what a popup casts - nothing here, on purpose - + - - - nothing - drawn transparent on purpose - + + nothing - drawn transparent on purpose @@ -5182,21 +4814,17 @@ - + - - - foregroundOnPrimary - the word on the main button - + + foregroundOnPrimary - the word on the main button - + - - - #1A1A1A - 7.60:1 on the main button - + + #1A1A1A - 7.60:1 on the main button @@ -5205,21 +4833,17 @@ - + - - - foregroundOnError - what is written on a filled red - + + foregroundOnError - what is written on a filled red - + - - - #1A1A1A - 7.59:1 on a filled red - + + #1A1A1A - 7.59:1 on a filled red @@ -5228,21 +4852,17 @@ - + - - - foregroundOnSuccess - what is written on a filled green - + + foregroundOnSuccess - what is written on a filled green - + - - - #1A1A1A - 7.56:1 on a filled green - + + #1A1A1A - 7.56:1 on a filled green @@ -5251,21 +4871,17 @@ - + - - - foregroundOnWarning - what is written on a filled amber - + + foregroundOnWarning - what is written on a filled amber - + - - - #1A1A1A - 7.56:1 on a filled amber - + + #1A1A1A - 7.56:1 on a filled amber @@ -5281,12 +4897,10 @@ Palette, light - computed and not installed - + - - - Worked out and guarded to the same thresholds. The window does not use it: this program has one look. - + + Worked out and guarded to the same thresholds. The window does not use it: this program has one look. @@ -5300,21 +4914,17 @@ - + - - - background - the page the window stands on - + + background - the page the window stands on - + - - - #FFFFFF - + + #FFFFFF @@ -5323,21 +4933,17 @@ - + - - - panel - the surface a section is drawn on - + + panel - the surface a section is drawn on - + - - - #EEEEEF - 94.1 L*, -5.9 from the page - + + #EEEEEF - 94.1 L*, -5.9 from the page @@ -5346,21 +4952,17 @@ - + - - - inputBackground - the fill of a box to type in - + + inputBackground - the fill of a box to type in - + - - - #DCDCE0 - 87.9 L*, -6.3 from the panel - + + #DCDCE0 - 87.9 L*, -6.3 from the panel @@ -5369,21 +4971,17 @@ - + - - - button - the face of a button that is not the main one - + + button - the face of a button that is not the main one - + - - - #CCCBD1 - 81.9 L*, -5.9 from a box to type in - + + #CCCBD1 - 81.9 L*, -5.9 from a box to type in @@ -5392,21 +4990,17 @@ - + - - - separator - a line that separates and says nothing else - + + separator - a line that separates and says nothing else - + - - - #CCCBD1 - 81.9 L*, -12.2 from the panel - + + #CCCBD1 - 81.9 L*, -12.2 from the panel @@ -5415,21 +5009,17 @@ - + - - - menuBackground - what an open list floats on - + + menuBackground - what an open list floats on - + - - - #FFFFFF - 100.0 L*, +12.1 from a box to type in - + + #FFFFFF - 100.0 L*, +12.1 from a box to type in @@ -5438,21 +5028,17 @@ - + - - - inputBorder - the edge that says where the typing goes - + + inputBorder - the edge that says where the typing goes - + - - - #ABAAB2 - 69.9 L*, -18.0 from its own fill - + + #ABAAB2 - 69.9 L*, -18.0 from its own fill @@ -5468,21 +5054,17 @@ - + - - - foreground - a value, and everything read at rest - + + foreground - a value, and everything read at rest - + - - - #1A1A1C - 17.38:1 on an open list - + + #1A1A1C - 17.38:1 on an open list @@ -5491,21 +5073,17 @@ - + - - - label - the name of a field, a step quieter than its value - + + label - the name of a field, a step quieter than its value - + - - - #434349 - 8.47:1 on a panel - + + #434349 - 8.47:1 on a panel @@ -5514,21 +5092,17 @@ - + - - - disabled - a value in a box switched off for the length of a run - + + disabled - a value in a box switched off for the length of a run - + - - - #3D3D42 - 7.90:1 on a box to type in - + + #3D3D42 - 7.90:1 on a box to type in @@ -5537,21 +5111,17 @@ - + - - - placeholder - a hint in a box nobody has typed in - + + placeholder - a hint in a box nobody has typed in - + - - - #585860 - 5.15:1 on a box to type in - + + #585860 - 5.15:1 on a box to type in @@ -5567,21 +5137,17 @@ - + - - - primary - the action a screen is for, and the line round a focused control - + + primary - the action a screen is for, and the line round a focused control - + - - - #286893 - 6.01:1 on the page - + + #286893 - 6.01:1 on the page @@ -5590,21 +5156,17 @@ - + - - - hyperlink - a link, the same blue as the action - + + hyperlink - a link, the same blue as the action - + - - - #286893 - 6.01:1 on the page - + + #286893 - 6.01:1 on the page @@ -5613,21 +5175,17 @@ - + - - - error - a refusal, and a file that failed - + + error - a refusal, and a file that failed - + - - - #BB293B - 6.01:1 on the page - + + #BB293B - 6.01:1 on the page @@ -5636,21 +5194,17 @@ - + - - - success - a run that wrote everything it promised - + + success - a run that wrote everything it promised - + - - - #237135 - 6.03:1 on the page - + + #237135 - 6.03:1 on the page @@ -5659,21 +5213,17 @@ - + - - - warning - a run that wrote files and skipped some - + + warning - a run that wrote files and skipped some - + - - - #805D18 - 6.01:1 on the page - + + #805D18 - 6.01:1 on the page @@ -5682,21 +5232,17 @@ - + - - - selection - the row or the segment somebody chose - + + selection - the row or the segment somebody chose - + - - - #C1E0FF - 87.9 L*, -12.1 from the page - + + #C1E0FF - 87.9 L*, -12.1 from the page @@ -5712,21 +5258,17 @@ - + - - - hover - what the pointer does to a dark face - + + hover - what the pointer does to a dark face - + - - - #000000 at 0x20 - over the page it comes to #DFDFDF, 88.8 L*, a move of -11.2 - + + #000000 at 0x20 - over the page it comes to #DFDFDF, 88.8 L*, a move of -11.2 @@ -5735,21 +5277,17 @@ - + - - - pressed - what a press does to a dark face - + + pressed - what a press does to a dark face - + - - - #000000 at 0x33 - over a button's face it comes to #A3A3A7, 67.0 L*, a move of -15.0 - + + #000000 at 0x33 - over a button's face it comes to #A3A3A7, 67.0 L*, a move of -15.0 @@ -5758,21 +5296,17 @@ - + - - - lift - what the pointer does to the filled main button - + + lift - what the pointer does to the filled main button - + - - - #FFFFFF at 0x66 - over the main button it comes to #7EA5BE, 65.6 L*, a move of +23.7 - + + #FFFFFF at 0x66 - over the main button it comes to #7EA5BE, 65.6 L*, a move of +23.7 @@ -5781,21 +5315,17 @@ - + - - - shade - what a press does to the filled main button - + + shade - what a press does to the filled main button - + - - - #000000 at 0x33 - over the main button it comes to #205376, 33.6 L*, a move of -8.3 - + + #000000 at 0x33 - over the main button it comes to #205376, 33.6 L*, a move of -8.3 @@ -5804,21 +5334,17 @@ - + - - - focus - the wash the toolkit lays over a control the keyboard is in - + + focus - the wash the toolkit lays over a control the keyboard is in - + - - - #007FBA at 0x66 - over a box to type in it comes to #84B7D1, 71.7 L*, a move of -16.1 - + + #007FBA at 0x66 - over a box to type in it comes to #84B7D1, 71.7 L*, a move of -16.1 @@ -5827,21 +5353,17 @@ - + - - - tipshade - the shade an explanation casts on the form under it - + + tipshade - the shade an explanation casts on the form under it - + - - - #000000 at 0x40 - over a panel it comes to #B2B2B3, 72.7 L*, a move of -21.4 - + + #000000 at 0x40 - over a panel it comes to #B2B2B3, 72.7 L*, a move of -21.4 @@ -5850,21 +5372,17 @@ - + - - - shadow - what a popup casts - nothing here, on purpose - + + shadow - what a popup casts - nothing here, on purpose - + - - - #000000 at 0x40 - + + #000000 at 0x40 @@ -5880,21 +5398,17 @@ - + - - - foregroundOnPrimary - the word on the main button - + + foregroundOnPrimary - the word on the main button - + - - - #FFFFFF - 6.01:1 on the main button - + + #FFFFFF - 6.01:1 on the main button @@ -5903,21 +5417,17 @@ - + - - - foregroundOnError - what is written on a filled red - + + foregroundOnError - what is written on a filled red - + - - - #FFFFFF - 6.01:1 on a filled red - + + #FFFFFF - 6.01:1 on a filled red @@ -5926,21 +5436,17 @@ - + - - - foregroundOnSuccess - what is written on a filled green - + + foregroundOnSuccess - what is written on a filled green - + - - - #FFFFFF - 6.03:1 on a filled green - + + #FFFFFF - 6.03:1 on a filled green @@ -5949,21 +5455,17 @@ - + - - - foregroundOnWarning - what is written on a filled amber - + + foregroundOnWarning - what is written on a filled amber - + - - - #FFFFFF - 6.01:1 on a filled amber - + + #FFFFFF - 6.01:1 on a filled amber diff --git a/internal/guard/testdata/screens/generate-chosen-by-key.xml b/internal/guard/testdata/screens/generate-chosen-by-key.xml index a74e1b1..ea60d4f 100644 --- a/internal/guard/testdata/screens/generate-chosen-by-key.xml +++ b/internal/guard/testdata/screens/generate-chosen-by-key.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -140,12 +136,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -288,10 +282,8 @@ Settings for png - - - - + + @@ -327,10 +319,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate-chosen.xml b/internal/guard/testdata/screens/generate-chosen.xml index 5195493..778cc5f 100644 --- a/internal/guard/testdata/screens/generate-chosen.xml +++ b/internal/guard/testdata/screens/generate-chosen.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -140,12 +136,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -288,10 +282,8 @@ Settings for png - - - - + + @@ -327,10 +319,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate-empty.xml b/internal/guard/testdata/screens/generate-empty.xml index 9e5d459..66eafad 100644 --- a/internal/guard/testdata/screens/generate-empty.xml +++ b/internal/guard/testdata/screens/generate-empty.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -140,12 +136,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -298,10 +292,8 @@ Settings for avif - - - - + + @@ -337,10 +329,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate-focused.xml b/internal/guard/testdata/screens/generate-focused.xml index 3887349..03f03a6 100644 --- a/internal/guard/testdata/screens/generate-focused.xml +++ b/internal/guard/testdata/screens/generate-focused.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -141,12 +137,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -289,10 +283,8 @@ Settings for avif - - - - + + @@ -328,10 +320,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate-hovered.xml b/internal/guard/testdata/screens/generate-hovered.xml index b47a7fe..cbcc47d 100644 --- a/internal/guard/testdata/screens/generate-hovered.xml +++ b/internal/guard/testdata/screens/generate-hovered.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -140,12 +136,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -288,10 +282,8 @@ Settings for avif - - - - + + @@ -327,10 +319,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate-menu-hovered.xml b/internal/guard/testdata/screens/generate-menu-hovered.xml index 2459e7f..d4d7039 100644 --- a/internal/guard/testdata/screens/generate-menu-hovered.xml +++ b/internal/guard/testdata/screens/generate-menu-hovered.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -140,12 +136,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -288,10 +282,8 @@ Settings for avif - - - - + + @@ -327,10 +319,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate-menu-keyed.xml b/internal/guard/testdata/screens/generate-menu-keyed.xml index df788a6..ce19722 100644 --- a/internal/guard/testdata/screens/generate-menu-keyed.xml +++ b/internal/guard/testdata/screens/generate-menu-keyed.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -140,12 +136,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -288,10 +282,8 @@ Settings for avif - - - - + + @@ -327,10 +319,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate-menu.xml b/internal/guard/testdata/screens/generate-menu.xml index 187206a..4ba61bd 100644 --- a/internal/guard/testdata/screens/generate-menu.xml +++ b/internal/guard/testdata/screens/generate-menu.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -140,12 +136,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -288,10 +282,8 @@ Settings for avif - - - - + + @@ -327,10 +319,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate-refused-both.xml b/internal/guard/testdata/screens/generate-refused-both.xml index d75eb80..a7483f7 100644 --- a/internal/guard/testdata/screens/generate-refused-both.xml +++ b/internal/guard/testdata/screens/generate-refused-both.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -141,12 +137,10 @@ - + - - - - + + @@ -308,10 +302,8 @@ Settings for avif - - - - + + @@ -347,10 +339,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate-refused-setting.xml b/internal/guard/testdata/screens/generate-refused-setting.xml index 62dfbb9..ad0c6f2 100644 --- a/internal/guard/testdata/screens/generate-refused-setting.xml +++ b/internal/guard/testdata/screens/generate-refused-setting.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -140,12 +136,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -288,10 +282,8 @@ Settings for png - - - - + + @@ -369,12 +361,10 @@ - + - - - width times height cannot pass 40 megapixels, because the picture is held in memory while it is encoded - + + width times height cannot pass 40 megapixels, because the picture is held in memory while it is encoded @@ -407,10 +397,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate-refused.xml b/internal/guard/testdata/screens/generate-refused.xml index 17ed15c..f3d432d 100644 --- a/internal/guard/testdata/screens/generate-refused.xml +++ b/internal/guard/testdata/screens/generate-refused.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -141,12 +137,10 @@ - + - - - 1 B - + + 1 B @@ -308,10 +302,8 @@ Settings for avif - - - - + + @@ -347,10 +339,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate-switch-by-key.xml b/internal/guard/testdata/screens/generate-switch-by-key.xml index 5c725fc..3451cb0 100644 --- a/internal/guard/testdata/screens/generate-switch-by-key.xml +++ b/internal/guard/testdata/screens/generate-switch-by-key.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -140,12 +136,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -288,10 +282,8 @@ Settings for avif - - - - + + @@ -327,10 +319,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate-typed.xml b/internal/guard/testdata/screens/generate-typed.xml index f602f26..92444fb 100644 --- a/internal/guard/testdata/screens/generate-typed.xml +++ b/internal/guard/testdata/screens/generate-typed.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -140,12 +136,10 @@ - + - - - - + + @@ -297,10 +291,8 @@ Settings for avif - - - - + + @@ -336,10 +328,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate-unchecked.xml b/internal/guard/testdata/screens/generate-unchecked.xml index d7bc9db..51135a4 100644 --- a/internal/guard/testdata/screens/generate-unchecked.xml +++ b/internal/guard/testdata/screens/generate-unchecked.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -140,12 +136,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -288,10 +282,8 @@ Settings for avif - - - - + + @@ -327,10 +319,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/generate.xml b/internal/guard/testdata/screens/generate.xml index 5471be6..54ebb5f 100644 --- a/internal/guard/testdata/screens/generate.xml +++ b/internal/guard/testdata/screens/generate.xml @@ -43,12 +43,10 @@ - + - - - Files of one format and one size, with a manifest that says how the system under test should react to them. - + + Files of one format and one size, with a manifest that says how the system under test should react to them. @@ -71,10 +69,8 @@ File configuration - - - - + + @@ -140,12 +136,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -288,10 +282,8 @@ Settings for avif - - - - + + @@ -327,10 +319,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/preset-many-settings.xml b/internal/guard/testdata/screens/preset-many-settings.xml index 55b0364..0145481 100644 --- a/internal/guard/testdata/screens/preset-many-settings.xml +++ b/internal/guard/testdata/screens/preset-many-settings.xml @@ -43,12 +43,10 @@ - + - - - Ready-made sets of files, each built to answer one question about the system under test. - + + Ready-made sets of files, each built to answer one question about the system under test. @@ -71,10 +69,8 @@ The question - - - - + + @@ -209,10 +205,8 @@ Settings - - - - + + @@ -251,12 +245,10 @@ - + - - - - + + @@ -404,10 +396,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/preset-menu-setting.xml b/internal/guard/testdata/screens/preset-menu-setting.xml index 42d36c4..4c6533b 100644 --- a/internal/guard/testdata/screens/preset-menu-setting.xml +++ b/internal/guard/testdata/screens/preset-menu-setting.xml @@ -43,12 +43,10 @@ - + - - - Ready-made sets of files, each built to answer one question about the system under test. - + + Ready-made sets of files, each built to answer one question about the system under test. @@ -71,10 +69,8 @@ The question - - - - + + @@ -179,10 +175,8 @@ Settings - - - - + + @@ -221,12 +215,10 @@ - + - - - - + + @@ -313,10 +305,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/preset-menu.xml b/internal/guard/testdata/screens/preset-menu.xml index 35f04ad..e658e2b 100644 --- a/internal/guard/testdata/screens/preset-menu.xml +++ b/internal/guard/testdata/screens/preset-menu.xml @@ -43,12 +43,10 @@ - + - - - Ready-made sets of files, each built to answer one question about the system under test. - + + Ready-made sets of files, each built to answer one question about the system under test. @@ -71,10 +69,8 @@ The question - - - - + + @@ -189,10 +185,8 @@ Settings - - - - + + @@ -255,10 +249,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/preset-refused.xml b/internal/guard/testdata/screens/preset-refused.xml index c3c7434..f3d2d05 100644 --- a/internal/guard/testdata/screens/preset-refused.xml +++ b/internal/guard/testdata/screens/preset-refused.xml @@ -43,12 +43,10 @@ - + - - - Ready-made sets of files, each built to answer one question about the system under test. - + + Ready-made sets of files, each built to answer one question about the system under test. @@ -71,10 +69,8 @@ The question - - - - + + @@ -179,10 +175,8 @@ Settings - - - - + + @@ -219,12 +213,10 @@ - + - - - 512 B - + + 512 B @@ -322,10 +314,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/preset.xml b/internal/guard/testdata/screens/preset.xml index 0ad5019..8f60917 100644 --- a/internal/guard/testdata/screens/preset.xml +++ b/internal/guard/testdata/screens/preset.xml @@ -43,12 +43,10 @@ - + - - - Ready-made sets of files, each built to answer one question about the system under test. - + + Ready-made sets of files, each built to answer one question about the system under test. @@ -71,10 +69,8 @@ The question - - - - + + @@ -189,10 +185,8 @@ Settings - - - - + + @@ -255,10 +249,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/recipe-contents.xml b/internal/guard/testdata/screens/recipe-contents.xml index 1c2a457..e1a2ea2 100644 --- a/internal/guard/testdata/screens/recipe-contents.xml +++ b/internal/guard/testdata/screens/recipe-contents.xml @@ -43,12 +43,10 @@ - + - - - Batches of different formats and sizes, generated together in one run. - + + Batches of different formats and sizes, generated together in one run. @@ -72,10 +70,8 @@ Build on a preset - - - - + + @@ -84,13 +80,11 @@ - + - - - With the box ticked, the chosen preset's files come first and the batches below are added after them. Without it, the batches are the whole - recipe. - + + With the box ticked, the chosen preset's files come first and the batches below are added after them. Without it, the batches are the whole + recipe. @@ -131,8 +125,8 @@ - - + + @@ -140,10 +134,8 @@ Batch 1 - - - - + + @@ -263,12 +255,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -357,10 +347,8 @@ Settings for zip - - - - + + @@ -393,10 +381,8 @@ Notes for the manifest - - - - + + @@ -526,10 +512,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/recipe-on-a-preset.xml b/internal/guard/testdata/screens/recipe-on-a-preset.xml index cdb66af..a23c2e4 100644 --- a/internal/guard/testdata/screens/recipe-on-a-preset.xml +++ b/internal/guard/testdata/screens/recipe-on-a-preset.xml @@ -43,12 +43,10 @@ - + - - - Batches of different formats and sizes, generated together in one run. - + + Batches of different formats and sizes, generated together in one run. @@ -72,10 +70,8 @@ Build on a preset - - - - + + @@ -84,13 +80,11 @@ - + - - - With the box ticked, the chosen preset's files come first and the batches below are added after them. Without it, the batches are the whole - recipe. - + + With the box ticked, the chosen preset's files come first and the batches below are added after them. Without it, the batches are the whole + recipe. @@ -190,8 +184,8 @@ - - + + @@ -199,10 +193,8 @@ Batch 1 - - - - + + @@ -327,12 +319,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -421,10 +411,8 @@ Settings for avif - - - - + + @@ -457,10 +445,8 @@ Notes for the manifest - - - - + + @@ -496,10 +482,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/recipe-refused-with-one-batch-filled.xml b/internal/guard/testdata/screens/recipe-refused-with-one-batch-filled.xml index 47c32ff..16f6acf 100644 --- a/internal/guard/testdata/screens/recipe-refused-with-one-batch-filled.xml +++ b/internal/guard/testdata/screens/recipe-refused-with-one-batch-filled.xml @@ -43,12 +43,10 @@ - + - - - Batches of different formats and sizes, generated together in one run. - + + Batches of different formats and sizes, generated together in one run. @@ -72,10 +70,8 @@ Build on a preset - - - - + + @@ -84,13 +80,11 @@ - + - - - With the box ticked, the chosen preset's files come first and the batches below are added after them. Without it, the batches are the whole - recipe. - + + With the box ticked, the chosen preset's files come first and the batches below are added after them. Without it, the batches are the whole + recipe. @@ -131,8 +125,8 @@ - - + + @@ -140,10 +134,8 @@ Batch 1 - - - - + + @@ -271,12 +263,10 @@ - + - - - - + + @@ -391,10 +381,8 @@ Settings for avif - - - - + + @@ -427,10 +415,8 @@ Notes for the manifest - - - - + + @@ -454,8 +440,8 @@ - - + + @@ -463,10 +449,8 @@ Batch 2 - - - - + + @@ -591,12 +575,10 @@ - + - - - 1 024 B - + + 1 024 B @@ -685,10 +667,8 @@ Settings for avif - - - - + + @@ -721,10 +701,8 @@ Notes for the manifest - - - - + + @@ -760,10 +738,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/recipe-refused.xml b/internal/guard/testdata/screens/recipe-refused.xml index 60c7752..856c46e 100644 --- a/internal/guard/testdata/screens/recipe-refused.xml +++ b/internal/guard/testdata/screens/recipe-refused.xml @@ -43,12 +43,10 @@ - + - - - Batches of different formats and sizes, generated together in one run. - + + Batches of different formats and sizes, generated together in one run. @@ -72,10 +70,8 @@ Build on a preset - - - - + + @@ -84,13 +80,11 @@ - + - - - With the box ticked, the chosen preset's files come first and the batches below are added after them. Without it, the batches are the whole - recipe. - + + With the box ticked, the chosen preset's files come first and the batches below are added after them. Without it, the batches are the whole + recipe. @@ -131,8 +125,8 @@ - - + + @@ -140,10 +134,8 @@ Batch 1 - - - - + + @@ -266,12 +258,10 @@ - + - - - - + + @@ -386,10 +376,8 @@ Settings for avif - - - - + + @@ -422,10 +410,8 @@ Notes for the manifest - - - - + + @@ -461,10 +447,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/recipe-two-batches.xml b/internal/guard/testdata/screens/recipe-two-batches.xml index 7ab1938..d7c2c96 100644 --- a/internal/guard/testdata/screens/recipe-two-batches.xml +++ b/internal/guard/testdata/screens/recipe-two-batches.xml @@ -43,12 +43,10 @@ - + - - - Batches of different formats and sizes, generated together in one run. - + + Batches of different formats and sizes, generated together in one run. @@ -72,10 +70,8 @@ Build on a preset - - - - + + @@ -84,13 +80,11 @@ - + - - - With the box ticked, the chosen preset's files come first and the batches below are added after them. Without it, the batches are the whole - recipe. - + + With the box ticked, the chosen preset's files come first and the batches below are added after them. Without it, the batches are the whole + recipe. @@ -131,8 +125,8 @@ - - + + @@ -140,10 +134,8 @@ Batch 1 - - - - + + @@ -268,12 +260,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -362,10 +352,8 @@ Settings for avif - - - - + + @@ -398,10 +386,8 @@ Notes for the manifest - - - - + + @@ -425,8 +411,8 @@ - - + + @@ -434,10 +420,8 @@ Batch 2 - - - - + + @@ -565,12 +549,10 @@ - + - - - - + + @@ -662,10 +644,8 @@ Settings for avif - - - - + + @@ -698,10 +678,8 @@ Notes for the manifest - - - - + + @@ -737,10 +715,8 @@ Output - - - - + + diff --git a/internal/guard/testdata/screens/recipe.xml b/internal/guard/testdata/screens/recipe.xml index 1793be3..266bcdf 100644 --- a/internal/guard/testdata/screens/recipe.xml +++ b/internal/guard/testdata/screens/recipe.xml @@ -43,12 +43,10 @@ - + - - - Batches of different formats and sizes, generated together in one run. - + + Batches of different formats and sizes, generated together in one run. @@ -72,10 +70,8 @@ Build on a preset - - - - + + @@ -84,13 +80,11 @@ - + - - - With the box ticked, the chosen preset's files come first and the batches below are added after them. Without it, the batches are the whole - recipe. - + + With the box ticked, the chosen preset's files come first and the batches below are added after them. Without it, the batches are the whole + recipe. @@ -131,8 +125,8 @@ - - + + @@ -140,10 +134,8 @@ Batch 1 - - - - + + @@ -263,12 +255,10 @@ - + - - - 10 485 760 B - + + 10 485 760 B @@ -357,10 +347,8 @@ Settings for avif - - - - + + @@ -393,10 +381,8 @@ Notes for the manifest - - - - + + @@ -432,10 +418,8 @@ Output - - - - + + diff --git a/internal/guard/themescope_test.go b/internal/guard/themescope_test.go new file mode 100644 index 0000000..a48c840 --- /dev/null +++ b/internal/guard/themescope_test.go @@ -0,0 +1,66 @@ +package guard + +import ( + "testing" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/test" + + "github.com/donislawdev/TestingFilesGenerator/internal/gui/catalogue" + "github.com/donislawdev/TestingFilesGenerator/internal/gui/parts" +) + +// No screen, and nothing in the catalogue of parts, stands in a theme override. +// +// An override is the toolkit's one public door into a subtree's theme, and it +// costs memory that never comes back. Fyne 2.8.1 gives an override a NEW scope +// at construction, at CreateRenderer and at every Refresh, and keys its parsed +// fonts by scope - so every rebuild of a screen followed by a new string drawn +// under an override parsed another ~7.4 MB set of fonts. Measured in the real +// window on 2026-09-23 (tools/probes/guilag, docs/GUI-MEMORY-2026-09-23.md +// section 4c): 26 sets after visiting the tabs, a live heap of 205 MB, and ten +// rebuilds each followed by a new size added 84 MB more. Every sentence, error +// area, caption and count of bytes was under one. Without them: 2 sets, 27 MB, +// and nothing added by the rebuilds. +// +// The open list of formats is not on this screen - it is a popup - and it +// still draws its rows under one (parts/openlist.go, rowTheme). That is the +// next thing the same document names, and it is named here so that nobody +// reads this guard as covering it. +func TestNoScreenStandsInAThemeOverride(t *testing.T) { + content, _ := laidOutWindow(t) + + quiet, counts := 0, 0 + walk(content, func(o fyne.CanvasObject) { + switch o.(type) { + case *parts.QuietText: + quiet++ + case *parts.ByteCount: + counts++ + } + }) + // The things that stood under an override until 2026-09-23 have to be on + // the screen for their absence from one to mean anything: a subtitle on + // each of three work screens, and the count of bytes beside a size. + if quiet < 3 || counts < 1 { + t.Fatalf("the window holds %d quiet line(s) and %d count(s) of bytes, so this guard is not "+ + "looking at the screens it asks about", quiet, counts) + } + + cat := test.NewWindow(catalogue.Screen()) + t.Cleanup(cat.Close) + + for name, root := range map[string]fyne.CanvasObject{"the window": content, "the catalogue": cat.Content()} { + overrides := 0 + walk(root, func(o fyne.CanvasObject) { + if _, is := o.(*container.ThemeOverride); is { + overrides++ + } + }) + if overrides > 0 { + t.Errorf("%s holds %d theme override(s), and each one parses the fonts again in a scope of its own - "+ + "take the room off with a layout (inkTight) and name the colour in the words (QuietText)", name, overrides) + } + } +} diff --git a/internal/guard/words_test.go b/internal/guard/words_test.go index 7deff14..b263e34 100644 --- a/internal/guard/words_test.go +++ b/internal/guard/words_test.go @@ -4,6 +4,8 @@ import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/widget" + + "github.com/donislawdev/TestingFilesGenerator/internal/gui/parts" ) // wordsOf is the text an object shows, whichever of the two kinds of object @@ -19,6 +21,10 @@ import ( // one place the two kinds are told apart, so the next kind is one more case // here rather than a hunt through thirty type assertions. // +// The third kind since 2026-09-23: parts.QuietText, the words that recede - +// a subtitle, a caption, a folded section's line, the count of bytes - which +// stopped being toolkit labels under a theme override (see QuietText). +// // A hidden object still answers. Whether something is on the screen is a // question about its ancestors as well, and sizechoice_test.go asks it // properly. Nothing here filters. @@ -28,6 +34,10 @@ func wordsOf(o fyne.CanvasObject) (string, bool) { return v.Text, true case *canvas.Text: return v.Text, true + case *parts.QuietText: + return v.Text, true + case *parts.ByteCount: + return v.Text, true } return "", false } @@ -46,6 +56,20 @@ func boldWordsAt(o fyne.CanvasObject) (text string, bold bool, size float32, ok return v.Text, v.TextStyle.Bold, fyne.CurrentApp().Settings().Theme().Size(name), true case *canvas.Text: return v.Text, v.TextStyle.Bold, v.TextSize, true + case *parts.QuietText: + return v.Text, false, quietSize(v), true + case *parts.ByteCount: + return v.Text, false, quietSize(&v.QuietText), true } return "", false, 0, false } + +// quietSize is the size quiet words are drawn at: their rank of the scale, +// the body text when none is named - the rule widget.Label keeps. +func quietSize(q *parts.QuietText) float32 { + name := q.SizeName + if name == "" { + name = "text" + } + return fyne.CurrentApp().Settings().Theme().Size(name) +} diff --git a/internal/gui/catalogue/words.go b/internal/gui/catalogue/words.go index 9eb2168..454757a 100644 --- a/internal/gui/catalogue/words.go +++ b/internal/gui/catalogue/words.go @@ -13,7 +13,7 @@ import ( // thing a person looks at as a whole, which is why every rank is here once, // one under another, and once more with a long line to see where it wraps. func textRanks() Entry { - return Entry{Name: "Title", Covers: []string{"Subtitle", "Titled", "Heading", "Subheading", "Prose", "Note", "Caption", "Bullets", "Ledger"}, States: []State{ + return Entry{Name: "Title", Covers: []string{"Subtitle", "Titled", "Heading", "Subheading", "Prose", "Note", "Caption", "QuietText", "Bullets", "Ledger"}, States: []State{ {"the title of a screen", func() fyne.CanvasObject { return parts.Title("Single batch") }}, {"the sentence under a title", func() fyne.CanvasObject { return parts.Subtitle("Files of one format and one size, with a manifest that says how the system under test should react to them.") diff --git a/internal/gui/parts/bytecount.go b/internal/gui/parts/bytecount.go index e4c6495..89d3923 100644 --- a/internal/gui/parts/bytecount.go +++ b/internal/gui/parts/bytecount.go @@ -2,7 +2,6 @@ package parts import ( "fyne.io/fyne/v2/theme" - "fyne.io/fyne/v2/widget" "github.com/donislawdev/TestingFilesGenerator/internal/core" ) @@ -28,18 +27,21 @@ import ( // Spelled by core.ExactBytes, which is what the command line prints. The // window had a spelling of its own without the grouping until 2026-09-14, so // one number came out as 10485760 B here and 10 485 760 B there. +// +// Quiet words since 2026-09-23, rather than a low importance label under a +// theme override - see QuietText for what the override cost. type ByteCount struct { - widget.Label + QuietText } func newByteCount() *ByteCount { c := &ByteCount{} + c.start("") c.ExtendBaseWidget(c) // The same rank as the line explaining a field, because it is the same kind // of thing: something quiet beside a control that the eye should skip until // it wants it. c.SizeName = theme.SizeNameCaptionText - c.Importance = widget.LowImportance return c } diff --git a/internal/gui/parts/field.go b/internal/gui/parts/field.go index 2f8309d..716d7c4 100644 --- a/internal/gui/parts/field.go +++ b/internal/gui/parts/field.go @@ -130,16 +130,15 @@ func shapedForItsValues(control fyne.CanvasObject) fyne.CanvasObject { // worse than the italics it was replacing. So it went in as ordinary text // until the palette arrived. // -// It goes through quiet rather than inkTight since 2026-09-15, which is O213: +// It is QuietText since 2026-09-23 and was a quiet label before, which is O213: // widget.LowImportance draws in ColorNameDisabled, #C2C8CD at 80 L*, a step -// brighter than the hint a caption is meant to be. quiet remaps it to the +// brighter than the hint a caption is meant to be. QuietText draws the // placeholder, #9DA3A8 at 66.7 L*, 5.61:1 on a panel. O70 and O71. func Note(content string) fyne.CanvasObject { - label := widget.NewLabel(content) - label.Wrapping = fyne.TextWrapWord - label.Importance = widget.LowImportance - label.SizeName = theme.SizeNameCaptionText - return quiet(label) + note := NewQuietText(content) + note.Wrapping = fyne.TextWrapWord + note.SizeName = theme.SizeNameCaptionText + return note } // ErrorArea is where a field says what a run said about it. diff --git a/internal/gui/parts/fields.go b/internal/gui/parts/fields.go index d944505..9ae19b2 100644 --- a/internal/gui/parts/fields.go +++ b/internal/gui/parts/fields.go @@ -226,10 +226,9 @@ func (s *Fields) counter(setting string, control fyne.CanvasObject) fyne.CanvasO // Beside the box on its own line, with no room of its own around the ink, // so what the row puts between the box and the count is what reaches the // screen. Until 2026-09-14 it stood at the far end of the name's line, 190 - // px from the box it was counting for. Drawn through quiet since 2026-09-15 - // - it is a low importance label, so the same O213 that dimmed a caption - // dimmed this. See parts.quiet. - return quiet(count) + // px from the box it was counting for. Quiet words since 2026-09-15 - the + // same O213 that dimmed a caption dimmed this. See QuietText. + return count } // Add builds a field and hands back the thing to put on the screen. diff --git a/internal/gui/parts/folding.go b/internal/gui/parts/folding.go index 4629234..faa8b01 100644 --- a/internal/gui/parts/folding.go +++ b/internal/gui/parts/folding.go @@ -36,7 +36,7 @@ type Folding struct { open bool title string body fyne.CanvasObject - line *widget.Label + line *QuietText // head is the one control the whole head row is - see FoldHead. head *FoldHead @@ -167,8 +167,7 @@ type groupCell struct{ wideCell } func newFolding(title string, titled fyne.CanvasObject, head []fyne.CanvasObject, content ...fyne.CanvasObject) *Folding { f := &Folding{open: true, title: title} - f.line = widget.NewLabel("") - f.line.Importance = widget.LowImportance + f.line = NewQuietText("") f.line.Hide() f.body = Grid(content...) @@ -182,7 +181,7 @@ func newFolding(title string, titled fyne.CanvasObject, head []fyne.CanvasObject // (TestEverythingAPersonReadsStartsOnOneLeftEdge). Indenting the section's // contents to match would put its fields off that edge instead, which is // worse - there are more of them and they are what somebody is reading. - // The summary line goes through quiet, so it recedes to the hint's colour + // The summary line is QuietText, so it recedes to the hint's colour // rather than the brighter disabled one widget.LowImportance draws (O213). // // The whole row is the control, since O221, and the arrow is its mark @@ -198,7 +197,14 @@ func newFolding(title string, titled fyne.CanvasObject, head []fyne.CanvasObject // words it was a 6 px triangle at the end of a heading, and the heading // read as an orphaned subtitle rather than as something that opens. The // arrow now stands on the left edge and the words start after it. - words := Padded(TabInset, container.NewHBox(arrow, titled, quiet(f.line))) + // + // The line stands in a container of its own that never hides, so the row + // keeps the gap before it even while the line is hidden - which is how the + // head of an open section gets as much room after its title as before its + // arrow. The line sat inside a theme override until 2026-09-23, and it was + // the override that stayed visible. Taking the override away took 4 px off + // the right of every open head, measured on the stored catalogue. + words := Padded(TabInset, container.NewHBox(arrow, titled, container.NewStack(f.line))) f.head.under = words row := container.NewBorder(nil, nil, nil, ButtonRow(head...), container.NewStack(f.head, words)) diff --git a/internal/gui/parts/parts.go b/internal/gui/parts/parts.go index 8017a66..787f8de 100644 --- a/internal/gui/parts/parts.go +++ b/internal/gui/parts/parts.go @@ -21,8 +21,6 @@ package parts import ( - "image/color" - "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" @@ -118,18 +116,17 @@ func oneLine(text string, size fyne.ThemeSizeName) fyne.CanvasObject { // hint rather than of a value, so it reads as an explanation of the word above // it and not as a second heading competing with it. // -// A toolkit label rather than canvas words, because a sentence wraps and a +// Wrapping words rather than canvas words, because a sentence wraps and a // name does not - the same split words and Prose make. Its colour is the // hint's, the same step the words on the strip stand at when they are not -// chosen, so the head of a screen has one quiet colour and not two. Asked for -// through quiet below, because the toolkit draws a low importance label in the -// DISABLED colour, and this palette keeps that a step brighter than a hint on -// purpose - see ColorNameDisabled in theme.go. +// chosen, so the head of a screen has one quiet colour and not two. QuietText, +// because the toolkit draws a low importance label in the DISABLED colour, and +// this palette keeps that a step brighter than a hint on purpose - see +// ColorNameDisabled in theme.go. func Subtitle(sentence string) fyne.CanvasObject { - label := widget.NewLabel(sentence) - label.Wrapping = fyne.TextWrapWord - label.Importance = widget.LowImportance - return quiet(label) + subtitle := NewQuietText(sentence) + subtitle.Wrapping = fyne.TextWrapWord + return subtitle } // Caption is a short quiet line over or under a thing, at the smallest rank @@ -138,39 +135,10 @@ func Subtitle(sentence string) fyne.CanvasObject { // on 2026-09-15 when a second thing needed it - a rank used twice without a // name is GUI rule 7's definition of a missing style. func Caption(text string) fyne.CanvasObject { - label := widget.NewLabel(text) - label.Wrapping = fyne.TextWrapWord - label.SizeName = theme.SizeNameCaptionText - label.Importance = widget.LowImportance - return quiet(label) -} - -// quiet draws a low importance label in the hint's colour rather than the -// disabled one, and takes the room a label keeps around itself off it. -// -// One helper rather than one at each call site, because O213 was four call -// sites saying different things: a caption under a field, the count of bytes, a -// folded section's summary and this subtitle were all widget.LowImportance, -// which the toolkit draws in ColorNameDisabled - #C2C8CD, 80 L*, a step -// BRIGHTER than a hint. So a caption meant to recede sat louder than the -// placeholder in an empty box beside it. Owner's decision on 2026-09-15: one -// quiet, the hint's, and the disabled colour kept for a value that is switched -// off - which is content somebody may want to re-read and so is right to be the -// brighter of the two. -func quiet(o fyne.CanvasObject) fyne.CanvasObject { - return container.NewThemeOverride(o, quietInk{noInnerPadding{Theme()}}) -} - -// quietInk is the window's theme with a low importance label drawn in the -// hint's colour rather than the disabled one, and without the room a label -// keeps around itself. -type quietInk struct{ noInnerPadding } - -func (q quietInk) Color(name fyne.ThemeColorName, variant fyne.ThemeVariant) color.Color { - if name == theme.ColorNameDisabled { - return q.noInnerPadding.Color(theme.ColorNamePlaceHolder, variant) - } - return q.noInnerPadding.Color(name, variant) + caption := NewQuietText(text) + caption.Wrapping = fyne.TextWrapWord + caption.SizeName = theme.SizeNameCaptionText + return caption } // Titled is what stands above a screen's sections: its name, and under it the diff --git a/internal/gui/parts/quiet.go b/internal/gui/parts/quiet.go new file mode 100644 index 0000000..b6575ff --- /dev/null +++ b/internal/gui/parts/quiet.go @@ -0,0 +1,95 @@ +package parts + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" +) + +// QuietText is words that recede: a screen's subtitle, a caption, the line a +// folded section keeps, the count of bytes beside a size. Drawn in the hint's +// colour, with no room of its own around the ink. +// +// The hint's colour and not the disabled one is O213, the owner's decision of +// 2026-09-15: the toolkit draws a low importance label in ColorNameDisabled, +// #C2C8CD at 80 L*, a step BRIGHTER than a hint - so a caption meant to recede +// sat louder than the placeholder in an empty box beside it. The disabled +// colour stays for a value that is switched off. +// +// Its own widget rather than a toolkit label under a theme override, since +// 2026-09-23. A label's colour follows its importance and nothing else, so the +// only way to give it the hint's colour was an override - and Fyne gives an +// override a new scope at construction, at CreateRenderer and at every +// Refresh, and parses a fresh ~7.4 MB set of fonts for every scope a new +// string is drawn in. Measured in the real window: ten rebuilds of the batch +// screen, each followed by a new size, parsed ten sets for the count of bytes +// alone, and nothing frees them (docs/GUI-MEMORY-2026-09-23.md section 4c). +// A rich text names its colour per segment, so none of that is needed. +// +// The segment is the one widget.Label builds for itself (widget/label.go, +// syncSegments), with the colour changed and nothing else, and the room is +// taken off by the layout inkTight uses - so what reaches the screen is what +// the label under the override drew, pixel for pixel on every stored screen. +// +// Like a label it does not wrap unless asked to. +type QuietText struct { + widget.BaseWidget + + // Text is what it says, SizeName the rank of the scale it says it at + // (the body text when empty), and Wrapping whether a long line breaks. + Text string + SizeName fyne.ThemeSizeName + Wrapping fyne.TextWrap + + rich *widget.RichText +} + +// NewQuietText makes quiet words. +func NewQuietText(text string) *QuietText { + q := &QuietText{} + q.start(text) + q.ExtendBaseWidget(q) + return q +} + +// start is what every QuietText needs before it is drawn, a ByteCount +// included - which is a QuietText inside and extends itself rather than this. +func (q *QuietText) start(text string) { + q.Text = text + q.rich = widget.NewRichText(&widget.TextSegment{}) +} + +// SetText changes what it says. +func (q *QuietText) SetText(text string) { + q.Text = text + q.Refresh() +} + +// Refresh carries the fields into the segment before anything is redrawn. +func (q *QuietText) Refresh() { + q.sync() + q.rich.Refresh() + q.BaseWidget.Refresh() +} + +// CreateRenderer draws the rich text ink tight. +func (q *QuietText) CreateRenderer() fyne.WidgetRenderer { + q.sync() + return widget.NewSimpleRenderer(inkTight(q.rich)) +} + +// sync is widget.Label's syncSegments with the hint's colour. +func (q *QuietText) sync() { + size := q.SizeName + if size == "" { + size = theme.SizeNameText + } + q.rich.Wrapping = q.Wrapping + segment := q.rich.Segments[0].(*widget.TextSegment) + segment.Text = q.Text + segment.Style = widget.RichTextStyle{ + ColorName: theme.ColorNamePlaceHolder, + Inline: true, + SizeName: size, + } +} diff --git a/internal/gui/parts/words.go b/internal/gui/parts/words.go index 0654eb0..6218f96 100644 --- a/internal/gui/parts/words.go +++ b/internal/gui/parts/words.go @@ -86,18 +86,6 @@ func (inkTightLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) { // - which has to be built by the runner and placed by the bar. func Flush(label *widget.Label) fyne.CanvasObject { return inkTight(label) } -// noInnerPadding is the window's theme with the room inside a label taken out. -// Only that one size, so a box to type in under the same override would still -// be a box. -type noInnerPadding struct{ fyne.Theme } - -func (n noInnerPadding) Size(name fyne.ThemeSizeName) float32 { - if name == theme.SizeNameInnerPadding { - return 0 - } - return n.Theme.Size(name) -} - // Padded keeps one distance from the scale between its edge and its content. // // The toolkit's padded container reads the theme's padding, which is the From 0957e5f7ceb571ffc8154df91b3336699b0360c7 Mon Sep 17 00:00:00 2001 From: DonislawDev Date: Wed, 23 Sep 2026 18:11:43 +0200 Subject: [PATCH 3/4] changelog: the window's memory Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d08446a..8a9359a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -475,6 +475,15 @@ because it turns other people's test suites red. ### Fixed +- **The window uses far less memory, and no longer grows with use.** Every + quiet line on a screen - a subtitle, a caption, the count of bytes beside a + size, the line a folded section keeps, the message under a field - parsed + its own copy of the fonts, and parsed another each time the screen was + rebuilt and the line said something new. After visiting the four tabs the + window held about 290 MB and it now holds about 120 MB, and rebuilding a + screen no longer adds to it. Nothing on the screen looks different. The open + list of formats still does this when you type into its filter, and is next. + - **The `Several batches` screen no longer slows down the longer it is used.** Every batch added, removed or copied, every format chosen and every press of `Start from a preset` made each box on the screen report a change From d5932da2a33eaea73d0ddd393c63fccabb0a921b Mon Sep 17 00:00:00 2001 From: DonislawDev Date: Wed, 23 Sep 2026 20:06:57 +0200 Subject: [PATCH 4/4] gui: quiet words refresh their text once, and the changelog claims only what was measured QuietText.Refresh refreshed its rich text itself and then again through the renderer, whose container refreshes every child - the shape copied from widget.Label, surplus included. The count of bytes redraws on every key. All 28 stored screens stay pixel for pixel the same, generate-typed among them, whose count is drawn after the first frame. The changelog heading said the window no longer grows with use while the same entry says the filter of the format list still does. It now says what was measured: rebuilding a screen no longer adds to it. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 3 ++- internal/gui/parts/quiet.go | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a9359a..a84e35d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -475,7 +475,8 @@ because it turns other people's test suites red. ### Fixed -- **The window uses far less memory, and no longer grows with use.** Every +- **The window uses far less memory, and rebuilding a screen no longer adds + to it.** Every quiet line on a screen - a subtitle, a caption, the count of bytes beside a size, the line a folded section keeps, the message under a field - parsed its own copy of the fonts, and parsed another each time the screen was diff --git a/internal/gui/parts/quiet.go b/internal/gui/parts/quiet.go index b6575ff..f28dc54 100644 --- a/internal/gui/parts/quiet.go +++ b/internal/gui/parts/quiet.go @@ -66,9 +66,11 @@ func (q *QuietText) SetText(text string) { } // Refresh carries the fields into the segment before anything is redrawn. +// The rich text is refreshed once, by the renderer through its container - +// widget.Label refreshes its own twice, which a count redrawn on every key +// has no need of. func (q *QuietText) Refresh() { q.sync() - q.rich.Refresh() q.BaseWidget.Refresh() }