diff --git a/src/modules/cmdpal/Core/Microsoft.CmdPal.Core.ViewModels/ShellViewModel.cs b/src/modules/cmdpal/Core/Microsoft.CmdPal.Core.ViewModels/ShellViewModel.cs index fed47a0591..a4178a2b15 100644 --- a/src/modules/cmdpal/Core/Microsoft.CmdPal.Core.ViewModels/ShellViewModel.cs +++ b/src/modules/cmdpal/Core/Microsoft.CmdPal.Core.ViewModels/ShellViewModel.cs @@ -476,6 +476,7 @@ public partial class ShellViewModel : ObservableObject, navigationToken, TaskContinuationOptions.None, _scheduler); + return; } // ------------------------------------------------------------- diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockControl.xaml.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockControl.xaml.cs index 36ac26883d..fbc29efd9a 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockControl.xaml.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockControl.xaml.cs @@ -178,6 +178,12 @@ public sealed partial class DockControl : UserControl, IRecipient + + + + + + + + + , IRecipient, IRecipient, + IRecipient, + IRecipient, IDisposable { #pragma warning disable SA1306 // Field names should begin with lower-case letter @@ -93,6 +97,9 @@ public sealed partial class DockWindow : WindowEx, WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); + WeakReferenceMessenger.Default.Register(this); + WeakReferenceMessenger.Default.Register(this); + _hwnd = GetWindowHandle(this); // Subclass the window to intercept messages @@ -529,6 +536,11 @@ public sealed partial class DockWindow : WindowEx, return false; } + private void ContextMenuFlyout_Opened(object sender, object e) + { + ContextMenuControl.FocusSearchBox(); + } + public void Receive(QuitMessage message) { DispatcherQueue.TryEnqueue(() => @@ -539,6 +551,25 @@ public sealed partial class DockWindow : WindowEx, }); } + public void Receive(ShowCommandInContextMenuMessage message) + { + DispatcherQueue.TryEnqueue(() => + { + ShowFlyoutOnUiThread(message.Context, message.Position); + }); + } + + public void Receive(CloseContextMenuMessage message) + { + DispatcherQueue.TryEnqueue(() => + { + if (ContextMenuFlyout.IsOpen) + { + ContextMenuFlyout.Hide(); + } + }); + } + void IRecipient.Receive(RequestShowPaletteAtMessage message) { DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () => RequestShowPaletteOnUiThread(message.PosDips)); @@ -546,6 +577,10 @@ public sealed partial class DockWindow : WindowEx, private void RequestShowPaletteOnUiThread(Point posDips) { + // TODO!!!! posDips was originally relative to the dock window. + // It's now relative to the screen. + // this method wasn't yet updated for that. + // pos is relative to our root. We need to convert to screen coords. var rootPosDips = Root.TransformToVisual(null).TransformPoint(new Point(0, 0)); var screenPosDips = new Point(rootPosDips.X + posDips.X, rootPosDips.Y + posDips.Y); @@ -613,6 +648,93 @@ public sealed partial class DockWindow : WindowEx, WeakReferenceMessenger.Default.Send(new(screenPosPixels, anchorPoint)); } + private void ShowFlyoutOnUiThread(IContextMenuContext context, Point position) + { + ContextMenuControl.ViewModel.SelectedItem = context; + + // Depending on the side we're on, change the direction of the results + switch (_settings.Side) + { + case DockSide.Top: + case DockSide.Left: + case DockSide.Right: + ContextMenuControl.ViewModel.FilterOnTop = true; + break; + case DockSide.Bottom: + ContextMenuControl.ViewModel.FilterOnTop = false; + break; + } + + // position is relative to our root. We need to convert to screen coords. + // + // Root.TransformToVisual(null) will always return 0,0, because Root is at the root of our window. + // + // we instead need: + + // var rootPosDips = Root.TransformToVisual(null).TransformPoint(new Point(0, 0)); + + // var screenPosDips = new Point(rootPosDips.X + position.X, rootPosDips.Y + position.Y); + + // TODO! deal with DPI - I'm sure this is wrong + var dpi = PInvoke.GetDpiForWindow(_hwnd); + PInvoke.GetWindowRect(_hwnd, out var ourRect); + var scaleFactor = dpi / 96.0; + + var positionPixels = new Point(position.X * scaleFactor, position.Y * scaleFactor); + + var screenPosPixels = // new Point(screenPosDips.X * scaleFactor, screenPosDips.Y * scaleFactor); + new Point(ourRect.left + positionPixels.X, ourRect.top + positionPixels.Y); + + var screenWidth = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CXSCREEN); + var screenHeight = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CYSCREEN); + var onTopHalf = screenPosPixels.Y < screenHeight / 2; + var onLeftHalf = screenPosPixels.X < screenWidth / 2; + var onRightHalf = !onLeftHalf; + var onBottomHalf = !onTopHalf; + var anchorPoint = _settings.Side switch + { + DockSide.Top => onLeftHalf ? AnchorPoint.TopLeft : AnchorPoint.TopRight, + DockSide.Bottom => onLeftHalf ? AnchorPoint.BottomLeft : AnchorPoint.BottomRight, + DockSide.Left => onTopHalf ? AnchorPoint.TopLeft : AnchorPoint.BottomLeft, + DockSide.Right => onTopHalf ? AnchorPoint.TopRight : AnchorPoint.BottomRight, + _ => AnchorPoint.TopLeft, + }; + + // we also need to slide the anchor point a bit away from the dock + var paddingDips = 8; + var paddingPixels = paddingDips * scaleFactor; + + // Depending on the side we're on, we need to offset differently + switch (_settings.Side) + { + case DockSide.Top: + screenPosPixels.Y += paddingPixels; + break; + case DockSide.Bottom: + screenPosPixels.Y -= paddingPixels; + break; + case DockSide.Left: + screenPosPixels.X += paddingPixels; + break; + case DockSide.Right: + screenPosPixels.X -= paddingPixels; + break; + } + + // var finalPosDips = new Point((screenPosPixels.X / scaleFactor) - rootPosDips.X, (screenPosPixels.Y / scaleFactor) - rootPosDips.Y); + var finalPosDips = new Point( + (screenPosPixels.X - ourRect.left) / scaleFactor, + (screenPosPixels.Y - ourRect.top) / scaleFactor); + + ContextMenuFlyout.ShowAt( + Root, + new FlyoutShowOptions() + { + ShowMode = FlyoutShowMode.Standard, + Position = finalPosDips, + }); + } + public DockWindowViewModel WindowViewModel => _windowViewModel; public void Dispose() diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/MainWindow.xaml b/src/modules/cmdpal/Microsoft.CmdPal.UI/MainWindow.xaml index 00f9c9a49d..32329e17a0 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/MainWindow.xaml +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/MainWindow.xaml @@ -16,29 +16,6 @@ Closed="MainWindow_Closed" mc:Ignorable="d"> - - - - - - - - , IRecipient, IRecipient, - IRecipient, - IRecipient, IRecipient, IRecipient, IDisposable @@ -144,8 +141,6 @@ public sealed partial class MainWindow : WindowEx, WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); - WeakReferenceMessenger.Default.Register(this); - WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); @@ -680,41 +675,6 @@ public sealed partial class MainWindow : WindowEx, _sessionErrorCount++; } - public void Receive(ShowCommandInContextMenuMessage message) - { - DispatcherQueue.TryEnqueue(() => - { - ContextMenuControl.ViewModel.SelectedItem = message.Context; - ContextMenuFlyout.ShouldConstrainToRootBounds = false; - ContextMenuFlyout.ShowMode = FlyoutShowMode.Standard; - ContextMenuFlyout.ShowAt(RootElement); - - // ContextMenuFlyout.ShowAt( - // RootElement, - // new FlyoutShowOptions() - // { - // ShowMode = FlyoutShowMode.Standard, - // Position = message.Position, - // }); - }); - } - - public void Receive(CloseContextMenuMessage message) - { - DispatcherQueue.TryEnqueue(() => - { - if (ContextMenuFlyout.IsOpen) - { - ContextMenuFlyout.Hide(); - } - }); - } - - private void ContextMenuFlyout_Opened(object sender, object e) - { - ContextMenuControl.FocusSearchBox(); - } - /// /// Ends the current telemetry session and emits the CmdPal_SessionDuration event. /// Aggregates all session metrics collected since ShowWindow and sends them to telemetry. @@ -1251,6 +1211,27 @@ public sealed partial class MainWindow : WindowEx, }); } + // public void Receive(ShowCommandInContextMenuMessage message) + // { + // DispatcherQueue.TryEnqueue(() => + // { + // ContextMenuControl.ViewModel.SelectedItem = message.Context; + // ContextMenuFlyout.ShouldConstrainToRootBounds = false; + // ContextMenuFlyout.ShowMode = FlyoutShowMode.Standard; + + // // message.Position is in dips, + + // ContextMenuFlyout.ShowAt(RootElement); + + // // ContextMenuFlyout.ShowAt( + // // RootElement, + // // new FlyoutShowOptions() + // // { + // // ShowMode = FlyoutShowMode.Standard, + // // Position = message.Position, + // // }); + // }); + // } private unsafe void StealForeground() { var foregroundWindow = PInvoke.GetForegroundWindow();