diff --git a/components/TitleBar/samples/TitleBarFullSample.xaml.cs b/components/TitleBar/samples/TitleBarFullSample.xaml.cs
index 546d4ec0a..9f950cd4a 100644
--- a/components/TitleBar/samples/TitleBarFullSample.xaml.cs
+++ b/components/TitleBar/samples/TitleBarFullSample.xaml.cs
@@ -44,7 +44,14 @@ await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
SystemBackdrop = new MicaBackdrop()
};
- newWindow.Content = new ShellPage(newWindow);
+
+ // Create the content for the window to show
+ // and set the FlowDirection to match the current region.
+ newWindow.Content = new ShellPage(newWindow)
+ {
+ FlowDirection = this.FlowDirection
+ };
+
newWindow.Activate();
#endif
}
diff --git a/components/TitleBar/src/NativeMethods.cs b/components/TitleBar/src/NativeMethods.cs
index d3874648c..d5dff8ccf 100644
--- a/components/TitleBar/src/NativeMethods.cs
+++ b/components/TitleBar/src/NativeMethods.cs
@@ -19,14 +19,21 @@ public enum WindowMessage : int
[Flags]
public enum WindowStyle : uint
{
- WS_SYSMENU = 0x80000
+ WS_SYSMENU = 0x80000,
+ }
+
+ [Flags]
+ public enum WindowStyleExtended : ulong
+ {
+ WS_EX_LAYOUTRTL= 0x00400000L,
}
[Flags]
public enum WindowLongIndexFlags : int
{
GWL_WNDPROC = -4,
- GWL_STYLE = -16
+ GWL_STYLE = -16,
+ GWL_EXSTYLE = -20,
}
[Flags]
@@ -44,43 +51,50 @@ public enum SystemCommand
SC_KEYMENU = 0xF100
}
+ // TODO: Check for typing online. IntPtr, int, or long?
+
[DllImport("user32.dll", EntryPoint = "GetWindowLongW", SetLastError = false)]
- public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
+ public static extern int GetWindowLongW(IntPtr hWnd, int nIndex);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", SetLastError = false)]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtrW", SetLastError = false)]
- public static extern int GetWindowLongPtr(IntPtr hWnd, int nIndex);
+ public static extern int GetWindowLongPtrW(IntPtr hWnd, int nIndex);
public static int GetWindowLongAuto(IntPtr hWnd, int nIndex)
{
if (IntPtr.Size is 8)
{
- return GetWindowLongPtr(hWnd, nIndex);
+ return GetWindowLongPtrW(hWnd, nIndex);
}
else
{
- return GetWindowLong(hWnd, nIndex);
+ return GetWindowLongW(hWnd, nIndex);
}
}
[DllImport("user32.dll", EntryPoint = "FindWindowExW", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow);
-
[DllImport("user32.dll", EntryPoint = "SetWindowLongW", SetLastError = false)]
- public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
+ public static extern IntPtr SetWindowLongW(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
- [DllImport("user32.dll", EntryPoint = "SetWindowLongPtrW", SetLastError = false)]
+ [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = false)]
public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
+ [DllImport("user32.dll", EntryPoint = "SetWindowLongPtrW", SetLastError = false)]
+ public static extern IntPtr SetWindowLongPtrW(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
+
public static IntPtr SetWindowLongAuto(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
{
if (IntPtr.Size is 8)
{
- return SetWindowLongPtr(hWnd, nIndex, dwNewLong);
+ return SetWindowLongPtrW(hWnd, nIndex, dwNewLong);
}
else
{
- return SetWindowLong(hWnd, nIndex, dwNewLong);
+ return SetWindowLongW(hWnd, nIndex, dwNewLong);
}
}
diff --git a/components/TitleBar/src/TitleBar.Properties.cs b/components/TitleBar/src/TitleBar.Properties.cs
index 17237dacb..168512ea1 100644
--- a/components/TitleBar/src/TitleBar.Properties.cs
+++ b/components/TitleBar/src/TitleBar.Properties.cs
@@ -58,6 +58,11 @@ public partial class TitleBar : Control
public static readonly DependencyProperty AutoConfigureCustomTitleBarProperty = DependencyProperty.Register(nameof(AutoConfigureCustomTitleBar), typeof(bool), typeof(TitleBar), new PropertyMetadata(true, AutoConfigureCustomTitleBarChanged));
#if WINAPPSDK
+ ///
+ /// The backing for the property.
+ ///
+ public static readonly DependencyProperty AutoChangeWindowLayoutStyleProperty = DependencyProperty.Register(nameof(AutoChangeWindowLayoutStyle), typeof(bool), typeof(TitleBar), new PropertyMetadata(true));
+
///
/// The backing for the property.
///
@@ -165,6 +170,15 @@ public bool AutoConfigureCustomTitleBar
}
#if WINAPPSDK
+ ///
+ /// Gets or sets if the TitleBar should automatically change the Window's LayoutStyle to match the FlowDirection of the TitleBar (WASDK only).
+ ///
+ public bool AutoChangeWindowLayoutStyle
+ {
+ get => (bool)GetValue(AutoChangeWindowLayoutStyleProperty);
+ set => SetValue(AutoChangeWindowLayoutStyleProperty, value);
+ }
+
///
/// Gets or sets the window the TitleBar should configure (WASDK only).
///
diff --git a/components/TitleBar/src/TitleBar.WASDK.cs b/components/TitleBar/src/TitleBar.WASDK.cs
index 6e5286658..321872132 100644
--- a/components/TitleBar/src/TitleBar.WASDK.cs
+++ b/components/TitleBar/src/TitleBar.WASDK.cs
@@ -3,17 +3,17 @@
// See the LICENSE file in the project root for more information.
#if WINDOWS_WINAPPSDK && !HAS_UNO
-using Windows.Graphics;
using Microsoft.UI;
using Microsoft.UI.Input;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml.Media;
+using System.Runtime.InteropServices;
+using Windows.Graphics;
namespace CommunityToolkit.WinUI.Controls;
[TemplatePart(Name = nameof(PART_FooterPresenter), Type = typeof(ContentPresenter))]
[TemplatePart(Name = nameof(PART_ContentPresenter), Type = typeof(ContentPresenter))]
-
public partial class TitleBar : Control
{
WndProcHelper? WndProcHelper;
@@ -54,12 +54,26 @@ private void SetWASDKTitleBar()
};
}
+ // Set the caption buttons to match the flow direction of the titlebar
+ if (AutoChangeWindowLayoutStyle)
+ {
+ UpdateCaptionButtonsDirection(this.FlowDirection);
+ }
+
PART_ContentPresenter = GetTemplateChild(nameof(PART_ContentPresenter)) as ContentPresenter;
PART_FooterPresenter = GetTemplateChild(nameof(PART_FooterPresenter)) as ContentPresenter;
// Get caption button occlusion information.
int CaptionButtonOcclusionWidthRight = Window.AppWindow.TitleBar.RightInset;
int CaptionButtonOcclusionWidthLeft = Window.AppWindow.TitleBar.LeftInset;
+
+ // Swap left/right if in RTL mode
+ if (this.FlowDirection == FlowDirection.RightToLeft)
+ {
+ (CaptionButtonOcclusionWidthRight, CaptionButtonOcclusionWidthLeft) = (CaptionButtonOcclusionWidthLeft, CaptionButtonOcclusionWidthRight);
+ }
+
+ // Set padding columns to match caption button occlusion.
PART_LeftPaddingColumn!.Width = new GridLength(CaptionButtonOcclusionWidthLeft);
PART_RightPaddingColumn!.Width = new GridLength(CaptionButtonOcclusionWidthRight);
@@ -102,6 +116,27 @@ private void UpdateCaptionButtons(FrameworkElement rootElement)
}
}
+ private void UpdateCaptionButtonsDirection(FlowDirection direction)
+ {
+ var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this.Window);
+
+ if (hwnd != 0)
+ {
+ var exStyle = NativeMethods.GetWindowLongPtr(hwnd, (int)NativeMethods.WindowLongIndexFlags.GWL_EXSTYLE);
+
+ if (direction == FlowDirection.RightToLeft)
+ {
+ exStyle |= (nint)NativeMethods.WindowStyleExtended.WS_EX_LAYOUTRTL;
+ }
+ else
+ {
+ exStyle &= (nint)NativeMethods.WindowStyleExtended.WS_EX_LAYOUTRTL;
+ }
+
+ NativeMethods.SetWindowLongPtr(hwnd, (int)NativeMethods.WindowLongIndexFlags.GWL_EXSTYLE, exStyle);
+ }
+ }
+
private void ResetWASDKTitleBar()
{
if (this.Window == null)
diff --git a/components/TitleBar/src/WndProcHelper.cs b/components/TitleBar/src/WndProcHelper.cs
index 63ed9732e..e40347233 100644
--- a/components/TitleBar/src/WndProcHelper.cs
+++ b/components/TitleBar/src/WndProcHelper.cs
@@ -44,7 +44,7 @@ public void RegisterInputNonClientPointerSourceWndProc(WNDPROC wndProc)
if (inputNonClientPointerSourceHandle != IntPtr.Zero)
{
- int style = NativeMethods.GetWindowLongAuto(Handle, (int)NativeMethods.WindowLongIndexFlags.GWL_STYLE);
+ IntPtr style = NativeMethods.GetWindowLongAuto(Handle, (int)NativeMethods.WindowLongIndexFlags.GWL_STYLE);
NativeMethods.SetWindowLongAuto(Handle, (int)NativeMethods.WindowLongIndexFlags.GWL_STYLE, (IntPtr)(style & ~(int)NativeMethods.WindowStyle.WS_SYSMENU));
newInputNonClientPointerSourceWndProc = wndProc;