Skip to content

Commit 53cdafb

Browse files
authored
Merge pull request #14 from NeverMorewd/fix/pipboy-window-icon-not-shown-in-titlebar
fix: display Window.Icon in PipboyWindow custom title bar
2 parents 5cdf242 + e780db6 commit 53cdafb

File tree

2 files changed

+80
-18
lines changed

2 files changed

+80
-18
lines changed

src/Pipboy.Avalonia/Controls/PipboyWindow.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
using System;
2+
using System.IO;
23
using Avalonia;
34
using Avalonia.Controls;
45
using Avalonia.Controls.Metadata;
56
using Avalonia.Controls.Primitives;
67
using Avalonia.Input;
8+
using Avalonia.Media;
9+
using Avalonia.Media.Imaging;
710
using Avalonia.Platform;
811

912
namespace Pipboy.Avalonia;
@@ -21,10 +24,19 @@ public class PipboyWindow : Window
2124
public static readonly StyledProperty<object?> TitleBarContentProperty =
2225
AvaloniaProperty.Register<PipboyWindow, object?>(nameof(TitleBarContent));
2326

27+
public static readonly StyledProperty<IImage?> TitleBarIconProperty =
28+
AvaloniaProperty.Register<PipboyWindow, IImage?>(nameof(TitleBarIcon));
29+
30+
public static readonly StyledProperty<double> TitleBarHeightProperty =
31+
AvaloniaProperty.Register<PipboyWindow, double>(nameof(TitleBarHeight), defaultValue: 32.0);
32+
2433
static PipboyWindow()
2534
{
2635
WindowStateProperty.Changed.AddClassHandler<PipboyWindow>(
2736
(w, e) => w.PseudoClasses.Set(":maximized", e.NewValue is WindowState.Maximized));
37+
38+
IconProperty.Changed.AddClassHandler<PipboyWindow>(
39+
(w, e) => w.SyncTitleBarIcon(e.NewValue as WindowIcon));
2840
}
2941

3042
/// <summary>
@@ -37,6 +49,28 @@ public object? TitleBarContent
3749
set => SetValue(TitleBarContentProperty, value);
3850
}
3951

52+
/// <summary>
53+
/// Icon displayed in the custom title bar. Automatically synced from
54+
/// <see cref="Window.Icon"/> when that property is set; can also be
55+
/// overridden independently.
56+
/// </summary>
57+
public IImage? TitleBarIcon
58+
{
59+
get => GetValue(TitleBarIconProperty);
60+
set => SetValue(TitleBarIconProperty, value);
61+
}
62+
63+
/// <summary>
64+
/// Height of the custom title bar row (and its chrome buttons).
65+
/// The title bar icon scales automatically to fill this height.
66+
/// Default is 32.
67+
/// </summary>
68+
public double TitleBarHeight
69+
{
70+
get => GetValue(TitleBarHeightProperty);
71+
set => SetValue(TitleBarHeightProperty, value);
72+
}
73+
4074
/// <summary>
4175
/// Overriding StyleKeyOverride is CRITICAL: Window base class returns typeof(Window),
4276
/// which causes Avalonia to apply the Window ControlTheme instead of ours.
@@ -51,6 +85,26 @@ public PipboyWindow()
5185
SystemDecorations = SystemDecorations.Full;
5286
}
5387

