Skip to content
8 changes: 7 additions & 1 deletion Src/Common/FwAvalonia/Detail/DataTree.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2026 SIL International
// Copyright (c) 2026 SIL International
// This software is licensed under the LGPL, version 2.1 or later
// (http://www.gnu.org/licenses/lgpl-2.1.html)

Expand Down Expand Up @@ -968,6 +968,7 @@ private FieldContent AddField(int row, DetailField field, ShownRow shown)
AutomationProperties.SetName(labelBlock, field.Label ?? field.Field ?? string.Empty);
ToolTip.SetTip(labelBlock, field.Label ?? field.Field); // the label text is its own tip
var editor = CreateEditor(field, automationId);
ApplyValueFontSize(editor);
if (editor is IDisposable disposable)
shown.Editor = disposable;
editor.Margin = new Thickness(0, 0, 0, FwAvaloniaDensity.FieldSpacing);
Expand Down Expand Up @@ -1149,6 +1150,11 @@ private void WireLabelContextMenu(Control cell, DetailField field,
}, Avalonia.Interactivity.RoutingStrategies.Bubble);
}

// Shows the editor's data at the model's value size, the Normal style's, in place of the
// surface font (LT-22811).
private void ApplyValueFontSize(Control editor)
=> FwSurfaceStyles.ApplyValueFontSize(editor, Model.ValueFontSize);

// The field->control dispatch is shared with the browse in-cell editor through
// SliceFactory. The detail pane passes its full callback set (per-WS keyboard, slice
// menu, link, clipboard) and routes reference-vector gesture completion to its validation-gated
Expand Down
11 changes: 10 additions & 1 deletion Src/Common/FwAvalonia/Detail/DetailModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2114,18 +2114,27 @@ public DetailModel(
string className,
string layoutName,
IReadOnlyList<DetailField> fields,
IReadOnlyList<ViewDiagnostic> diagnostics)
IReadOnlyList<ViewDiagnostic> diagnostics,
double valueFontSize = 0)
{
ClassName = className;
LayoutName = layoutName;
Fields = fields ?? new List<DetailField>();
Diagnostics = diagnostics ?? new List<ViewDiagnostic>();
ValueFontSize = valueFontSize;
}

public string ClassName { get; }
public string LayoutName { get; }
public IReadOnlyList<DetailField> Fields { get; }
public IReadOnlyList<ViewDiagnostic> Diagnostics { get; }

/// <summary>
/// The font size of the field values, in device-independent units: the project's Normal
/// style size. A value that carries its own <see cref="DetailWsValue.FontSize"/> shows at
/// that instead. 0 leaves the values at the theme's size.
/// </summary>
public double ValueFontSize { get; }
}

/// <summary>
Expand Down
11 changes: 9 additions & 2 deletions Src/Common/FwAvalonia/Detail/DetailModelProjector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ namespace SIL.FieldWorks.Common.FwAvalonia.Detail
/// </summary>
public static class DetailModelProjector
{
/// <summary>
/// Projects <paramref name="definition"/> into a detail model whose rows read their
/// values from <paramref name="values"/>. <paramref name="valueFontSize"/> becomes the
/// model's <see cref="DetailModel.ValueFontSize"/> (0 leaves the theme's size).
/// </summary>
public static DetailModel FromViewDefinition(
ViewDefinitionModel definition,
IDetailValueProvider values)
IDetailValueProvider values,
double valueFontSize = 0)
{
if (definition == null)
throw new System.ArgumentNullException(nameof(definition));
Expand All @@ -34,7 +40,8 @@ public static DetailModel FromViewDefinition(
definition.ClassName,
definition.LayoutName,
fields,
definition.Diagnostics);
definition.Diagnostics,
valueFontSize);
}

