diff --git a/CHANGELOG.md b/CHANGELOG.md index cf137bd..4245d57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,16 @@ because it turns other people's test suites red. ### Changed +- **The window says where things begin and end.** Every field's name now + stands above its box rather than beside it, in a lighter ink than the + value under it, so a form reads as a column of named boxes. A section + draws a line round its edge again. Preview, Choose, Duplicate and Add a + batch stand on a surface of their own, brighter than a box to type in, so + a button no longer looks like a field. A folded block of settings inside + a section is titled at the rank of a subheading rather than a section, and + the pointer lights only its words rather than the whole row. A field's + explanation opens with an edge and a shadow, so it reads as something laid + over the form rather than a patch of it. - **Nine things the owner saw in the running window.** A field's explanation opens on the same raised surface as an open list, so it no longer lies flat on the section it covers. A list of formats keeps its diff --git a/internal/guard/controlstates_test.go b/internal/guard/controlstates_test.go index 873b33c..4f7ea93 100644 --- a/internal/guard/controlstates_test.go +++ b/internal/guard/controlstates_test.go @@ -271,8 +271,17 @@ func TestASecondaryButtonWearsAFaceAtRest(t *testing.T) { return nil } rest := faceOf() - if want := parts.PaletteColour(theme.ColorNameInputBackground, theme.VariantDark); rest != want { - t.Errorf("at rest the face is %v and should be the surface of a box to type in, %v - an outline round nothing reads as a bordered word", rest, want) + // The button's own surface since 2026-09-21, and a step brighter than a + // box to type in: the owner's report from the running window was that a + // button wearing the field's surface read as a field. Asked as a + // relationship, not only as a name, so a palette edit that lowers the + // button under the field goes red here rather than on the screen. + if want := parts.PaletteColour(theme.ColorNameButton, theme.VariantDark); rest != want { + t.Errorf("at rest the face is %v and should be the button's own surface, %v - a button in the field's colour reads as a field", rest, want) + } + field := parts.PaletteColour(theme.ColorNameInputBackground, theme.VariantDark) + if gap := lightnessGap(rest, field); gap < 5 { + t.Errorf("the button's face is %.1f L* off a box to type in, and 5 is the least that tells a thing to press from a thing to type in", gap) } b.MouseIn(&desktop.MouseEvent{}) hovered := faceOf() diff --git a/internal/guard/detailpopup_test.go b/internal/guard/detailpopup_test.go index 59ab703..d3363ca 100644 --- a/internal/guard/detailpopup_test.go +++ b/internal/guard/detailpopup_test.go @@ -252,21 +252,37 @@ func TestTheExplanationFloatsOnTheSurfaceAnOpenListDoes(t *testing.T) { t.Fatal("hovering the button put nothing on the sheet, so there is no box to measure") } - var surface *canvas.Rectangle + // Two rectangles since 2026-09-21: the shade the box casts, then the + // surface it stands on. The owner's report from the running window was + // that a flat box with no edge read as a random rectangle, so the + // surface wears a line and a shade shows below it. Each is asked for by + // what it is rather than by its place in the tree. + var surface, shade *canvas.Rectangle + want := parts.PaletteColour(theme.ColorNameMenuBackground, theme.VariantDark) walk(box, func(o fyne.CanvasObject) { - if rect, is := o.(*canvas.Rectangle); is && surface == nil { + rect, is := o.(*canvas.Rectangle) + if !is { + return + } + if rect.FillColor == want && surface == nil { surface = rect + } else if _, _, _, a := rect.FillColor.RGBA(); a > 0 && a < 0xFFFF && shade == nil { + shade = rect } }) if surface == nil { - t.Fatal("the explanation's box draws no rectangle, so it stands on nothing this guard can measure") - } - want := parts.PaletteColour(theme.ColorNameMenuBackground, theme.VariantDark) - if surface.FillColor != want { - t.Errorf("the explanation stands on %v and an open list on %v - a box the colour of the panel it opens over has no edge anywhere", - surface.FillColor, want) + t.Fatal("the explanation's box draws no rectangle in the colour of an open list, so it stands on nothing that floats") } if surface.CornerRadius != parts.RadiusField { t.Errorf("the explanation's corner is %.0f and a floating control's is %d", surface.CornerRadius, parts.RadiusField) } + if surface.StrokeWidth == 0 { + t.Error("the explanation's surface has no line round it, which is the random rectangle the owner saw") + } + if shade == nil { + t.Error("the explanation casts no shade, so nothing says it lies over the form rather than in it") + } else if shade.Position().Y <= surface.Position().Y { + t.Errorf("the shade sits at y=%.0f and the surface at y=%.0f - a shade that is not below the box it belongs to reads as a smudge", + shade.Position().Y, surface.Position().Y) + } } diff --git a/internal/guard/foldhead_test.go b/internal/guard/foldhead_test.go index ff0f142..58d291c 100644 --- a/internal/guard/foldhead_test.go +++ b/internal/guard/foldhead_test.go @@ -197,6 +197,23 @@ func TestTheHeadRowDrawsItsStatesAndTheArrowFollows(t *testing.T) { if want := parts.PaletteColour(theme.ColorNameHover, theme.VariantDark); back.FillColor != want { t.Errorf("under the pointer the row's fill is %v, not the hover colour %v", back.FillColor, want) } + // The fill is as wide as the words and no wider, since 2026-09-21: the + // owner's report from the running window was a hover the width of the + // form, which is enormous. The row is still the target - the head is as + // wide as the row - so the two widths are asked for apart: the head wide, + // its fill narrow. + // Bounded from both sides, after the outside review of #116: "narrower + // than the row" alone would have let a one pixel fill through. The fill + // has to be at least as wide as the title it lights, and narrower than + // the row it stands in. + title, ok := labelBox(fold.Object(), "Notes for the manifest") + if !ok { + t.Fatal("the fold's title is not on the screen, so there is nothing to measure the fill against") + } + if row, fill := head.Size().Width, back.Size().Width; fill >= row || fill < title.Width { + t.Errorf("under the pointer the fill is %.0f px wide, the title %.0f and the head %.0f - the fill has to cover the words and stop short of the row", + fill, title.Width, row) + } if arrow.Resource.Name() == restingArrow { t.Error("the arrow is inked the same under the pointer as at rest, so it does not follow the row") } diff --git a/internal/guard/guitext_test.go b/internal/guard/guitext_test.go index 709757d..d057825 100644 --- a/internal/guard/guitext_test.go +++ b/internal/guard/guitext_test.go @@ -108,6 +108,8 @@ var notWords = map[string]string{ `"%s: %w"`: "how one error is wrapped around another, both already worded", `"•"`: "the marker in front of a list item, a shape rather than a word", `"panel"`: "our name for a colour, in the palette the toolkit asks by name", + `"label"`: "our name for the ink of a field's name, a colour the palette holds", + `"tipshade"`: "our name for the shade under an explanation, a colour the palette holds", `"lift"`: "our name for what the pointer does to the filled button, a colour the palette holds", `"shade"`: "our name for what a press does to the filled button, a colour the palette holds", `"fyneDo"`: "a migration flag the toolkit reads, never shown", diff --git a/internal/guard/namescolumn_test.go b/internal/guard/namescolumn_test.go deleted file mode 100644 index 1259862..0000000 --- a/internal/guard/namescolumn_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package guard - -import ( - "testing" - - "fyne.io/fyne/v2" - - "github.com/donislawdev/TestingFilesGenerator/internal/damage" - "github.com/donislawdev/TestingFilesGenerator/internal/format" - "github.com/donislawdev/TestingFilesGenerator/internal/gui/parts" - "github.com/donislawdev/TestingFilesGenerator/internal/gui/text" - "github.com/donislawdev/TestingFilesGenerator/internal/gui/window" - "github.com/donislawdev/TestingFilesGenerator/internal/preset" -) - -// Every name a screen can show is in the list the column of names is worked -// out from. -// -// The column is one width for the whole window, taken from every name the -// window can ever draw - window.EveryFieldName - so that choosing a format -// with a long setting name does not move every box on the screen. That list -// is written by hand, and a list written by hand is missing something the day -// after it is written: a name that is not in it draws at its own width, wider -// than the column, and its box starts to the right of every other box. -// -// So the names are read off the screens, with every format, every damage and -// every preset chosen in turn, and each one is asked whether the list has it. -// The screens are the source and the list is what is checked, which is the -// direction that finds the missing entry rather than the one that confirms -// the entries there are. -func TestEveryNameOnAScreenIsInTheListTheColumnIsWorkedOutFrom(t *testing.T) { - ourTheme(t) - content, _ := laidOutWindow(t) - - listed := map[string]bool{} - for _, name := range window.EveryFieldName() { - listed[name] = true - } - if len(listed) == 0 { - t.Fatal("the window lists no names at all, so there is nothing to compare") - } - - seen := map[string]bool{} - note := func(screen fyne.CanvasObject) { - for _, name := range fieldNamesOn(screen) { - seen[name] = true - } - } - - generate := tabContent(t, content, text.TabOneTarget()) - formats := menuUnder(t, generate, text.FieldFormat()) - for _, id := range format.IDs() { - formats.SetSelected(id) - note(generate) - } - damages := menuUnder(t, generate, text.FieldDamage()) - for _, id := range damage.Names() { - damages.SetSelected(id) - note(generate) - } - - presets := tabContent(t, content, text.TabPresets()) - picker := menuUnder(t, presets, text.FieldPreset()) - for _, id := range preset.IDs() { - picker.SetSelected(id) - note(presets) - } - - recipe := tabContent(t, content, text.TabRecipe()) - batches := menuUnder(t, recipe, text.FieldFormat()) - for _, id := range format.IDs() { - batches.SetSelected(id) - note(recipe) - } - - if len(seen) < len(listed)/2 { - t.Fatalf("only %d names were read off the screens against %d listed, so this guard did not reach the screens", - len(seen), len(listed)) - } - for name := range seen { - if !listed[name] { - t.Errorf("%q is the name of a field on a screen and is not in the list the column of names is worked out from,"+ - " so its box may start to the right of every other box", name) - } - } -} - -// fieldNamesOn is the name of every field on a screen, read off the rows the -// form is made of. A switch carries its own name and stands in the column of -// controls, so its row has no name here, which is right - the column of names -// is not for it. -func fieldNamesOn(screen fyne.CanvasObject) []string { - var out []string - walk(screen, func(obj fyne.CanvasObject) { - box, ok := obj.(*fyne.Container) - if !ok || !parts.IsFieldRow(box) || len(box.Objects) < 2 { - return - } - if name, named := headingOf(box.Objects[0]); named && name != "" { - out = append(out, name) - } - }) - return out -} diff --git a/internal/guard/palette_test.go b/internal/guard/palette_test.go index 254d488..e669c2b 100644 --- a/internal/guard/palette_test.go +++ b/internal/guard/palette_test.go @@ -50,6 +50,21 @@ func TestThePaletteMeetsTheContrastItWasComputedFor(t *testing.T) { } } + // A field's name, since 2026-09-21 in an ink of its own a step under + // the value's, is still read - on the panel it stands on, which is + // lighter than the page and so the harder of the two. + panel := parts.PaletteColour(parts.ColorNamePanel, variant.v) + if got := contrast(parts.PaletteColour(parts.ColorNameLabel, variant.v), panel); got < 4.5 { + t.Errorf("%s: a field's name is %.2f:1 against the panel, under the 4.5 a reader needs", variant.name, got) + } + // And it is a step under the value, or the two inks are one ink with + // two names - the owner accepted the quieter name on 2026-09-21 and + // then asked for it brighter, so the step is small and it is asked + // for as a step rather than as a number. + if label, value := parts.PaletteColour(parts.ColorNameLabel, variant.v), parts.PaletteColour(theme.ColorNameForeground, variant.v); lightnessGap(label, value) < 3 { + t.Errorf("%s: a field's name is %.1f L* off the value under it, so nothing tells the name from the value", variant.name, lightnessGap(label, value)) + } + // Recognised as a state: 3.0, from WCAG 1.4.11. What carries it is the // LINE round a control - parts.Ring - and not the focus colour, which // is a wash the toolkit lays over whatever the control already is. diff --git a/internal/guard/samename_test.go b/internal/guard/samename_test.go index 705ea85..eb3b7b5 100644 --- a/internal/guard/samename_test.go +++ b/internal/guard/samename_test.go @@ -72,6 +72,24 @@ func TestNoSectionIsNamedAfterAFieldInsideIt(t *testing.T) { } } +// fieldNamesOn is every field name a screen draws, read off the fields +// themselves - a field is the one container laid out as a field, and its +// first thing is its name. Asked by the layout rather than by the weight of +// the words, for the reason the guard above gives. +func fieldNamesOn(screen fyne.CanvasObject) []string { + var out []string + walk(screen, func(obj fyne.CanvasObject) { + box, ok := obj.(*fyne.Container) + if !ok || !parts.IsField(box) || len(box.Objects) < 2 { + return + } + if name, named := headingOf(box.Objects[0]); named && name != "" { + out = append(out, name) + } + }) + return out +} + // And the preset card still says what it is for. // // The half that stops the guard above being satisfied by deleting the title. diff --git a/internal/guard/sectionsurface_test.go b/internal/guard/sectionsurface_test.go index 8bf0825..74de118 100644 --- a/internal/guard/sectionsurface_test.go +++ b/internal/guard/sectionsurface_test.go @@ -65,28 +65,30 @@ func TestASectionDrawsItsOwnSurface(t *testing.T) { subject.what, surface.FillColor, want) } - // No line round it, and the protection that line used to give has moved - // rather than gone. Both halves matter and they are checked together. + // A line round it, since 2026-09-21, and the fill under it - both, and + // both are checked. // - // It used to be drawn with one, because the fill on its own was 4.0 L* - // off the page - a surface you sense rather than see - and a panel with - // no boundary is where this started. What changed on 2026-08-23 is that - // the same one pixel line was also what every box to type in used to - // say "your value goes here". One mark meaning two things means - // neither, and the field is the one that needs it. - // - // So the fill has to do the work alone now, and that is asserted here - // rather than assumed: a border removed without lifting the surface - // would leave exactly the panel this file was written about. - if surface.StrokeWidth != 0 { - t.Errorf("%s draws a line round itself %.1f px wide.\n"+ - "Reason: a border is what a box to type in uses, so a container wearing one makes the mark mean nothing.\n"+ - "What to do: let the surface group by being a surface.", subject.what, surface.StrokeWidth) + // The line was taken away on 2026-08-23 on the argument that the same + // one pixel line was what a box to type in used to say "your value + // goes here", and a mark meaning two things means neither. The owner's + // report from the running window a month later was the other half of + // that trade: with the fill 5.9 L* off the page and nothing round it, + // the whole window ran together and nobody could tell where a section + // ended. The line is back on the owner's decision, in the separator's + // colour, and the field keeps its own edge in its own colour - two + // marks, two colours, and the surface still does its share. + if surface.StrokeWidth == 0 { + t.Errorf("%s draws no line round itself.\n"+ + "Reason: the fill alone was measured at 5.9 L* off the page and read as nothing, 2026-09-21.\n"+ + "What to do: stroke the surface in the separator's colour, one edge wide.", subject.what) + } + if want := parts.PaletteColour(theme.ColorNameSeparator, theme.VariantDark); surface.StrokeColor != want { + t.Errorf("%s draws its edge in %v and the palette says a separator is %v", subject.what, surface.StrokeColor, want) } page := parts.PaletteColour(theme.ColorNameBackground, theme.VariantDark) if gap := lightnessGap(surface.FillColor, page); gap < 5 { - t.Errorf("%s is %.1f L* off the page with no line round it, and 5 is the least that reads as a surface.\n"+ - "Reason: the edge used to carry this and no longer does, so the fill is all there is.", subject.what, gap) + t.Errorf("%s is %.1f L* off the page, and 5 is the least that reads as a surface even with a line round it.\n"+ + "Reason: the line says where the edge is, the fill says there is a thing inside it.", subject.what, gap) } } } diff --git a/internal/guard/spacingscale_test.go b/internal/guard/spacingscale_test.go index 7bfef65..1cdae5d 100644 --- a/internal/guard/spacingscale_test.go +++ b/internal/guard/spacingscale_test.go @@ -13,32 +13,31 @@ import ( "github.com/donislawdev/TestingFilesGenerator/internal/gui/text" ) -// A name stands level with its box, on one edge with every other box. +// A name stands over its box, on one edge with it and with every other. // -// GUI rule 13 in the owner's words: a form is a grid with a column of names, -// values in a second column, names lined up with each other. Until -// 2026-09-14 a name stood OVER its box, and this guard measured the gap -// between the two against the gap between two fields, because those were the -// two distances a stacked form has. A row has one: the space between two -// rows. What holds a field together in a row is that its name and its box -// share a line, and what lines the form up is that every box starts where -// every other box starts. +// Over since 2026-09-21, on the owner's decision from the running window +// ("that is prettier"). Beside from 2026-09-14 to that day, in a column of +// names, when this guard asked for the middle of the name to be the middle +// of the box. Over before 2026-09-14 too - so the question this asks is the +// one a stacked form has, written down this time so the third turn of the +// wheel can read it: a name belongs to the box UNDER it, which means the gap +// from a name down to its box has to be smaller than the gap from that box +// down to the next name. A form where those two are equal is a list of +// words and boxes with no pairing, and a form where the name is nearer the +// box above it pairs every name with the wrong box. // // Three things, all read off the laid out screen rather than off the // constants, for the reason the section guards give below: a layout is free // to put a name anywhere, and reading the numbers back out of the package that // declares them proves they were declared, which is not the question. // -// Level means the middle of the name is the middle of the box, to a pixel. -// "Inside the box's height" was the first version and a mutation laying every -// name at the top of its row passed it: a name 19 px tall at the top of a 32 -// px row has its middle 6 px above the box's, still inside, and a form where -// every name floats above its box reads as the stacked form it replaced. One edge means every control of the screen begins -// at one X, whatever the length of the name beside it - the column of names -// is worked out from the widest name the window can show, so "Seed" and -// "Output directory" put their boxes on the same line. Apart means two rows -// have room between them, or the form is a list with no rhythm. -func TestANameStandsLevelWithItsBoxOnOneEdgeWithEveryOther(t *testing.T) { +// Over means the name ends above the box begins. One edge means the name and +// its box start on one X, and every box on the screen starts on that X - a +// stacked form has no column of names to line up, so the left edge is the +// only line there is, and a box indented under its name reads as a child of +// it rather than as the value it holds. Apart means two fields have room +// between them, or the form is a list with no rhythm. +func TestANameStandsOverItsBoxOnOneEdgeWithEveryOther(t *testing.T) { ourTheme(t) content, _ := laidOutWindow(t) generate := tabContent(t, content, text.TabOneTarget()) @@ -47,18 +46,23 @@ func TestANameStandsLevelWithItsBoxOnOneEdgeWithEveryOther(t *testing.T) { text.FieldNameTemplate(), text.FieldOutputDir(), text.FieldSeed()} edges := map[float32][]string{} var boxes []band + var nameGaps []float32 for _, label := range names { name, box := nameAndBox(t, generate, label) - middle, boxMiddle := name.Y+name.Height/2, box.Y+box.Height/2 - if off := middle - boxMiddle; off > 1 || off < -1 { - t.Errorf("%q has its middle at y=%.1f and its box its middle at y=%.1f, so the name is not level with the box", - label, middle, boxMiddle) + if name.Y+name.Height > box.Y { + t.Errorf("%q ends at y=%.1f and its box begins at y=%.1f, so the name does not stand over the box", + label, name.Y+name.Height, box.Y) } + if off := name.X - box.X; off > 1 || off < -1 { + t.Errorf("%q starts at x=%.1f and its box at x=%.1f - a box not on its name's edge reads as indented under it", + label, name.X, box.X) + } + nameGaps = append(nameGaps, box.Y-(name.Y+name.Height)) edges[box.X] = append(edges[box.X], label) boxes = append(boxes, box) } if len(edges) != 1 { - t.Errorf("the boxes on the generate screen start on %d different edges, and a form is a grid only while they start on one: %v", + t.Errorf("the boxes on the generate screen start on %d different edges, and a form lines up only while they start on one: %v", len(edges), edges) } for i := 1; i < len(boxes); i++ { @@ -67,6 +71,17 @@ func TestANameStandsLevelWithItsBoxOnOneEdgeWithEveryOther(t *testing.T) { names[i-1], names[i], boxes[i-1].Y+boxes[i-1].Height, boxes[i].Y) } } + // The pairing: a name is nearer the box under it than that box is to the + // next name. Asked for each pair down the screen rather than once at the + // top, after the outside review of #116: measured once, a later pair + // could drift while the first still held. + for i := 0; i+1 < len(names); i++ { + between := gapBelowField(t, generate, names[i], names[i+1]) + if nameGaps[i] >= between { + t.Errorf("%q stands %.1f px over its box and %q stands %.1f px under that box, so nothing says which box the name belongs to", + names[i], nameGaps[i], names[i+1], between) + } + } } // Two sections are the same distance apart wherever they are. diff --git a/internal/guard/testdata/screens/about.png b/internal/guard/testdata/screens/about.png index 4a49704..3103140 100644 Binary files a/internal/guard/testdata/screens/about.png and b/internal/guard/testdata/screens/about.png differ diff --git a/internal/guard/testdata/screens/about.xml b/internal/guard/testdata/screens/about.xml index 2c22b3e..87fe9d6 100644 --- a/internal/guard/testdata/screens/about.xml +++ b/internal/guard/testdata/screens/about.xml @@ -56,7 +56,7 @@ - + Licence @@ -90,7 +90,7 @@ - + Support @@ -116,7 +116,7 @@ - + Third party code compiled in @@ -164,7 +164,7 @@ - + Files compiled in that are not code @@ -189,7 +189,7 @@ - + Shipped beside the program on Windows @@ -218,7 +218,7 @@ - + diff --git a/internal/guard/testdata/screens/catalogue.png b/internal/guard/testdata/screens/catalogue.png index 9380854..a5d73d2 100644 Binary files a/internal/guard/testdata/screens/catalogue.png and b/internal/guard/testdata/screens/catalogue.png differ diff --git a/internal/guard/testdata/screens/catalogue.xml b/internal/guard/testdata/screens/catalogue.xml index d254dae..b57ecff 100644 --- a/internal/guard/testdata/screens/catalogue.xml +++ b/internal/guard/testdata/screens/catalogue.xml @@ -1,7 +1,7 @@ - + - - + + @@ -25,7 +25,7 @@ - + Button @@ -114,7 +114,7 @@ - + Generate @@ -132,7 +132,7 @@ - + Generate @@ -150,7 +150,7 @@ - + Generate @@ -168,7 +168,7 @@ - + Generate @@ -294,7 +294,7 @@ - + Write a label inside each generated file, including the ones that are far too small to hold it @@ -375,7 +375,7 @@ - + Chooser @@ -539,7 +539,7 @@ - + Entry @@ -661,7 +661,7 @@ - + Toggle @@ -761,7 +761,7 @@ - + Segments @@ -911,7 +911,7 @@ - + OpenList @@ -1317,7 +1317,7 @@ - + Tabs @@ -1500,12 +1500,12 @@ - - - - + + + + Fields - + @@ -1515,10 +1515,10 @@ - - - Size - + + + Size + @@ -1537,7 +1537,7 @@ - + @@ -1547,15 +1547,15 @@ - - - - Size + + + + Size * - + @@ -1574,7 +1574,7 @@ - + @@ -1584,10 +1584,10 @@ - - - Size - + + + Size + @@ -1604,12 +1604,11 @@ - - - - - - + + + + + a size of 3 B is below the smallest png, which is 73 B @@ -1618,7 +1617,7 @@ - + @@ -1628,10 +1627,10 @@ - - - Size - + + + Size + @@ -1650,7 +1649,7 @@ - + @@ -1660,10 +1659,10 @@ - - - Label in each file - + + + Label in each file + @@ -1671,7 +1670,7 @@ - + @@ -1683,9 +1682,9 @@ - Name + Name - Size + Size * @@ -1729,7 +1728,7 @@ - + Remove @@ -1774,7 +1773,7 @@ - + Remove @@ -1784,7 +1783,7 @@ - + @@ -1821,13 +1820,13 @@ - + Choose... - + @@ -1837,25 +1836,25 @@ - - - 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 + + + + + + + - + - + @@ -1863,12 +1862,12 @@ - - - - + + + + PropertyField - + @@ -1878,19 +1877,19 @@ - - - - - - Width + + + + + + Width - + @@ -1912,11 +1911,11 @@ - + - + @@ -1926,19 +1925,19 @@ - - - - - - Compression + + + + + + Compression - + @@ -1956,11 +1955,11 @@ - + - + @@ -1970,19 +1969,19 @@ - - - - - - Bom + + + + + + Bom - + @@ -1990,11 +1989,11 @@ - + - + @@ -2004,19 +2003,19 @@ - - - - - - Member size + + + + + + Member size - + @@ -2035,10 +2034,10 @@ - - - - + + + + @@ -2047,11 +2046,11 @@ - + - + @@ -2061,19 +2060,19 @@ - - - - - - Password + + + + + + Password - + @@ -2095,19 +2094,19 @@ - + - - - - + + + + ByteCount - + @@ -2117,10 +2116,10 @@ - - - Size - + + + Size + @@ -2136,10 +2135,10 @@ - - - - + + + + 10 485 760 B @@ -2148,7 +2147,7 @@ - + @@ -2158,10 +2157,10 @@ - - - Size - + + + Size + @@ -2180,10 +2179,10 @@ - - - - + + + + @@ -2192,7 +2191,7 @@ - + @@ -2202,10 +2201,10 @@ - - - Size - + + + Size + @@ -2221,10 +2220,10 @@ - - - - + + + + 2 147 483 648 B @@ -2236,12 +2235,12 @@ - - - - + + + + Tips - + @@ -2251,18 +2250,18 @@ - - - - - Size + + + + + Size - + @@ -2283,11 +2282,11 @@ - + - + @@ -2299,16 +2298,16 @@ - - - Size + + + Size - + @@ -2331,7 +2330,10 @@ - + + + + @@ -2351,8 +2353,8 @@ - - + + ErrorArea @@ -2415,8 +2417,8 @@ - - + + Progress @@ -2468,10 +2470,10 @@ - - - - + + + + Folding @@ -2484,15 +2486,15 @@ - + - - + + @@ -2537,15 +2539,15 @@ - + - - + + @@ -2579,15 +2581,15 @@ - + - - + + @@ -2615,7 +2617,7 @@ - + @@ -2625,21 +2627,21 @@ - + - - + + - Advanced - - + Advanced + + - + @@ -2663,7 +2665,7 @@ - + @@ -2678,16 +2680,16 @@ - - + + - Advanced - - + Advanced + + - + @@ -2700,7 +2702,7 @@ - + @@ -2711,7 +2713,7 @@ - + @@ -2753,7 +2755,7 @@ - + @@ -2764,15 +2766,15 @@ - + - - + + @@ -2806,7 +2808,7 @@ - + @@ -2817,15 +2819,15 @@ - + - - + + @@ -2859,7 +2861,7 @@ - + @@ -2870,15 +2872,15 @@ - + - - + + @@ -2909,8 +2911,8 @@ - - + + Title @@ -2995,7 +2997,7 @@ - Output directory + Output directory @@ -3146,7 +3148,7 @@ - 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 @@ -3179,12 +3181,12 @@ - - - - + + + + Section - + @@ -3194,52 +3196,52 @@ - - - - + + + + File configuration - - - Size - - - - - - - + + + Size + + + + + + + - + - + - - - How many files - - - - - - - + + + How many files + + + + + + + - + - + @@ -3247,7 +3249,7 @@ - + @@ -3257,54 +3259,54 @@ - - - - + + + + Output - - - Size - - - - - - - + + + Size + + + + + + + - + - + - + - - - How many files - - - - - - - + + + How many files + + + + + + + - + - + @@ -3312,7 +3314,7 @@ - + @@ -3323,7 +3325,7 @@ - + @@ -3333,7 +3335,7 @@ - + Preview @@ -3359,7 +3361,7 @@ - + @@ -3369,52 +3371,52 @@ - - - - + + + + Write a label inside each generated file, including the ones that are far too small to hold it - - - Size - - - - - - - + + + Size + + + + + + + - + - + - - - How many files - - - - - - - + + + How many files + + + + + + + - + - + @@ -3425,8 +3427,8 @@ - - + + Not drawn, and why @@ -3543,8 +3545,8 @@ - - + + Layout only, and why diff --git a/internal/guard/testdata/screens/generate-chosen-by-key.png b/internal/guard/testdata/screens/generate-chosen-by-key.png index 16d4799..8dc7fca 100644 Binary files a/internal/guard/testdata/screens/generate-chosen-by-key.png and b/internal/guard/testdata/screens/generate-chosen-by-key.png differ diff --git a/internal/guard/testdata/screens/generate-chosen-by-key.xml b/internal/guard/testdata/screens/generate-chosen-by-key.xml index 53c090a..365930c 100644 --- a/internal/guard/testdata/screens/generate-chosen-by-key.xml +++ b/internal/guard/testdata/screens/generate-chosen-by-key.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -117,10 +117,10 @@ - - - - + + + + 10 485 760 B @@ -128,15 +128,15 @@ - - - - How many files + + + + How many files * - + @@ -154,10 +154,10 @@ - - - - Batch name + + + + Batch name * @@ -167,7 +167,7 @@ - + @@ -185,17 +185,17 @@ - - - - File names + + + + File names - + @@ -216,22 +216,22 @@ - + - - + + - Settings for png - - + Settings for png + + - + @@ -244,17 +244,17 @@ - - - - Damage + + + + Damage - + @@ -271,20 +271,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -294,33 +294,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -330,7 +330,7 @@ - + @@ -348,17 +348,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -373,7 +373,7 @@ - + @@ -383,7 +383,7 @@ - + Preview diff --git a/internal/guard/testdata/screens/generate-chosen.png b/internal/guard/testdata/screens/generate-chosen.png index 8bee73b..f748899 100644 Binary files a/internal/guard/testdata/screens/generate-chosen.png and b/internal/guard/testdata/screens/generate-chosen.png differ diff --git a/internal/guard/testdata/screens/generate-chosen.xml b/internal/guard/testdata/screens/generate-chosen.xml index 7237440..ec000f3 100644 --- a/internal/guard/testdata/screens/generate-chosen.xml +++ b/internal/guard/testdata/screens/generate-chosen.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -117,10 +117,10 @@ - - - - + + + + 10 485 760 B @@ -128,15 +128,15 @@ - - - - How many files + + + + How many files * - + @@ -154,10 +154,10 @@ - - - - Batch name + + + + Batch name * @@ -167,7 +167,7 @@ - + @@ -185,17 +185,17 @@ - - - - File names + + + + File names - + @@ -216,22 +216,22 @@ - + - - + + - Settings for png - - + Settings for png + + - + @@ -244,17 +244,17 @@ - - - - Damage + + + + Damage - + @@ -271,20 +271,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -294,33 +294,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -330,7 +330,7 @@ - + @@ -348,17 +348,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -373,7 +373,7 @@ - + @@ -383,7 +383,7 @@ - + Preview diff --git a/internal/guard/testdata/screens/generate-empty.png b/internal/guard/testdata/screens/generate-empty.png index 7064173..7150779 100644 Binary files a/internal/guard/testdata/screens/generate-empty.png and b/internal/guard/testdata/screens/generate-empty.png differ diff --git a/internal/guard/testdata/screens/generate-empty.xml b/internal/guard/testdata/screens/generate-empty.xml index 83317d5..a60ccb4 100644 --- a/internal/guard/testdata/screens/generate-empty.xml +++ b/internal/guard/testdata/screens/generate-empty.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -117,10 +117,10 @@ - - - - + + + + 10 485 760 B @@ -128,15 +128,15 @@ - - - - How many files + + + + How many files * - + @@ -154,12 +154,11 @@ - - - - - - + + + + + target "files" asks for 0 files. Ask for at least one @@ -167,10 +166,10 @@ - - - - Batch name + + + + Batch name * @@ -180,7 +179,7 @@ - + @@ -198,17 +197,17 @@ - - - - File names + + + + File names - + @@ -229,22 +228,22 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -257,17 +256,17 @@ - - - - Damage + + + + Damage - + @@ -284,20 +283,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -307,33 +306,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -343,7 +342,7 @@ - + @@ -361,17 +360,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -386,7 +385,7 @@ - + @@ -396,7 +395,7 @@ - + Preview diff --git a/internal/guard/testdata/screens/generate-focused.png b/internal/guard/testdata/screens/generate-focused.png index 0cca0cb..6cd29f6 100644 Binary files a/internal/guard/testdata/screens/generate-focused.png and b/internal/guard/testdata/screens/generate-focused.png differ diff --git a/internal/guard/testdata/screens/generate-focused.xml b/internal/guard/testdata/screens/generate-focused.xml index 383d277..c0e610a 100644 --- a/internal/guard/testdata/screens/generate-focused.xml +++ b/internal/guard/testdata/screens/generate-focused.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -118,10 +118,10 @@ - - - - + + + + 10 485 760 B @@ -129,15 +129,15 @@ - - - - How many files + + + + How many files * - + @@ -155,10 +155,10 @@ - - - - Batch name + + + + Batch name * @@ -168,7 +168,7 @@ - + @@ -186,17 +186,17 @@ - - - - File names + + + + File names - + @@ -217,22 +217,22 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -245,17 +245,17 @@ - - - - Damage + + + + Damage - + @@ -272,20 +272,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -295,33 +295,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -331,7 +331,7 @@ - + @@ -349,17 +349,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -374,7 +374,7 @@ - + @@ -384,7 +384,7 @@ - + Preview diff --git a/internal/guard/testdata/screens/generate-hovered.png b/internal/guard/testdata/screens/generate-hovered.png index 7ed66e3..7307353 100644 Binary files a/internal/guard/testdata/screens/generate-hovered.png and b/internal/guard/testdata/screens/generate-hovered.png differ diff --git a/internal/guard/testdata/screens/generate-hovered.xml b/internal/guard/testdata/screens/generate-hovered.xml index d56ecaf..fc36fb3 100644 --- a/internal/guard/testdata/screens/generate-hovered.xml +++ b/internal/guard/testdata/screens/generate-hovered.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -117,10 +117,10 @@ - - - - + + + + 10 485 760 B @@ -128,15 +128,15 @@ - - - - How many files + + + + How many files * - + @@ -154,10 +154,10 @@ - - - - Batch name + + + + Batch name * @@ -167,7 +167,7 @@ - + @@ -185,17 +185,17 @@ - - - - File names + + + + File names - + @@ -216,22 +216,22 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -244,17 +244,17 @@ - - - - Damage + + + + Damage - + @@ -271,20 +271,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -294,33 +294,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -330,7 +330,7 @@ - + @@ -348,17 +348,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -373,7 +373,7 @@ - + @@ -383,7 +383,7 @@ - + Preview @@ -425,8 +425,11 @@ - - + + + + + diff --git a/internal/guard/testdata/screens/generate-menu-hovered.png b/internal/guard/testdata/screens/generate-menu-hovered.png index 4398f6e..eca08b8 100644 Binary files a/internal/guard/testdata/screens/generate-menu-hovered.png and b/internal/guard/testdata/screens/generate-menu-hovered.png differ diff --git a/internal/guard/testdata/screens/generate-menu-hovered.xml b/internal/guard/testdata/screens/generate-menu-hovered.xml index c8397f7..84deb1f 100644 --- a/internal/guard/testdata/screens/generate-menu-hovered.xml +++ b/internal/guard/testdata/screens/generate-menu-hovered.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -117,10 +117,10 @@ - - - - + + + + 10 485 760 B @@ -128,15 +128,15 @@ - - - - How many files + + + + How many files * - + @@ -154,10 +154,10 @@ - - - - Batch name + + + + Batch name * @@ -167,7 +167,7 @@ - + @@ -185,17 +185,17 @@ - - - - File names + + + + File names - + @@ -216,22 +216,22 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -244,17 +244,17 @@ - - - - Damage + + + + Damage - + @@ -271,20 +271,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -294,33 +294,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -330,7 +330,7 @@ - + @@ -348,17 +348,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -373,7 +373,7 @@ - + @@ -383,7 +383,7 @@ - + Preview @@ -431,7 +431,7 @@ - + diff --git a/internal/guard/testdata/screens/generate-menu-keyed.png b/internal/guard/testdata/screens/generate-menu-keyed.png index bb9e1ec..ca291ba 100644 Binary files a/internal/guard/testdata/screens/generate-menu-keyed.png and b/internal/guard/testdata/screens/generate-menu-keyed.png differ diff --git a/internal/guard/testdata/screens/generate-menu-keyed.xml b/internal/guard/testdata/screens/generate-menu-keyed.xml index 86419fb..bceb88f 100644 --- a/internal/guard/testdata/screens/generate-menu-keyed.xml +++ b/internal/guard/testdata/screens/generate-menu-keyed.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -117,10 +117,10 @@ - - - - + + + + 10 485 760 B @@ -128,15 +128,15 @@ - - - - How many files + + + + How many files * - + @@ -154,10 +154,10 @@ - - - - Batch name + + + + Batch name * @@ -167,7 +167,7 @@ - + @@ -185,17 +185,17 @@ - - - - File names + + + + File names - + @@ -216,22 +216,22 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -244,17 +244,17 @@ - - - - Damage + + + + Damage - + @@ -271,20 +271,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -294,33 +294,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -330,7 +330,7 @@ - + @@ -348,17 +348,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -373,7 +373,7 @@ - + @@ -383,7 +383,7 @@ - + Preview @@ -431,7 +431,7 @@ - + diff --git a/internal/guard/testdata/screens/generate-menu.png b/internal/guard/testdata/screens/generate-menu.png index f1f62b3..77ce6bf 100644 Binary files a/internal/guard/testdata/screens/generate-menu.png and b/internal/guard/testdata/screens/generate-menu.png differ diff --git a/internal/guard/testdata/screens/generate-menu.xml b/internal/guard/testdata/screens/generate-menu.xml index 3c95915..652e197 100644 --- a/internal/guard/testdata/screens/generate-menu.xml +++ b/internal/guard/testdata/screens/generate-menu.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -117,10 +117,10 @@ - - - - + + + + 10 485 760 B @@ -128,15 +128,15 @@ - - - - How many files + + + + How many files * - + @@ -154,10 +154,10 @@ - - - - Batch name + + + + Batch name * @@ -167,7 +167,7 @@ - + @@ -185,17 +185,17 @@ - - - - File names + + + + File names - + @@ -216,22 +216,22 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -244,17 +244,17 @@ - - - - Damage + + + + Damage - + @@ -271,20 +271,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -294,33 +294,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -330,7 +330,7 @@ - + @@ -348,17 +348,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -373,7 +373,7 @@ - + @@ -383,7 +383,7 @@ - + Preview @@ -431,7 +431,7 @@ - + diff --git a/internal/guard/testdata/screens/generate-refused-both.png b/internal/guard/testdata/screens/generate-refused-both.png index 476f4be..39a12bd 100644 Binary files a/internal/guard/testdata/screens/generate-refused-both.png and b/internal/guard/testdata/screens/generate-refused-both.png differ diff --git a/internal/guard/testdata/screens/generate-refused-both.xml b/internal/guard/testdata/screens/generate-refused-both.xml index 187b69c..61be050 100644 --- a/internal/guard/testdata/screens/generate-refused-both.xml +++ b/internal/guard/testdata/screens/generate-refused-both.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -118,22 +118,21 @@ - - - - + + + + - - - - - - + + + + + Size "abc" has no number: write something like 10mb or 1048576 @@ -141,15 +140,15 @@ - - - - How many files + + + + How many files * - + @@ -166,24 +165,22 @@ - - - - - - - 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 - - - - Batch name + + + + Batch name * @@ -193,7 +190,7 @@ - + @@ -211,17 +208,17 @@ - - - - File names + + + + File names - + @@ -242,22 +239,22 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -270,17 +267,17 @@ - - - - Damage + + + + Damage - + @@ -297,20 +294,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -320,33 +317,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -356,7 +353,7 @@ - + @@ -374,17 +371,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -399,7 +396,7 @@ - + @@ -409,7 +406,7 @@ - + Preview diff --git a/internal/guard/testdata/screens/generate-refused-setting.png b/internal/guard/testdata/screens/generate-refused-setting.png index 9b2af8c..de04df7 100644 Binary files a/internal/guard/testdata/screens/generate-refused-setting.png and b/internal/guard/testdata/screens/generate-refused-setting.png differ diff --git a/internal/guard/testdata/screens/generate-refused-setting.xml b/internal/guard/testdata/screens/generate-refused-setting.xml index 641540e..3e16629 100644 --- a/internal/guard/testdata/screens/generate-refused-setting.xml +++ b/internal/guard/testdata/screens/generate-refused-setting.xml @@ -32,8 +32,8 @@ - - + + @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -117,10 +117,10 @@ - - - - + + + + 10 485 760 B @@ -128,15 +128,15 @@ - - - - How many files + + + + How many files * - + @@ -154,10 +154,10 @@ - - - - Batch name + + + + Batch name * @@ -167,7 +167,7 @@ - + @@ -185,17 +185,17 @@ - - - - File names + + + + File names - + @@ -216,22 +216,22 @@ - - + + - - + + - Settings for png - - + Settings for png + + - + @@ -242,18 +242,18 @@ - - - - - Width + + + + + Width - + @@ -271,12 +271,11 @@ - - - - - - + + + + + png: Width cannot be "99999" - it takes a whole number of pixels from 1 to 20000 @@ -284,17 +283,17 @@ - - - - Height + + + + Height - + @@ -315,7 +314,7 @@ - + @@ -327,17 +326,17 @@ - - - - Damage + + + + Damage - + @@ -354,20 +353,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -377,33 +376,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -413,7 +412,7 @@ - + @@ -431,17 +430,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -454,9 +453,17 @@ + + + + + + + + - + @@ -466,7 +473,7 @@ - + Preview diff --git a/internal/guard/testdata/screens/generate-refused.png b/internal/guard/testdata/screens/generate-refused.png index e496e4f..f4ed6a7 100644 Binary files a/internal/guard/testdata/screens/generate-refused.png and b/internal/guard/testdata/screens/generate-refused.png differ diff --git a/internal/guard/testdata/screens/generate-refused.xml b/internal/guard/testdata/screens/generate-refused.xml index f4ef311..97381cf 100644 --- a/internal/guard/testdata/screens/generate-refused.xml +++ b/internal/guard/testdata/screens/generate-refused.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -118,40 +118,39 @@ - - - - + + + + 1 B - - - - - - - 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 - - - - How many files + + + + How many files * - + @@ -169,10 +168,10 @@ - - - - Batch name + + + + Batch name * @@ -182,7 +181,7 @@ - + @@ -200,17 +199,17 @@ - - - - File names + + + + File names - + @@ -231,22 +230,22 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -259,17 +258,17 @@ - - - - Damage + + + + Damage - + @@ -286,20 +285,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -309,33 +308,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -345,7 +344,7 @@ - + @@ -363,17 +362,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -388,7 +387,7 @@ - + @@ -398,7 +397,7 @@ - + Preview diff --git a/internal/guard/testdata/screens/generate-switch-by-key.png b/internal/guard/testdata/screens/generate-switch-by-key.png index 277c21c..5c67f52 100644 Binary files a/internal/guard/testdata/screens/generate-switch-by-key.png and b/internal/guard/testdata/screens/generate-switch-by-key.png differ diff --git a/internal/guard/testdata/screens/generate-switch-by-key.xml b/internal/guard/testdata/screens/generate-switch-by-key.xml index 33818c1..a81dbd4 100644 --- a/internal/guard/testdata/screens/generate-switch-by-key.xml +++ b/internal/guard/testdata/screens/generate-switch-by-key.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -117,10 +117,10 @@ - - - - + + + + 10 485 760 B @@ -128,15 +128,15 @@ - - - - How many files + + + + How many files * - + @@ -154,10 +154,10 @@ - - - - Batch name + + + + Batch name * @@ -167,7 +167,7 @@ - + @@ -185,17 +185,17 @@ - - - - File names + + + + File names - + @@ -216,22 +216,22 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -244,17 +244,17 @@ - - - - Damage + + + + Damage - + @@ -271,20 +271,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -294,33 +294,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -330,7 +330,7 @@ - + @@ -348,17 +348,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -373,7 +373,7 @@ - + @@ -383,7 +383,7 @@ - + Preview diff --git a/internal/guard/testdata/screens/generate-typed.png b/internal/guard/testdata/screens/generate-typed.png index 9ccc44f..af4dd9f 100644 Binary files a/internal/guard/testdata/screens/generate-typed.png and b/internal/guard/testdata/screens/generate-typed.png differ diff --git a/internal/guard/testdata/screens/generate-typed.xml b/internal/guard/testdata/screens/generate-typed.xml index 0c43239..2f11d34 100644 --- a/internal/guard/testdata/screens/generate-typed.xml +++ b/internal/guard/testdata/screens/generate-typed.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -117,22 +117,21 @@ - - - - + + + + - - - - - - + + + + + Size "abc" has no number: write something like 10mb or 1048576 @@ -140,15 +139,15 @@ - - - - How many files + + + + How many files * - + @@ -166,10 +165,10 @@ - - - - Batch name + + + + Batch name * @@ -179,7 +178,7 @@ - + @@ -197,17 +196,17 @@ - - - - File names + + + + File names - + @@ -228,22 +227,22 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -256,17 +255,17 @@ - - - - Damage + + + + Damage - + @@ -283,20 +282,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -306,33 +305,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -342,7 +341,7 @@ - + @@ -360,17 +359,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -385,7 +384,7 @@ - + @@ -395,7 +394,7 @@ - + Preview diff --git a/internal/guard/testdata/screens/generate-unchecked.png b/internal/guard/testdata/screens/generate-unchecked.png index 29c277e..ef8e986 100644 Binary files a/internal/guard/testdata/screens/generate-unchecked.png and b/internal/guard/testdata/screens/generate-unchecked.png differ diff --git a/internal/guard/testdata/screens/generate-unchecked.xml b/internal/guard/testdata/screens/generate-unchecked.xml index ac44356..aad8e19 100644 --- a/internal/guard/testdata/screens/generate-unchecked.xml +++ b/internal/guard/testdata/screens/generate-unchecked.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -117,10 +117,10 @@ - - - - + + + + 10 485 760 B @@ -128,15 +128,15 @@ - - - - How many files + + + + How many files * - + @@ -154,10 +154,10 @@ - - - - Batch name + + + + Batch name * @@ -167,7 +167,7 @@ - + @@ -185,17 +185,17 @@ - - - - File names + + + + File names - + @@ -216,22 +216,22 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -244,17 +244,17 @@ - - - - Damage + + + + Damage - + @@ -271,20 +271,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -294,33 +294,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -330,7 +330,7 @@ - + @@ -348,17 +348,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -372,7 +372,7 @@ - + @@ -382,7 +382,7 @@ - + Preview diff --git a/internal/guard/testdata/screens/generate.png b/internal/guard/testdata/screens/generate.png index 37507c1..44029b4 100644 Binary files a/internal/guard/testdata/screens/generate.png and b/internal/guard/testdata/screens/generate.png differ diff --git a/internal/guard/testdata/screens/generate.xml b/internal/guard/testdata/screens/generate.xml index 5e126b5..46d1924 100644 --- a/internal/guard/testdata/screens/generate.xml +++ b/internal/guard/testdata/screens/generate.xml @@ -56,22 +56,22 @@ - - - - + + + + File configuration - - - - Format + + + + Format - + @@ -88,10 +88,10 @@ - - - - Size + + + + Size * @@ -101,7 +101,7 @@ - + @@ -117,10 +117,10 @@ - - - - + + + + 10 485 760 B @@ -128,15 +128,15 @@ - - - - How many files + + + + How many files * - + @@ -154,10 +154,10 @@ - - - - Batch name + + + + Batch name * @@ -167,7 +167,7 @@ - + @@ -185,17 +185,17 @@ - - - - File names + + + + File names - + @@ -216,22 +216,22 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -244,17 +244,17 @@ - - - - Damage + + + + Damage - + @@ -271,20 +271,20 @@ - + - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -294,33 +294,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -330,7 +330,7 @@ - + @@ -348,17 +348,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -373,7 +373,7 @@ - + @@ -383,7 +383,7 @@ - + Preview diff --git a/internal/guard/testdata/screens/preset-menu-setting.png b/internal/guard/testdata/screens/preset-menu-setting.png index d5ce549..4a571f3 100644 Binary files a/internal/guard/testdata/screens/preset-menu-setting.png and b/internal/guard/testdata/screens/preset-menu-setting.png differ diff --git a/internal/guard/testdata/screens/preset-menu-setting.xml b/internal/guard/testdata/screens/preset-menu-setting.xml index 5da9d42..40a0cb1 100644 --- a/internal/guard/testdata/screens/preset-menu-setting.xml +++ b/internal/guard/testdata/screens/preset-menu-setting.xml @@ -56,22 +56,22 @@ - - - - + + + + The question - - - - Preset + + + + Preset - + @@ -88,7 +88,7 @@ - + @@ -149,23 +149,23 @@ - - - - + + + + Settings - - - - - Limit + + + + + Limit - + @@ -184,10 +184,10 @@ - - - - + + + + @@ -195,17 +195,17 @@ - - - - Spread + + + + Spread - + @@ -226,17 +226,17 @@ - - - - Format + + + + Format - + @@ -257,15 +257,15 @@ - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -275,33 +275,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -311,7 +311,7 @@ - + @@ -336,7 +336,7 @@ - + @@ -346,7 +346,7 @@ - + Preview @@ -394,15 +394,15 @@ - - - - - - - - - + + + + + + + + + @@ -552,27 +552,6 @@ webp - - - - - xlsx - - - - - - - xml - - - - - - - zip - - @@ -636,22 +615,13 @@ - - - - - - - - - - + - - - + + + diff --git a/internal/guard/testdata/screens/preset-menu.png b/internal/guard/testdata/screens/preset-menu.png index 091c1fe..6e345f1 100644 Binary files a/internal/guard/testdata/screens/preset-menu.png and b/internal/guard/testdata/screens/preset-menu.png differ diff --git a/internal/guard/testdata/screens/preset-menu.xml b/internal/guard/testdata/screens/preset-menu.xml index 08a3ddc..5816ab0 100644 --- a/internal/guard/testdata/screens/preset-menu.xml +++ b/internal/guard/testdata/screens/preset-menu.xml @@ -56,22 +56,22 @@ - - - - + + + + The question - - - - Preset + + + + Preset - + @@ -88,7 +88,7 @@ - + @@ -149,23 +149,23 @@ - - - - + + + + Settings - - - - - Limit + + + + + Limit - + @@ -184,10 +184,10 @@ - - - - + + + + @@ -195,17 +195,17 @@ - - - - Spread + + + + Spread - + @@ -226,17 +226,17 @@ - - - - Format + + + + Format - + @@ -257,15 +257,15 @@ - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -275,33 +275,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -311,7 +311,7 @@ - + @@ -336,7 +336,7 @@ - + @@ -346,7 +346,7 @@ - + Preview @@ -394,7 +394,7 @@ - + diff --git a/internal/guard/testdata/screens/preset-refused.png b/internal/guard/testdata/screens/preset-refused.png index 901a986..489d002 100644 Binary files a/internal/guard/testdata/screens/preset-refused.png and b/internal/guard/testdata/screens/preset-refused.png differ diff --git a/internal/guard/testdata/screens/preset-refused.xml b/internal/guard/testdata/screens/preset-refused.xml index c9a49f5..84d8893 100644 --- a/internal/guard/testdata/screens/preset-refused.xml +++ b/internal/guard/testdata/screens/preset-refused.xml @@ -56,22 +56,22 @@ - - - - + + + + The question - - - - Preset + + + + Preset - + @@ -88,7 +88,7 @@ - + @@ -149,23 +149,23 @@ - - - - + + + + Settings - - - - - Limit + + + + + Limit - + @@ -182,42 +182,41 @@ - - - - + + + + 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. + + + + + + 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. - - - - Spread + + + + Spread - + @@ -238,17 +237,17 @@ - - - - Format + + + + Format - + @@ -269,15 +268,15 @@ - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -287,33 +286,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -323,7 +322,7 @@ - + @@ -348,7 +347,7 @@ - + @@ -358,7 +357,7 @@ - + Preview diff --git a/internal/guard/testdata/screens/preset.png b/internal/guard/testdata/screens/preset.png index c9c1f32..5a60d65 100644 Binary files a/internal/guard/testdata/screens/preset.png and b/internal/guard/testdata/screens/preset.png differ diff --git a/internal/guard/testdata/screens/preset.xml b/internal/guard/testdata/screens/preset.xml index 5a994a8..787a171 100644 --- a/internal/guard/testdata/screens/preset.xml +++ b/internal/guard/testdata/screens/preset.xml @@ -56,22 +56,22 @@ - - - - + + + + The question - - - - Preset + + + + Preset - + @@ -88,7 +88,7 @@ - + @@ -149,23 +149,23 @@ - - - - + + + + Settings - - - - - Limit + + + + + Limit - + @@ -184,10 +184,10 @@ - - - - + + + + @@ -195,17 +195,17 @@ - - - - Spread + + + + Spread - + @@ -226,17 +226,17 @@ - - - - Format + + + + Format - + @@ -257,15 +257,15 @@ - - - - + + + + Output - - - - Output directory + + + + Output directory * @@ -275,33 +275,33 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Seed + + + + Seed * @@ -311,7 +311,7 @@ - + @@ -336,7 +336,7 @@ - + @@ -346,7 +346,7 @@ - + Preview diff --git a/internal/guard/testdata/screens/recipe-contents.png b/internal/guard/testdata/screens/recipe-contents.png index f3d64d2..dde0123 100644 Binary files a/internal/guard/testdata/screens/recipe-contents.png and b/internal/guard/testdata/screens/recipe-contents.png differ diff --git a/internal/guard/testdata/screens/recipe-contents.xml b/internal/guard/testdata/screens/recipe-contents.xml index c1aa9d0..1cf271c 100644 --- a/internal/guard/testdata/screens/recipe-contents.xml +++ b/internal/guard/testdata/screens/recipe-contents.xml @@ -32,8 +32,8 @@ - - + + @@ -56,18 +56,18 @@ - - - - - - + + + + + + - - + + @@ -85,24 +85,24 @@ - + Duplicate - - - - - Format + + + + + Format - + @@ -119,10 +119,10 @@ - - - - Batch name + + + + Batch name * @@ -132,7 +132,7 @@ - + @@ -153,10 +153,10 @@ - - - How many files - + + + How many files + @@ -177,25 +177,22 @@ - - - - - - - - - - One size - A range - Around a limit - - - - - - - Size + + + + + + + + One size + A range + Around a limit + + + + + + Size * @@ -205,7 +202,7 @@ - + @@ -224,10 +221,10 @@ - - - - + + + + @@ -236,17 +233,17 @@ - - - - File names + + + + File names - + @@ -267,21 +264,21 @@ - + - - + + - Settings for zip - - + Settings for zip + + - + @@ -293,21 +290,21 @@ - + - - + + - Notes for the manifest - - + Notes for the manifest + + - + @@ -319,7 +316,7 @@ - + @@ -330,9 +327,9 @@ - Format - How many files - Size + Format + How many files + Size @@ -395,7 +392,7 @@ - + Remove @@ -405,7 +402,7 @@ - + Add files inside @@ -415,16 +412,16 @@ - - - - - + + + + + Output - - - - Output directory + + + + Output directory * @@ -434,40 +431,40 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Manifest file name + + + + Manifest file name - + @@ -488,17 +485,17 @@ - - - - Seed + + + + Seed - + @@ -519,17 +516,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -542,9 +539,17 @@ + + + + + + + + - + @@ -554,7 +559,7 @@ - + Preview @@ -593,7 +598,7 @@ - + Add a batch diff --git a/internal/guard/testdata/screens/recipe-refused-with-one-batch-filled.png b/internal/guard/testdata/screens/recipe-refused-with-one-batch-filled.png index 6ea8c37..a0dc7af 100644 Binary files a/internal/guard/testdata/screens/recipe-refused-with-one-batch-filled.png and b/internal/guard/testdata/screens/recipe-refused-with-one-batch-filled.png differ 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 d2043cd..90b4e8e 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 @@ -32,8 +32,8 @@ - - + + @@ -56,18 +56,18 @@ - - - - - - + + + + + + - - + + @@ -85,29 +85,29 @@ - + Duplicate - + Remove - - - - - Format + + + + + Format - + @@ -124,10 +124,10 @@ - - - - Batch name + + + + Batch name * @@ -137,7 +137,7 @@ - + @@ -158,14 +158,13 @@ - - - - - - - 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. + + + + + + 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. @@ -173,10 +172,10 @@ - - - How many files - + + + How many files + @@ -197,25 +196,22 @@ - - - - - - - - - - One size - A range - Around a limit - - - - - - - Size + + + + + + + + One size + A range + Around a limit + + + + + + Size * @@ -225,7 +221,7 @@ - + @@ -244,24 +240,23 @@ - - - - + + + + - - - - - - - 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. + + + + + + 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. @@ -270,17 +265,17 @@ - - - - File names + + + + File names - + @@ -301,21 +296,21 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -327,21 +322,21 @@ - + - - + + - Notes for the manifest - - + Notes for the manifest + + - + @@ -357,16 +352,16 @@ - - - - + + + + - - + + @@ -384,29 +379,29 @@ - + Duplicate - + Remove - - - - - Format + + + + + Format - + @@ -423,10 +418,10 @@ - - - - Batch name + + + + Batch name * @@ -436,7 +431,7 @@ - + @@ -454,10 +449,10 @@ - - - How many files - + + + How many files + @@ -478,25 +473,22 @@ - - - - - - - - - - One size - A range - Around a limit - - - - - - - Size + + + + + + + + One size + A range + Around a limit + + + + + + Size * @@ -506,7 +498,7 @@ - + @@ -522,10 +514,10 @@ - - - - + + + + 1 024 B @@ -534,17 +526,17 @@ - - - - File names + + + + File names - + @@ -565,21 +557,21 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -591,21 +583,21 @@ - + - - + + - Notes for the manifest - - + Notes for the manifest + + - + @@ -623,16 +615,16 @@ - - - - - + + + + + Output - - - - Output directory + + + + Output directory * @@ -642,40 +634,40 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Manifest file name + + + + Manifest file name - + @@ -696,17 +688,17 @@ - - - - Seed + + + + Seed - + @@ -727,17 +719,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -754,13 +746,13 @@ - - + + - + @@ -770,7 +762,7 @@ - + Preview @@ -809,7 +801,7 @@ - + Add a batch diff --git a/internal/guard/testdata/screens/recipe-refused.png b/internal/guard/testdata/screens/recipe-refused.png index c6eec40..a3c1b56 100644 Binary files a/internal/guard/testdata/screens/recipe-refused.png and b/internal/guard/testdata/screens/recipe-refused.png differ diff --git a/internal/guard/testdata/screens/recipe-refused.xml b/internal/guard/testdata/screens/recipe-refused.xml index 48ce42d..bcb8fc9 100644 --- a/internal/guard/testdata/screens/recipe-refused.xml +++ b/internal/guard/testdata/screens/recipe-refused.xml @@ -32,8 +32,8 @@ - - + + @@ -56,18 +56,18 @@ - - - - - - + + + + + + - - + + @@ -85,24 +85,24 @@ - + Duplicate - - - - - Format + + + + + Format - + @@ -119,10 +119,10 @@ - - - - Batch name + + + + Batch name * @@ -132,7 +132,7 @@ - + @@ -153,14 +153,13 @@ - - - - - - - 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. + + + + + + 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. @@ -168,10 +167,10 @@ - - - How many files - + + + How many files + @@ -192,25 +191,22 @@ - - - - - - - - - - One size - A range - Around a limit - - - - - - - Size + + + + + + + + One size + A range + Around a limit + + + + + + Size * @@ -220,7 +216,7 @@ - + @@ -239,24 +235,23 @@ - - - - + + + + - - - - - - - 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. + + + + + + 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. @@ -265,17 +260,17 @@ - - - - File names + + + + File names - + @@ -296,21 +291,21 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -322,21 +317,21 @@ - + - - + + - Notes for the manifest - - + Notes for the manifest + + - + @@ -354,16 +349,16 @@ - - - - - + + + + + Output - - - - Output directory + + + + Output directory * @@ -373,40 +368,40 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Manifest file name + + + + Manifest file name - + @@ -427,17 +422,17 @@ - - - - Seed + + + + Seed - + @@ -458,17 +453,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -481,9 +476,17 @@ + + + + + + + + - + @@ -493,7 +496,7 @@ - + Preview @@ -532,7 +535,7 @@ - + Add a batch diff --git a/internal/guard/testdata/screens/recipe-two-batches.png b/internal/guard/testdata/screens/recipe-two-batches.png index fcd2d6f..28b6f55 100644 Binary files a/internal/guard/testdata/screens/recipe-two-batches.png and b/internal/guard/testdata/screens/recipe-two-batches.png differ diff --git a/internal/guard/testdata/screens/recipe-two-batches.xml b/internal/guard/testdata/screens/recipe-two-batches.xml index a359830..0aaf64c 100644 --- a/internal/guard/testdata/screens/recipe-two-batches.xml +++ b/internal/guard/testdata/screens/recipe-two-batches.xml @@ -32,8 +32,8 @@ - - + + @@ -56,18 +56,18 @@ - - - - - - + + + + + + - - + + @@ -85,29 +85,29 @@ - + Duplicate - + Remove - - - - - Format + + + + + Format - + @@ -124,10 +124,10 @@ - - - - Batch name + + + + Batch name * @@ -137,7 +137,7 @@ - + @@ -158,10 +158,10 @@ - - - How many files - + + + How many files + @@ -182,25 +182,22 @@ - - - - - - - - - - One size - A range - Around a limit - - - - - - - Size + + + + + + + + One size + A range + Around a limit + + + + + + Size * @@ -210,7 +207,7 @@ - + @@ -229,10 +226,10 @@ - - - - + + + + @@ -241,17 +238,17 @@ - - - - File names + + + + File names - + @@ -272,21 +269,21 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -298,21 +295,21 @@ - + - - + + - Notes for the manifest - - + Notes for the manifest + + - + @@ -328,16 +325,16 @@ - - - - + + + + - - + + @@ -355,29 +352,29 @@ - + Duplicate - + Remove - - - - - Format + + + + + Format - + @@ -394,10 +391,10 @@ - - - - Batch name + + + + Batch name * @@ -407,7 +404,7 @@ - + @@ -428,10 +425,10 @@ - - - How many files - + + + How many files + @@ -452,25 +449,22 @@ - - - - - - - - - - One size - A range - Around a limit - - - - - - - Size + + + + + + + + One size + A range + Around a limit + + + + + + Size * @@ -480,7 +474,7 @@ - + @@ -499,10 +493,10 @@ - - - - + + + + @@ -511,17 +505,17 @@ - - - - File names + + + + File names - + @@ -542,21 +536,21 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -568,21 +562,21 @@ - + - - + + - Notes for the manifest - - + Notes for the manifest + + - + @@ -600,16 +594,16 @@ - - - - - + + + + + Output - - - - Output directory + + + + Output directory * @@ -619,40 +613,40 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Manifest file name + + + + Manifest file name - + @@ -673,17 +667,17 @@ - - - - Seed + + + + Seed - + @@ -704,17 +698,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -731,13 +725,13 @@ - - + + - + @@ -747,7 +741,7 @@ - + Preview @@ -786,7 +780,7 @@ - + Add a batch diff --git a/internal/guard/testdata/screens/recipe.png b/internal/guard/testdata/screens/recipe.png index 34608dd..5dcf93c 100644 Binary files a/internal/guard/testdata/screens/recipe.png and b/internal/guard/testdata/screens/recipe.png differ diff --git a/internal/guard/testdata/screens/recipe.xml b/internal/guard/testdata/screens/recipe.xml index 0098f46..55c666c 100644 --- a/internal/guard/testdata/screens/recipe.xml +++ b/internal/guard/testdata/screens/recipe.xml @@ -56,18 +56,18 @@ - - - - - - + + + + + + - - + + @@ -85,24 +85,24 @@ - + Duplicate - - - - - Format + + + + + Format - + @@ -119,10 +119,10 @@ - - - - Batch name + + + + Batch name * @@ -132,7 +132,7 @@ - + @@ -153,10 +153,10 @@ - - - How many files - + + + How many files + @@ -177,25 +177,22 @@ - - - - - - - - - - One size - A range - Around a limit - - - - - - - Size + + + + + + + + One size + A range + Around a limit + + + + + + Size * @@ -205,7 +202,7 @@ - + @@ -224,10 +221,10 @@ - - - - + + + + @@ -236,17 +233,17 @@ - - - - File names + + + + File names - + @@ -267,21 +264,21 @@ - + - - + + - Settings for avif - - + Settings for avif + + - + @@ -293,21 +290,21 @@ - + - - + + - Notes for the manifest - - + Notes for the manifest + + - + @@ -325,16 +322,16 @@ - - - - - + + + + + Output - - - - Output directory + + + + Output directory * @@ -344,40 +341,40 @@ - - - - - - - - + + + + + + + + /tfg/out - + - + Choose... - + - - - - Manifest file name + + + + Manifest file name - + @@ -398,17 +395,17 @@ - - - - Seed + + + + Seed - + @@ -429,17 +426,17 @@ - - - - Label in each file + + + + Label in each file - + @@ -454,7 +451,7 @@ - + @@ -464,7 +461,7 @@ - + Preview @@ -503,7 +500,7 @@ - + Add a batch diff --git a/internal/guard/typeshape_test.go b/internal/guard/typeshape_test.go index 65db5e3..39b896a 100644 --- a/internal/guard/typeshape_test.go +++ b/internal/guard/typeshape_test.go @@ -41,7 +41,7 @@ const ( // ceilings. The busy state and its four controls left it that day for a // type of their own (runbusy.go), and the ratchet moved down to the next // widest: parts.Fields by methods, window.batch by fields. - mostMethods = 27 + mostMethods = 26 mostFields = 21 // What counts as crowding, in the shape this package already uses diff --git a/internal/gui/catalogue/fields.go b/internal/gui/catalogue/fields.go index a13ba77..7116398 100644 --- a/internal/gui/catalogue/fields.go +++ b/internal/gui/catalogue/fields.go @@ -10,24 +10,18 @@ import ( "github.com/donislawdev/TestingFilesGenerator/internal/gui/parts" ) -// form is a set of fields with the column of names a screen would give them: -// measured from the names the catalogue shows, the way a screen measures it -// from every name it can show, so a row here stands where a row stands there. -func form() *parts.Fields { - s := parts.NewFields() - s.LabelColumn(parts.WidestName("Size", "Name", "How many files", "Label in each file", "Compression", "Member size", "Password")) - return s -} +// form is a set of fields the way a screen builds them. +func form() *parts.Fields { return parts.NewFields() } -// A row of the form: the name in the column of names, the control beside it, -// and whatever the row has to say about its value. +// A field of the form: the name over the control, and under the control +// whatever the field has to say about its value. func fields() Entry { sizeRow := func(s *parts.Fields) fyne.CanvasObject { e := parts.NewEntry() e.SetText("10mb") return s.Add("size", "Size", "10mb", parts.NoDetail, parts.Numeric(e)) } - return Entry{Name: "Fields", Covers: []string{"FieldSaying", "CellSaying", "FieldRow", "RequiredMark", "Table"}, States: []State{ + return Entry{Name: "Fields", Covers: []string{"FieldSaying", "CellSaying", "FieldStack", "RequiredMark", "Table"}, States: []State{ {"a row", func() fyne.CanvasObject { return sizeRow(form()) }}, {"a row that has to be filled in", func() fyne.CanvasObject { s := form() diff --git a/internal/gui/parts/button.go b/internal/gui/parts/button.go index 02eb019..eec296a 100644 --- a/internal/gui/parts/button.go +++ b/internal/gui/parts/button.go @@ -418,7 +418,10 @@ func buttonFace(look Look, state buttonState) face { // way the palette lightens every dark face (ColorNameHover and // ColorNamePressed), worked out here as one opaque colour each. f := face{ink: theme.ColorNameForeground, edge: PaletteColour(theme.ColorNameInputBorder, dark), edgeWidth: edgeWidth} - f.fill = PaletteColour(theme.ColorNameInputBackground, dark) + // The button's own surface since 2026-09-21, a step brighter than a + // box to type in - the owner's report from the running window was + // that a button in the field's colour read as a field. + f.fill = PaletteColour(theme.ColorNameButton, dark) if wash := pointerFill(state); wash != color.Transparent { f.fill = blended(f.fill, wash) } diff --git a/internal/gui/parts/detail.go b/internal/gui/parts/detail.go index 51bbff9..96d6ea9 100644 --- a/internal/gui/parts/detail.go +++ b/internal/gui/parts/detail.go @@ -218,7 +218,7 @@ func (t *Tips) open(near fyne.CanvasObject, detail string) fyne.CanvasObject { // On the surface an open list floats on, not on a panel's - see // floatingSurface for the report that moved it there. - box := container.NewStack(floatingSurface(), Padded(Inset, Prose(detail))) + box := container.NewStack(tipShadow(), tipSurface(), Padded(Inset, Prose(detail))) // Sized twice, and this is the same finding the render probe records rather // than superstition. A wrapping label reports the height it needs for the diff --git a/internal/gui/parts/field.go b/internal/gui/parts/field.go index 2e914f5..6b3979c 100644 --- a/internal/gui/parts/field.go +++ b/internal/gui/parts/field.go @@ -51,15 +51,15 @@ import ( // as the sentence is there. Two marks rather than one on purpose - a colour on // its own says nothing to somebody who cannot tell it from the others, and a // sentence on its own leaves them looking for which of eight boxes it means. -func FieldSaying(names float32, label string, detail Detail, required bool, trailing, control fyne.CanvasObject) Built { +func FieldSaying(label string, detail Detail, required bool, trailing, control fyne.CanvasObject) Built { marked, ring := WithRing(shapedForItsValues(control)) - area := newErrorArea(names) + area := NewErrorArea() area.edge = ring - cells := []fyne.CanvasObject{headingRow(label, detail, required), marked} + pieces := []fyne.CanvasObject{headingRow(label, detail, required), marked} if trailing != nil { - cells = append(cells, trailing) + pieces = append(pieces, trailing) } - body := FieldRow(names, cells...) + body := FieldStack(pieces...) return Built{Object: Column(GapTight, body, area.Object()), Body: body, Area: area} } @@ -91,7 +91,7 @@ type Built struct { // names the box by it - it is just not drawn here. func CellSaying(control fyne.CanvasObject) Built { marked, ring := WithRing(shapedForItsValues(control)) - area := newErrorArea(0) + area := NewErrorArea() area.edge = ring return Built{Object: Column(GapTight, marked, area.Object()), Body: marked, Area: area} } @@ -153,23 +153,14 @@ type ErrorArea struct { // NewErrorArea builds one that stands on its own, for the line at the foot of // the form that speaks for the whole run. -func NewErrorArea() *ErrorArea { return newErrorArea(0) } - -// newErrorArea builds one for a field whose names stand in a column that -// wide, so the sentence starts under the control it is about rather than -// under the name. Nought for a cell of a table, where the sentence starts -// under the cell. -func newErrorArea(names float32) *ErrorArea { +func NewErrorArea() *ErrorArea { label := widget.NewLabel("") label.Wrapping = fyne.TextWrapWord label.Importance = widget.DangerImportance - var box fyne.CanvasObject - if names > 0 { - box = FieldRow(names, Clear(), inkTight(label)) - } else { - box = container.NewVBox(inkTight(label)) - } - area := &ErrorArea{label: label, box: box} + // The sentence starts under the control it is about, on the edge the + // control starts on - which is the field's edge since the name stands + // over the control rather than beside it. + area := &ErrorArea{label: label, box: container.NewVBox(inkTight(label))} area.Clear() return area } diff --git a/internal/gui/parts/fieldrow.go b/internal/gui/parts/fieldrow.go deleted file mode 100644 index 6086f68..0000000 --- a/internal/gui/parts/fieldrow.go +++ /dev/null @@ -1,126 +0,0 @@ -package parts - -import ( - "fyne.io/fyne/v2" - "fyne.io/fyne/v2/canvas" - "fyne.io/fyne/v2/container" - "image/color" -) - -// A field is one row: its name in a column of names, its control in a column -// of controls, so every name lines up with every other name and every value -// starts on one edge. GUI rule 13 of CLAUDE.md, in the owner's words: a form -// is a grid with a column of labels, not a centred stack of controls. -// -// Until 2026-09-14 a field was the name ABOVE the control, which cost two -// rows a field and put the name of a box 32 px above the box because the -// button beside the name was 32 px tall. In the row the name and the control -// share a line, so the height of a field is the height of its control. - -// fieldRow lays a field out as cells: the first is the name and gets the -// column of names, the last gets whatever width is left, and anything between -// stands at its own width. GapColumns separates them. -// -// The last cell takes the rest rather than every cell sharing it out, so a -// box holding a path fills the row and a box holding a number, which sizes -// itself, does not - the row does not decide how wide a control is, the -// control does (see Numeric and Sized). -// -// Every cell keeps its own height and is centred on the row's, so a name -// stands level with the middle of its box rather than with the top of it, and -// the line drawn round a refused box goes round the box and not round the -// row - the stack holding a control and its mark is as tall as the control. -type fieldRow struct{ names float32 } - -// FieldRow puts objects into one row of the form: the name cell first, the -// control next, anything else after. For the screens that need a row the -// field builders do not make - a switch that belongs to three boxes, a -// button that belongs to no field. -func FieldRow(names float32, cells ...fyne.CanvasObject) fyne.CanvasObject { - return container.New(fieldRow{names: names}, cells...) -} - -func (f fieldRow) MinSize(objects []fyne.CanvasObject) fyne.Size { - size := fyne.NewSize(0, 0) - shown := 0 - for i, o := range objects { - if !o.Visible() { - continue - } - min := o.MinSize() - if i == 0 { - size.Width += fyne.Max(min.Width, f.names) - } else { - size.Width += min.Width - } - size.Height = fyne.Max(size.Height, min.Height) - shown++ - } - if shown > 1 { - size.Width += GapColumns * float32(shown-1) - } - return size -} - -func (f fieldRow) Layout(objects []fyne.CanvasObject, size fyne.Size) { - last := -1 - for i, o := range objects { - if o.Visible() { - last = i - } - } - x := float32(0) - for i, o := range objects { - if !o.Visible() { - continue - } - width := o.MinSize().Width - switch { - case i == 0: - width = fyne.Max(width, f.names) - case i == last: - width = fyne.Max(width, size.Width-x) - } - height := fyne.Min(o.MinSize().Height, size.Height) - o.Resize(fyne.NewSize(width, height)) - o.Move(fyne.NewPos(x, (size.Height-height)/2)) - x += width + GapColumns - } -} - -// Clear is a shape that takes room and draws nothing. -// -// For the name cell of a row whose control carries its own name - a switch -// says what it is on the part somebody clicks - so the control still stands -// in the column of controls. Transparent rather than the colour of the panel, -// because a rectangle in the colour of the thing under it is right at the call -// site and wrong on the first screen that puts the row on something else. -func Clear() fyne.CanvasObject { - return canvas.NewRectangle(color.Transparent) -} - -// WidestName is how wide a column of names has to be to hold every name given, -// with the star and the button that can stand beside one. -// -// Measured from the same objects a heading is drawn with, so the answer and -// the drawing cannot come apart - a width worked out from a copy of the -// arithmetic would be a second copy of the drawing (the sibling project paid -// four pixels for exactly that on 2026-09-09). -func WidestName(names ...string) float32 { - widest := float32(0) - for _, name := range names { - if w := Heading(name).MinSize().Width; w > widest { - widest = w - } - } - return widest + GapInline + newRequiredMark().MinSize().Width + GapLabel + GlyphButton -} - -// IsFieldRow says whether a container is one row of the form, for a guard -// reading the names off a screen. Asked by the layout rather than by shape, -// because a section is also a container whose first thing is words and whose -// second is not. -func IsFieldRow(c *fyne.Container) bool { - _, is := c.Layout.(fieldRow) - return is -} diff --git a/internal/gui/parts/fields.go b/internal/gui/parts/fields.go index 964274b..e86f337 100644 --- a/internal/gui/parts/fields.go +++ b/internal/gui/parts/fields.go @@ -105,12 +105,6 @@ type Fields struct { // nobody would find by looking. shortcuts func(fyne.Shortcut) - // names is how wide the column of names is, so every field on the screen - // puts its control on the same edge. Set once by the screen from the - // widest name the window can ever show - see LabelColumn - and nought - // until then, which lays a name out at its own width. - names float32 - // bare are the controls on the form that have no setting and no name of // their own and are still part of the form - the switch between the three // ways of stating a size. Each remembers how many fields stood before it, @@ -130,19 +124,6 @@ type bareControl struct { after int } -// LabelColumn says how wide the column of names is on this screen. -// -// Every field built after this stands its control on that edge. Handed in -// rather than measured from the fields as they arrive, because the settings a -// chosen format declares arrive after the screen is built, and a column that -// widened to fit them would move every control on the screen the moment -// somebody chose a format with a long setting name. -func (s *Fields) LabelColumn(width float32) { s.names = width } - -// Names is the width of the column of names, for a screen laying out a row -// of its own beside the fields. -func (s *Fields) Names() float32 { return s.names } - // PassShortcutsTo says where the boxes of this screen should send a shortcut // they have no use for. Called once, before the fields are built. func (s *Fields) PassShortcutsTo(deliver func(fyne.Shortcut)) { @@ -252,7 +233,7 @@ func (s *Fields) Add(setting, label, hint string, detail Detail, control fyne.Ca // field that still carries one is not something anybody can write. explained := alsoSaying(hint, detail) return s.register(setting, label, explained, control, - FieldSaying(s.names, label, explained, s.required[setting], s.counter(setting, control), control)) + FieldSaying(label, explained, s.required[setting], s.counter(setting, control), control)) } // register is what every kind of field goes through once it is built. @@ -276,7 +257,7 @@ func (s *Fields) Unlabelled(control fyne.CanvasObject) fyne.CanvasObject { if d, ok := control.(fyne.Disableable); ok { s.bare = append(s.bare, bareControl{control: d, after: len(s.list)}) } - return FieldRow(s.names, Clear(), control) + return control } // AddToggle is a switch, and since 2026-09-15 it is a field like any other: its diff --git a/internal/gui/parts/fieldstack.go b/internal/gui/parts/fieldstack.go new file mode 100644 index 0000000..02abc87 --- /dev/null +++ b/internal/gui/parts/fieldstack.go @@ -0,0 +1,51 @@ +package parts + +import ( + "image/color" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" +) + +// A field is its name over its control: the name on the left edge, the control +// under it starting on the same edge, and under the control whatever the field +// has to say about its value - the count of bytes a size comes to. +// +// Over rather than beside since 2026-09-21, on the owner's decision from the +// running window ("that is prettier"). It was beside from 2026-09-14, in a +// column of names as wide as the widest name the window could show, and over +// before that - so this is the second time round, and what is different this +// time is written down: the column and everything that measured it (the +// widest name, the list of every name a screen can draw, the guard holding +// the list complete) went with the layout, because a width nothing draws is +// a number waiting to be wrong. +// +// A layout of its own rather than a plain column, so that a guard reading the +// names off a screen can tell a field from any other stack of words and boxes +// - IsField, the way IsFieldRow was asked before. + +// fieldStack is the layout behind a field: a column at the name's distance. +type fieldStack struct{ column } + +// FieldStack stacks a field's pieces: the name, the control, then whatever the +// field says under its control. +func FieldStack(pieces ...fyne.CanvasObject) fyne.CanvasObject { + return container.New(fieldStack{column{gap: GapLabel}}, pieces...) +} + +// IsField says whether a container is one field of the form, for a guard +// reading the names off a screen. Asked by the layout rather than by shape, +// because a section is also a container whose first thing is words. +func IsField(c *fyne.Container) bool { + _, is := c.Layout.(fieldStack) + return is +} + +// Clear is an empty cell: what a table draws over a column whose control has +// no name. Transparent rather than the colour of the panel, because a +// rectangle in the colour of the thing under it is right at the call site and +// wrong on the first screen that puts the row on something else. +func Clear() fyne.CanvasObject { + return canvas.NewRectangle(color.Transparent) +} diff --git a/internal/gui/parts/foldhead.go b/internal/gui/parts/foldhead.go index cdda4a0..2afae4f 100644 --- a/internal/gui/parts/foldhead.go +++ b/internal/gui/parts/foldhead.go @@ -34,6 +34,13 @@ import ( type FoldHead struct { widget.BaseWidget + // under is the words this head stands under - the title, the arrow and + // the line - so the fill and the ring are drawn to their width rather + // than across the whole row. Owner's report from the running window, + // 2026-09-21: a hover the width of the form is enormous. The row stays + // the target and only the drawing narrows. + under fyne.CanvasObject + fold *Folding arrow *widget.Icon @@ -175,6 +182,9 @@ type foldHeadRenderer struct { } func (r *foldHeadRenderer) Layout(size fyne.Size) { + if r.head.under != nil { + size.Width = fyne.Min(size.Width, r.head.under.MinSize().Width) + } r.back.Resize(size) r.ring.Resize(size) } diff --git a/internal/gui/parts/folding.go b/internal/gui/parts/folding.go index da1ca1a..0605889 100644 --- a/internal/gui/parts/folding.go +++ b/internal/gui/parts/folding.go @@ -61,7 +61,7 @@ type Folding struct { // that could not be removed or copied would be a batch somebody has to open to // do the two things they are most likely to want from a list of them. func NewFolding(title string, head []fyne.CanvasObject, content ...fyne.CanvasObject) *Folding { - f := newFolding(title, head, content...) + f := newFolding(title, sectionTitle(title), head, content...) f.object = container.NewStack(panelSurface(), Padded(Inset, f.inside)) return f } @@ -79,12 +79,14 @@ func NewFolding(title string, head []fyne.CanvasObject, content ...fyne.CanvasOb // and Duplicate, which act on the batch - a section of it is not a thing // anybody removes or copies on its own. func NewInnerFolding(title string, content ...fyne.CanvasObject) *Folding { - f := newFolding(title, nil, content...) + // At the rank of a subheading rather than a section's title since + // 2026-09-21: drawn as a section, it read as one (owner, running window). + f := newFolding(title, words(title, TextBody, true, theme.ColorNameForeground), nil, content...) f.object = f.inside return f } -func newFolding(title string, head []fyne.CanvasObject, content ...fyne.CanvasObject) *Folding { +func newFolding(title string, titled fyne.CanvasObject, head []fyne.CanvasObject, content ...fyne.CanvasObject) *Folding { f := &Folding{open: true, title: title} f.line = widget.NewLabel("") @@ -113,7 +115,8 @@ func newFolding(title string, head []fyne.CanvasObject, content ...fyne.CanvasOb // the same amount so the title's ink does not move - see overhang. arrow := widget.NewIcon(theme.MenuDropDownIcon()) f.head = newFoldHead(f, arrow) - words := Padded(TabInset, container.NewHBox(sectionTitle(title), arrow, quiet(f.line))) + words := Padded(TabInset, container.NewHBox(titled, arrow, quiet(f.line))) + f.head.under = words row := container.NewBorder(nil, nil, nil, container.NewHBox(head...), container.NewStack(f.head, words)) f.inside = Column(GapField, container.New(overhang{by: TabInset}, row), f.body) diff --git a/internal/gui/parts/parts.go b/internal/gui/parts/parts.go index 7b74663..981ab4a 100644 --- a/internal/gui/parts/parts.go +++ b/internal/gui/parts/parts.go @@ -53,7 +53,7 @@ func Prose(text string) fyne.CanvasObject { // - and a name is read by where it stands: in the column of names, level with // its box. func Heading(text string) fyne.CanvasObject { - return words(text, TextBody, false, theme.ColorNameForeground) + return words(text, TextBody, false, ColorNameLabel) } // Subheading names a block inside a section - the list of what a preset finds, @@ -248,6 +248,10 @@ func sectionTitle(text string) fyne.CanvasObject { func panelSurface() *canvas.Rectangle { rect := canvas.NewRectangle(PaletteColour(ColorNamePanel, theme.VariantDark)) rect.CornerRadius = RadiusPanel + // A line round the edge again, owner's decision of 2026-09-21 after the + // running window: the fill alone did not say where a section ends. + rect.StrokeColor = PaletteColour(theme.ColorNameSeparator, theme.VariantDark) + rect.StrokeWidth = edgeWidth return rect } @@ -269,6 +273,39 @@ func floatingSurface() *canvas.Rectangle { return rect } +// tipSurface is what an explanation stands on: the floating surface with a +// line round it, so it reads as a thing laid over the form and not as a +// patch of it. Owner's report from the running window, 2026-09-21: without +// the line it looked like a random rectangle. +func tipSurface() *canvas.Rectangle { + rect := floatingSurface() + rect.StrokeColor = PaletteColour(theme.ColorNameInputBorder, theme.VariantDark) + rect.StrokeWidth = edgeWidth + return rect +} + +// tipShadow is the shade an explanation casts, offset downwards so it reads +// as depth rather than as a smudge - the same reason Refactoring UI gives +// for offsetting shadows. Drawn under tipSurface in a stack, so it shows +// only past the surface's lower edge. +func tipShadow() fyne.CanvasObject { + rect := canvas.NewRectangle(PaletteColour(ColorNameTipShade, theme.VariantDark)) + rect.CornerRadius = RadiusField + return container.New(shifted{dy: TipShadowDrop}, rect) +} + +// shifted lays its one child at an offset from its own origin. +type shifted struct{ dx, dy float32 } + +func (shifted) MinSize([]fyne.CanvasObject) fyne.Size { return fyne.Size{} } + +func (s shifted) Layout(objects []fyne.CanvasObject, size fyne.Size) { + for _, o := range objects { + o.Move(fyne.NewPos(s.dx, s.dy)) + o.Resize(size) + } +} + // Bullets is a list of short statements, drawn as a list. // // It replaces a run of labels each starting with a dash typed into the string. diff --git a/internal/gui/parts/theme.go b/internal/gui/parts/theme.go index 8e0da16..01cc035 100644 --- a/internal/gui/parts/theme.go +++ b/internal/gui/parts/theme.go @@ -30,6 +30,18 @@ import ( // colours at call sites. const ColorNamePanel fyne.ThemeColorName = "panel" +// ColorNameLabel is the ink of a field's name, a step quieter than the value +// in the box under it, so the value is the brightest thing in the field. +// Owner's decision of 2026-09-21 - see docs/GUI-STRUCTURE-2026-09-21.md. +const ColorNameLabel fyne.ThemeColorName = "label" + +// ColorNameTipShade is the shade an explanation casts on the form under it. +// A name of its own rather than the toolkit's Shadow, which this palette +// answers with nothing on purpose (see ColorNameShadow): the toolkit lays its +// shadow under every popup and the format list is where it read as a hard +// band, while an explanation is the one floating thing that wanted one. +const ColorNameTipShade fyne.ThemeColorName = "tipshade" + // ColorNameLift is what the pointer does to a face that is itself light - the // filled primary button - and ColorNameShade is what a press does to it. // @@ -133,7 +145,8 @@ var ( // A button is no longer the same colour as a box to type in. It was, // exactly, and that is half of why a menu and a field were one object // with an arrow on the end of it - see the note on Chooser. - theme.ColorNameButton: hex(0x2E, 0x2E, 0x30), + theme.ColorNameButton: hex(0x4A, 0x4A, 0x52), + ColorNameLabel: hex(0xCF, 0xD3, 0xD8), // A menu floats over everything, so it is the LIGHTEST surface rather // than another one at the height of an input box. @@ -187,6 +200,7 @@ var ( // than as a popup - see parts.Tips - so it never asked the theme for a // shadow and does not lose one. theme.ColorNameShadow: color.Transparent, + ColorNameTipShade: overlay(0x00, 0x00, 0x00, 0x66), // The surface a section is drawn on, and the line round its edge. // @@ -282,11 +296,13 @@ var ( theme.ColorNameInputBackground: hex(0xE7, 0xE7, 0xEA), theme.ColorNameInputBorder: hex(0xA8, 0xA8, 0xB0), theme.ColorNameButton: hex(0xEF, 0xEF, 0xEF), + ColorNameLabel: hex(0x44, 0x44, 0x48), // The same reasoning the other way up: on a white page a floating // surface is the lightest thing there is, so it is white and the shadow // is what separates it. theme.ColorNameMenuBackground: hex(0xFF, 0xFF, 0xFF), theme.ColorNameShadow: overlay(0x00, 0x00, 0x00, 0x40), + ColorNameTipShade: overlay(0x00, 0x00, 0x00, 0x40), // The same two, worked out the same way against a white page. The gap // between page and input is narrower here - 5.6 L* against 7.7 - so the diff --git a/internal/gui/parts/tokens.go b/internal/gui/parts/tokens.go index 19279f9..9831498 100644 --- a/internal/gui/parts/tokens.go +++ b/internal/gui/parts/tokens.go @@ -149,6 +149,8 @@ const ( // under the strip across the top. One pixel, and drawn as a filled // rectangle rather than a stroke, so it is one pixel and not a blend. Hairline = 1 + // TipShadowDrop is how far below an explanation its shade shows. + TipShadowDrop = 3 ) // Widths and heights that are not distances. diff --git a/internal/gui/window/labels.go b/internal/gui/window/labels.go deleted file mode 100644 index 3b0ba05..0000000 --- a/internal/gui/window/labels.go +++ /dev/null @@ -1,80 +0,0 @@ -package window - -import ( - "github.com/donislawdev/TestingFilesGenerator/internal/damage" - "github.com/donislawdev/TestingFilesGenerator/internal/format" - "github.com/donislawdev/TestingFilesGenerator/internal/gui/parts" - "github.com/donislawdev/TestingFilesGenerator/internal/gui/text" - "github.com/donislawdev/TestingFilesGenerator/internal/preset" -) - -// The column of names is as wide as the widest name the window can ever -// show, and it is worked out rather than written down - GUI rule 14 of -// CLAUDE.md: a layout is computed, never measured, because a number picked to -// fit today's words stops fitting at the first translation. -// -// Every name is asked, not only the ones a screen draws at rest: the settings -// a chosen format declares, a chosen damage's parameters and a preset's -// arrive after the screen is built, and a column that widened for them would -// move every control on the screen the moment somebody chose a format with a -// long setting name. So the width is one number for the whole window, from -// every source a name can come from. -// -// What is asked is the same wording the screens draw, through the same -// functions, so a name renamed in the catalogue is measured under its new -// spelling without anything here changing. TestEveryNameOnAScreenFitsTheColumnOfNames -// is what says the list below is complete: it reads the names off the built -// screens and asks whether each fits. - -// labelColumn is the width of the column of names, worked out for each -// screen as it is built. Worked out again rather than kept, on purpose: a -// value kept across screens would need a lock or a once, and concurrency in -// this package is a decision the guards ask about by name. Measuring eighty -// short names costs less than drawing one of them. -func labelColumn() float32 { - return parts.WidestName(everyName()...) -} - -// EveryFieldName is every field name the window can show, from every source -// - for the guard that reads the names off the built screens and asks -// whether each is in this list. -func EveryFieldName() []string { return everyName() } - -// everyName is every field name the window can show, from every source. -func everyName() []string { - names := []string{ - text.FieldFormat(), text.FieldSize(), text.FieldCount(), text.FieldTargetID(), - text.FieldNameTemplate(), text.FieldOutputDir(), text.FieldSeed(), - text.FieldPreset(), text.FieldDamage(), text.FieldSizeRange(), - text.FieldBoundary(), text.FieldGroup(), text.FieldExpected(), - text.FieldReason(), text.FieldManifest(), - // The label switch stands under its name in the column since 2026-09-15, - // so its name is a name on a screen the column has to be wide enough - // for - it was not, while the switch carried its own words. - text.FieldLabel(), - } - for _, id := range format.IDs() { - d, err := format.Get(id) - if err != nil { - continue - } - for _, p := range d.Properties { - names = append(names, text.SettingLabel(p.Name)) - } - } - for _, id := range damage.Names() { - d, err := damage.Get(id) - if err != nil { - continue - } - for _, p := range d.Parameters { - names = append(names, text.SettingLabel(p.Name)) - } - } - for _, p := range preset.All() { - for _, param := range p.Parameters { - names = append(names, text.SettingLabel(param.Name)) - } - } - return names -} diff --git a/internal/gui/window/run.go b/internal/gui/window/run.go index 26e86d4..1cfc792 100644 --- a/internal/gui/window/run.go +++ b/internal/gui/window/run.go @@ -325,7 +325,6 @@ func (r *runner) refreshLine() { func newRunner(wait later) *runner { r := &runner{fields: parts.NewFields(), line: &runLine{}} - r.fields.LabelColumn(labelColumn()) // Wired once, here, so that a field added later is covered without anybody // remembering to wire it. See Fields.WhenTypedIn and recheck. r.fields.WhenTypedIn(r.recheck)