88+
private void SyncTitleBarIcon(WindowIcon? icon)
89+
{
90+
if (icon == null)
91+
{
92+
TitleBarIcon = null;
93+
return;
94+
}
95+
try
96+
{
97+
using var stream = new MemoryStream();
98+
icon.Save(stream);
99+
stream.Position = 0;
100+
TitleBarIcon = new Bitmap(stream);
101+
}
102+
catch
103+
{
104+
TitleBarIcon = null;
105+
}
106+
}
107+
54108
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
55109
{
56110
base.OnApplyTemplate(e);

src/Pipboy.Avalonia/Styles/Controls/Window.axaml

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,13 @@
133133
<!-- ── Inline title bar ── -->
134134
<Border
135135
DockPanel.Dock="Top"
136-
Height="32"
136+
Height="{TemplateBinding TitleBarHeight}"
137137
Background="{DynamicResource PipboyPrimaryDarkBrush}"
138138
BorderBrush="{DynamicResource PipboyBorderBrush}"
139139
BorderThickness="0,0,0,1">
140-
<Grid ColumnDefinitions="*,Auto">
140+
<Grid ColumnDefinitions="*,Auto,Auto">
141141

142-
<!-- Drag area -->
142+
<!-- Drag area (icon + title) -->
143143
<Border
144144
Name="PART_TitleDragArea"
145145
Grid.Column="0"
@@ -150,49 +150,57 @@
150150
VerticalAlignment="Center"
151151
Orientation="Horizontal"
152152
Spacing="10">
153-
<!-- Pip-Boy icon square -->
153+
<!-- Title bar icon: shows window icon when set, else Pip-Boy green square -->
154+
<Image
155+
Name="PART_TitleBarIcon"
156+
VerticalAlignment="Stretch"
157+
Margin="0,6"
158+
Stretch="Uniform"
159+
Source="{TemplateBinding TitleBarIcon}"
160+
IsVisible="{TemplateBinding TitleBarIcon, Converter={x:Static ObjectConverters.IsNotNull}}"
161+
RenderOptions.BitmapInterpolationMode="HighQuality" />
154162
<Border
155163
Width="8"
156164
Height="8"
157-
Background="{DynamicResource PipboyPrimaryBrush}" />
165+
Background="{DynamicResource PipboyPrimaryBrush}"
166+
IsVisible="{TemplateBinding TitleBarIcon, Converter={x:Static ObjectConverters.IsNull}}" />
158167
<!-- Title -->
159168
<TextBlock
160169
VerticalAlignment="Center"
161170
FontSize="{DynamicResource PipboyFontSizeSmall}"
162171
FontWeight="Bold"
163172
Foreground="{DynamicResource PipboyTextBrush}"
164173
Text="{TemplateBinding Title}" />
165-
<!-- Separator -->
166-
<TextBlock
167-
VerticalAlignment="Center"
168-
Classes="dim"
169-
FontSize="{DynamicResource PipboyFontSizeXSmall}"
170-
IsVisible="{TemplateBinding TitleBarContent, Converter={x:Static ObjectConverters.IsNotNull}}"
171-
Text=" ·" />
172-
<!-- Extra title bar content -->
173-
<ContentPresenter
174-
VerticalAlignment="Center"
175-
Content="{TemplateBinding TitleBarContent}"
176-
IsVisible="{TemplateBinding TitleBarContent, Converter={x:Static ObjectConverters.IsNotNull}}" />
177174
</StackPanel>
178175
</Border>
179176

177+
<!-- Extra title bar content — right-aligned, beside system buttons -->
178+
<ContentPresenter
179+
Grid.Column="1"
180+
VerticalAlignment="Center"
181+
Margin="0,0,4,0"
182+
Content="{TemplateBinding TitleBarContent}"
183+
IsVisible="{TemplateBinding TitleBarContent, Converter={x:Static ObjectConverters.IsNotNull}}" />
184+
180185
<!-- System buttons -->
181186
<StackPanel
182-
Grid.Column="1"
187+
Grid.Column="2"
183188
VerticalAlignment="Stretch"
184189
Orientation="Horizontal">
185190
<Button
186191
Name="PART_MinimizeButton"
187192
Theme="{StaticResource ChromeButtonTheme}"
193+
Height="{TemplateBinding TitleBarHeight}"
188194
Content="" />
189195
<Button
190196
Name="PART_MaxRestoreButton"
191197
Theme="{StaticResource ChromeButtonTheme}"
198+
Height="{TemplateBinding TitleBarHeight}"
192199
Content="" />
193200
<Button
194201
Name="PART_CloseButton"
195202
Theme="{StaticResource ChromeCloseButtonTheme}"
203+
Height="{TemplateBinding TitleBarHeight}"
196204
Content="" />
197205
</StackPanel>
198206

0 commit comments

Comments
 (0)