private static void CollectFields(
Expand Down
1 change: 1 addition & 0 deletions Src/Common/FwAvalonia/Detail/DetailRichTextChrome.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ internal static TextBlock CreatePerRunFontDisplay(DetailRichTextValue rich,
Background = FwAvaloniaDensity.TransparentBrush,
FlowDirection = rightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight
};
FwSurfaceStyles.MarkValueText(display);
AutomationProperties.SetAutomationId(display, automationId);

foreach (var run in rich.Runs)
Expand Down
12 changes: 12 additions & 0 deletions Src/Common/FwAvalonia/Detail/FwFieldControls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,7 @@ private static TextBox CreateValueBox(DetailField field, DetailWsValue value, bo
Background = FwAvaloniaDensity.TransparentBrush,
TextWrapping = TextWrapping.Wrap // long values wrap; the row grows vertically
};
FwSurfaceStyles.MarkValueText(box);
// A voice/audio writing system has no sound player in this view yet, so the row
// is read-only and says why (a distinct message from the rich-content read-only case).
if (value.IsAudio)
Expand Down Expand Up @@ -937,6 +938,12 @@ private Control CreateValueContentWithFontSwap(DetailField field, string automat
var rtl = box.FlowDirection == FlowDirection.RightToLeft;
var display = DetailRichTextChrome.CreatePerRunFontDisplay(currentRich, field.WritingSystemFonts,
automationId + "." + wsKey + ".Display", rtl);
// The display stands in for the box, so it shows the value's own size and emphasis
// (LT-22811).
if (box.IsSet(TextBox.FontSizeProperty))
display.FontSize = box.FontSize;
if (box.IsSet(TextBox.FontWeightProperty))
display.FontWeight = box.FontWeight;
_valueStops.AttachDisplay(valueStop, display);

// Exactly ONE of {display, box} occupies the row at a time (IsVisible collapses the other out
Expand Down Expand Up @@ -1137,6 +1144,7 @@ public FwChooserField(
Text = CurrentName(field),
VerticalAlignment = VerticalAlignment.Center
};
FwSurfaceStyles.MarkValueText(_valueText);
ApplyEmptyValueWidth();
var content = new StackPanel
{
Expand Down Expand Up @@ -1440,6 +1448,7 @@ public FwReferenceVectorField(
BorderThickness = new Thickness(0),
Background = FwAvaloniaDensity.TransparentBrush
};
FwSurfaceStyles.MarkValueText(box);
// Held to the width its text measures, so the last character is not
// cut, and kept in step while typing.
FloorWidthToText(box);
Expand Down Expand Up @@ -1493,6 +1502,7 @@ public FwReferenceVectorField(
Background = FwAvaloniaDensity.TransparentBrush
};
}
FwSurfaceStyles.MarkValueText(text);
AutomationProperties.SetAutomationId(text, ItemAutomationId(automationId, item.Key));
// Any button selects, so a right-click's menu acts on the item under the pointer;
// focus selects too. The first item is a chip row's one Tab stop; the editors of
Expand Down Expand Up @@ -1678,6 +1688,7 @@ public FwReferenceVectorField(
Background = FwAvaloniaDensity.TransparentBrush,
Watermark = FwAvaloniaStrings.AddItem
};
FwSurfaceStyles.MarkValueText(newItem);
// Keeps its empty width until what is typed needs more than that.
FloorWidthToText(newItem, FwAvaloniaDensity.NewItemSlotMinWidth);
AutomationProperties.SetAutomationId(newItem, automationId + ".New");
Expand Down Expand Up @@ -2187,6 +2198,7 @@ public FwDialogLauncherField(string value, string label, Action launch)
Margin = FwAvaloniaDensity.TrailingGap,
Background = FwAvaloniaDensity.TransparentBrush // the value text is the hover surface
};
FwSurfaceStyles.MarkValueText(text);
AutomationProperties.SetName(text, label ?? string.Empty);

DockPanel.SetDock(_button, Dock.Right);
Expand Down
5 changes: 5 additions & 0 deletions Src/Common/FwAvalonia/Detail/FwOptionChooser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ public FwOptionChooser(IReadOnlyList<DetailChoiceOption> options,
BorderThickness = new Thickness(0),
Watermark = FwAvaloniaStrings.SearchPrompt
};
// What is typed here matches the option names, so it shows at their size.
FwSurfaceStyles.MarkValueText(_filterBox);
AutomationProperties.SetAutomationId(_filterBox, automationId + ".Search");
AutomationProperties.SetName(_filterBox, FwAvaloniaStrings.SearchPrompt);
_filterBox.TextChanged += (s, e) => ApplyFilter();
Expand Down Expand Up @@ -226,6 +228,7 @@ public FwOptionChooser(IReadOnlyList<DetailChoiceOption> options,
VerticalAlignment = VerticalAlignment.Center,
Foreground = FwAvaloniaDensity.PickerForegroundBrush
};
FwSurfaceStyles.MarkValueText(_dropdownLabel);
var chevron = new TextBlock
{
Text = "▾", // ▾ collapsed-dropdown affordance
Expand Down Expand Up @@ -948,6 +951,7 @@ private IDataTemplate OptionTemplate()
VerticalAlignment = VerticalAlignment.Center,
Foreground = FwAvaloniaDensity.HotlinkBrush
};
FwSurfaceStyles.MarkValueText(create);
AutomationProperties.SetAutomationId(create, _automationId + ".Create");
AutomationProperties.SetName(create, option.Name);
return create;
Expand All @@ -959,6 +963,7 @@ private IDataTemplate OptionTemplate()
Foreground = IsOptionAvailable(option) ? FwAvaloniaDensity.PickerForegroundBrush : FwAvaloniaDensity.DisabledOptionBrush,
Opacity = IsOptionAvailable(option) ? 1.0 : 0.55
};
FwSurfaceStyles.MarkValueText(label);
if (!_multiSelect)
{
label.Margin = new Thickness(option.Depth * 14, 0, 0, 0);
Expand Down
2 changes: 2 additions & 0 deletions Src/Common/FwAvalonia/Detail/FwReversalEntriesField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ private Control CreateRow(GroupState state, DetailReversalRow row, string rowId,
Background = FwAvaloniaDensity.TransparentBrush,
TextWrapping = TextWrapping.NoWrap
};
FwSurfaceStyles.MarkValueText(editor);
box = editor;
if (!string.IsNullOrEmpty(group.FontFamily))
editor.FontFamily = new FontFamily(group.FontFamily);
Expand Down Expand Up @@ -852,6 +853,7 @@ private static Control CreateOtherWsSuffix(DetailReversalRow row, string automat
Padding = FwAvaloniaDensity.EditorPadding,
FlowDirection = FlowDirection.LeftToRight
};
FwSurfaceStyles.MarkValueText(block);
block.Inlines.Add(new Run("["));
for (var i = 0; i < row.OtherWsForms.Count; i++)
{
Expand Down
1 change: 1 addition & 0 deletions Src/Common/FwAvalonia/Detail/FwStructuredTextField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ private Control CreateParagraphRow(
Background = FwAvaloniaDensity.TransparentBrush,
TextWrapping = TextWrapping.Wrap
};
FwSurfaceStyles.MarkValueText(box);
var paragraphStop = _paragraphStops.Add(box);
AutomationProperties.SetAutomationId(box, automationId + ".Para." + index);
AutomationProperties.SetName(box, FwAvaloniaStrings.StructuredTextParagraphName(field.Label ?? automationId, index + 1));
Expand Down
4 changes: 3 additions & 1 deletion Src/Common/FwAvalonia/Detail/LexiconFirstSlice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,9 @@ private static ViewNode StampProductLeaf(ViewNode source, string automationId, s
=> new ViewNode(source.StableId, ViewNodeKind.Field, labelOverride ?? source.Label, source.Abbreviation,
source.Field, source.RawEditor, source.EditorClassification, source.WritingSystem, source.Visibility,
source.Expansion, source.Indented, source.TargetLayout, null,
source.LocalizationKey, automationId, HostRouting.Product, helpTopicId: source.HelpTopicId);
source.LocalizationKey, automationId, HostRouting.Product,
boldEmphasis: source.BoldEmphasis, fontScalePercent: source.FontScalePercent,
helpTopicId: source.HelpTopicId);

private static ViewNode Leaf(string stableId, string label, string field, string editor, string ws, string automationId)
=> new ViewNode(stableId, ViewNodeKind.Field, label, null, field, editor,
Expand Down
Loading
Loading