diff --git a/Directory.Build.props b/Directory.Build.props
index 3a08133..1ab2674 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -5,7 +5,7 @@
scripts/build-installer.ps1 both read it from here, so releasing is a reviewed change
to this line rather than an edit in a pipeline variable group.
-->
- 1.1.2
+ 1.1.4
latest
enable
enable
diff --git a/TODO.md b/TODO.md
index 6dc7195..2a54152 100644
--- a/TODO.md
+++ b/TODO.md
@@ -16,7 +16,7 @@ The delivery chain works end to end: a merge to `main` builds, signs, and publis
pre-release to GitHub Releases, and one approval promotes that same build to a release.
reads its download links from the release manifest
deployed beside it and needs no edit per release. The current product version is `VersionPrefix` in `Directory.Build.props`
-(1.1.2). Identity version for the Store package is `VersionPrefix.0` (`1.1.2.0`).
+(1.1.4). Identity version for the Store package is `VersionPrefix.0` (`1.1.4.0`).
Declaring that number is decision 20 in [docs/decisions.md](docs/decisions.md). What 1.0
was waiting on shipped during 0.9.x: Preferences, `.wimport`, Explorer and VS Code
diff --git a/src/SQLBI.Whiteboard/PreferencesWindow.xaml.cs b/src/SQLBI.Whiteboard/PreferencesWindow.xaml.cs
index 079d2f7..10b823a 100644
--- a/src/SQLBI.Whiteboard/PreferencesWindow.xaml.cs
+++ b/src/SQLBI.Whiteboard/PreferencesWindow.xaml.cs
@@ -229,12 +229,7 @@ private FrameworkElement CreateSampleChoice(
SettingDescriptor setting,
Func sampleFor)
{
- var host = new UniformGrid
- {
- Rows = 1,
- Columns = setting.Choices.Count,
- };
-
+ var host = new ReflowingSegments();
var segments = new List();
foreach (var choice in setting.Choices)
{
@@ -243,17 +238,33 @@ private FrameworkElement CreateSampleChoice(
continue;
}
- var content = new StackPanel { HorizontalAlignment = HorizontalAlignment.Center };
+ var content = new StackPanel { HorizontalAlignment = HorizontalAlignment.Stretch };
+
+ // The sample is drawn at a fixed size and then allowed to shrink
+ // with the column. Left to its own width it overflowed a narrowed
+ // dialog and was clipped, edges first, which is worse than small.
sample.HorizontalAlignment = HorizontalAlignment.Center;
- content.Children.Add(sample);
+ content.Children.Add(new Viewbox
+ {
+ Child = sample,
+ Stretch = Stretch.Uniform,
+ StretchDirection = StretchDirection.DownOnly,
+ MaxWidth = sample.Width > 0 ? sample.Width : double.PositiveInfinity,
+ HorizontalAlignment = HorizontalAlignment.Center,
+ });
+
+ // Wrapping runs out at the longest word, and a clipped word reads as
+ // a different one. Past that point the picture carries the meaning,
+ // and the tooltip still spells it out.
content.Children.Add(new TextBlock
{
Style = (Style)FindResource("SettingsValueLabel"),
Text = choice.Title,
Margin = new Thickness(0, 8, 0, 0),
TextWrapping = TextWrapping.Wrap,
+ TextTrimming = TextTrimming.CharacterEllipsis,
TextAlignment = TextAlignment.Center,
- HorizontalAlignment = HorizontalAlignment.Center,
+ HorizontalAlignment = HorizontalAlignment.Stretch,
});
var segment = new ToggleButton
@@ -263,6 +274,7 @@ private FrameworkElement CreateSampleChoice(
IsChecked = choice.Id == CurrentEnumId(setting),
Tag = choice.Id,
ToolTip = choice.Title,
+ HorizontalContentAlignment = HorizontalAlignment.Stretch,
};
segment.Click += (_, _) =>
{
@@ -280,6 +292,91 @@ private FrameworkElement CreateSampleChoice(
return host;
}
+ ///
+ /// A row of drawn choices that takes a second row rather than squeezing its
+ /// labels. Below a segment cannot hold the
+ /// longest word in a label - "Bottom" is 44px at the 12px label size, and
+ /// the padding and border take the rest - and a word too long for its line
+ /// overflows and is clipped rather than wrapped or trimmed, so it reads as a
+ /// different word.
+ ///
+ private sealed class ReflowingSegments : Panel
+ {
+ private const double MinimumSegmentWidth = 82;
+
+ // The width a row is measured against and the width it is finally given
+ // are not the same here: measurement arrives far narrower than the
+ // arrangement, so a count settled during measure put five choices on
+ // three columns in a row with room for all five. Arrange has the real
+ // width, so that is what the count is taken from, and the children are
+ // measured again if it disagrees with what measure assumed.
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ var count = InternalChildren.Count;
+ if (count == 0)
+ {
+ return default;
+ }
+
+ var columns = ColumnsFor(availableSize.Width, count);
+ var cell = MeasureCells(columns, availableSize.Width, count);
+ return new Size(
+ double.IsInfinity(availableSize.Width)
+ ? cell.Width * columns
+ : availableSize.Width,
+ cell.Height * RowsFor(count, columns));
+ }
+
+ protected override Size ArrangeOverride(Size finalSize)
+ {
+ var count = InternalChildren.Count;
+ if (count == 0)
+ {
+ return finalSize;
+ }
+
+ var columns = ColumnsFor(finalSize.Width, count);
+ MeasureCells(columns, finalSize.Width, count);
+
+ var cellWidth = finalSize.Width / columns;
+ var cellHeight = finalSize.Height / RowsFor(count, columns);
+ for (var index = 0; index < count; index++)
+ {
+ InternalChildren[index].Arrange(new Rect(
+ index % columns * cellWidth,
+ index / columns * cellHeight,
+ cellWidth,
+ cellHeight));
+ }
+
+ return finalSize;
+ }
+
+ private static int ColumnsFor(double width, int count) => Math.Clamp(
+ double.IsInfinity(width) ? count : (int)(width / MinimumSegmentWidth),
+ 1,
+ count);
+
+ private static int RowsFor(int count, int columns) =>
+ ((count - 1) / columns) + 1;
+
+ private Size MeasureCells(int columns, double width, int count)
+ {
+ var cellWidth = double.IsInfinity(width)
+ ? MinimumSegmentWidth
+ : width / columns;
+ var tallest = 0d;
+ for (var index = 0; index < count; index++)
+ {
+ var child = InternalChildren[index];
+ child.Measure(new Size(cellWidth, double.PositiveInfinity));
+ tallest = Math.Max(tallest, child.DesiredSize.Height);
+ }
+
+ return new Size(cellWidth, tallest);
+ }
+ }
+
private static readonly Brush SampleInkBrush = Frozen(0xFF374151);
private static readonly Brush SampleGhostBrush = Frozen(0x59374151);
private static readonly Brush SampleBoardBrush = Frozen(0xFFFFFFFF);
diff --git a/src/SQLBI.Whiteboard/Themes/Settings.xaml b/src/SQLBI.Whiteboard/Themes/Settings.xaml
index f6921f0..7adf003 100644
--- a/src/SQLBI.Whiteboard/Themes/Settings.xaml
+++ b/src/SQLBI.Whiteboard/Themes/Settings.xaml
@@ -300,9 +300,9 @@