diff --git a/HellionChat/Ui/StyleEngine/Widgets/SettingRow.cs b/HellionChat/Ui/StyleEngine/Widgets/SettingRow.cs index d380a2f..32385ba 100644 --- a/HellionChat/Ui/StyleEngine/Widgets/SettingRow.cs +++ b/HellionChat/Ui/StyleEngine/Widgets/SettingRow.cs @@ -34,6 +34,10 @@ internal readonly record struct SettingRowContext public float ControlHeight { get; init; } public float HoverAmount { get; init; } + // Passed through so a draw-list control can fade itself. BeginDisabled only + // reaches ImGui's own widgets, so the row cannot dim its control for it. + public bool Disabled { get; init; } + // Right edge of the control column, vertically centred. public Vector2 AlignRight(Vector2 size) => new( @@ -56,10 +60,12 @@ internal static class SettingRow string? description, SettingRowColors colors, Action drawControl, + bool disabled = false, SettingRowStyle? styleOverride = null ) { var style = styleOverride ?? new SettingRowStyle(); + var alpha = disabled ? 0.5f : 1f; var scale = Metrics.Scale; var padY = style.PadY * scale; var gap = style.Gap * scale; @@ -78,11 +84,13 @@ internal static class SettingRow // The label half is the hit area: the control column submits its own // item and would fight with a button underneath it. ImGui.SetCursorScreenPos(origin); - var labelClicked = ImGui.InvisibleButton( - $"##hellion-srow-{id}", - new Vector2(labelWidth, size.Y) - ); - var hovered = ImGui.IsMouseHoveringRect(origin, origin + size) && ImGui.IsWindowHovered(); + var labelClicked = + ImGui.InvisibleButton($"##hellion-srow-{id}", new Vector2(labelWidth, size.Y)) + && !disabled; + var hovered = + !disabled + && ImGui.IsMouseHoveringRect(origin, origin + size) + && ImGui.IsWindowHovered(); var hoverAmount = HoverState.Query(id, hovered); // Chrome first, all of it draw-list only: nothing between here and the @@ -98,7 +106,7 @@ internal static class SettingRow SurfaceHoverAbgr = colors.SurfaceHoverAbgr, SurfaceActiveAbgr = colors.SurfaceHoverAbgr, AccentAbgr = colors.BorderAbgr, - BorderAbgr = colors.BorderAbgr, + BorderAbgr = ColourUtil.ApplyAlpha(colors.BorderAbgr, alpha), }, new RowStyle { AccentBarWidth = 0f, DrawSeparator = style.DrawSeparator } ); @@ -107,13 +115,17 @@ internal static class SettingRow // control. The description wraps instead of being cut. var dl = ImGui.GetWindowDrawList(); dl.PushClipRect(origin, new Vector2(origin.X + labelWidth, origin.Y + size.Y), true); - dl.AddText(new Vector2(origin.X, origin.Y + padY), colors.LabelAbgr, label); + dl.AddText( + new Vector2(origin.X, origin.Y + padY), + ColourUtil.ApplyAlpha(colors.LabelAbgr, alpha), + label + ); if (description is not null) dl.AddText( ImGui.GetFont(), ImGui.GetFontSize(), new Vector2(origin.X, origin.Y + padY + lineHeight), - colors.DescriptionAbgr, + ColourUtil.ApplyAlpha(colors.DescriptionAbgr, alpha), description, labelWidth ); @@ -129,6 +141,7 @@ internal static class SettingRow ControlWidth = controlWidth, ControlHeight = lineHeight, HoverAmount = hoverAmount, + Disabled = disabled, } ); diff --git a/HellionChat/Ui/Windows/WidgetGalleryWindow.cs b/HellionChat/Ui/Windows/WidgetGalleryWindow.cs index 227ed6a..cb9c9fa 100644 --- a/HellionChat/Ui/Windows/WidgetGalleryWindow.cs +++ b/HellionChat/Ui/Windows/WidgetGalleryWindow.cs @@ -48,6 +48,7 @@ internal sealed class WidgetGalleryWindow : Window DrawSectionHeaderSection(c); DrawRowSection(c); DrawToggleSection(c); + DrawSegmentedSection(c); DrawSettingRowSection(c); DrawBadgeSection(c); DrawPillSection(c); @@ -250,9 +251,84 @@ internal sealed class WidgetGalleryWindow : Window null, colors, _ => ImGui.SliderInt("##gallery-sr-d", ref _badgeCount, 0, 150), - new SettingRowStyle { DrawSeparator = false, PreferredControlWidth = 90f } + styleOverride: new SettingRowStyle + { + DrawSeparator = false, + PreferredControlWidth = 90f, + } ); + // Disabled: the label fades, the row stops lighting up, and the click + // does not reach the setting. + using (ImRaii.Disabled()) + { + SettingRow.Draw( + ImGui.GetID("gallery.settingrow.disabled"), + "Disabled row", + "Neither the row nor its control may respond.", + colors, + _ => ImGui.SliderInt("##gallery-sr-e", ref _badgeCount, 0, 150), + disabled: true + ); + } + + ImGui.Spacing(); + } + + // Segment labels are held rather than built per frame: a collection + // expression in the draw call would allocate a fresh array every frame. + private static readonly string[] SegmentLabelsTwo = ["Sidebar", "Top tabs"]; + private static readonly string[] SegmentLabelsThree = ["Off", "Compact", "Full"]; + private int _segmentTwo; + private int _segmentThree = 1; + + private void DrawSegmentedSection(ThemeColors c) + { + var colors = new SegmentedControlColors + { + TrackAbgr = _palette.Abgr(Token.SurfaceBase, c), + SelectedAbgr = _palette.Abgr(Token.AccentPrimary, c), + HoverAbgr = _palette.Abgr(Token.SurfaceHover, c), + LabelAbgr = _palette.Abgr(Token.TextMuted, c), + SelectedLabelAbgr = _palette.Abgr(Token.Text, c), + BorderAbgr = _palette.Abgr(Token.Border, c), + }; + + var width = MathF.Min(260f * Metrics.Scale, ImGui.GetContentRegionAvail().X); + + _segmentTwo = SegmentedControl.Draw( + ImGui.GetID("gallery.segmented.two"), + ImGui.GetCursorScreenPos(), + width, + SegmentLabelsTwo, + _segmentTwo, + colors + ); + ImGui.Dummy(SegmentedControl.CalcSize(width)); + + _segmentThree = SegmentedControl.Draw( + ImGui.GetID("gallery.segmented.three"), + ImGui.GetCursorScreenPos(), + width, + SegmentLabelsThree, + _segmentThree, + colors + ); + ImGui.Dummy(SegmentedControl.CalcSize(width)); + + // Odd width over three segments: the edges must stay flush with no seam + // and no overhang on the right. + SegmentedControl.Draw( + ImGui.GetID("gallery.segmented.odd"), + ImGui.GetCursorScreenPos(), + 201f, + SegmentLabelsThree, + 0, + colors, + disabled: true + ); + ImGui.Dummy(SegmentedControl.CalcSize(201f)); + ImGui.Spacing(); }