2022-10-23 11:02:31 +13:00
|
|
|
|
// <copyright file="Menu.xaml.cs" company="PlaceholderCompany">
|
2020-07-07 09:37:55 +12:00
|
|
|
|
// Copyright (c) PlaceholderCompany. All rights reserved.
|
|
|
|
|
// </copyright>
|
|
|
|
|
|
|
|
|
|
namespace SystemTrayMenu.UserInterface
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2020-07-07 07:15:45 +12:00
|
|
|
|
using System;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
using System.Collections.Generic;
|
2023-08-13 04:37:26 +12:00
|
|
|
|
using System.Collections.Specialized;
|
2023-04-16 07:23:28 +12:00
|
|
|
|
using System.IO;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
using System.Windows;
|
|
|
|
|
using System.Windows.Controls;
|
|
|
|
|
using System.Windows.Data;
|
|
|
|
|
using System.Windows.Input;
|
|
|
|
|
using System.Windows.Media;
|
2023-09-18 09:22:29 +12:00
|
|
|
|
using System.Windows.Media.Animation;
|
2022-12-04 10:41:03 +13:00
|
|
|
|
using SystemTrayMenu.Business;
|
2020-07-07 07:15:45 +12:00
|
|
|
|
using SystemTrayMenu.DataClasses;
|
|
|
|
|
using SystemTrayMenu.DllImports;
|
2023-09-03 03:42:43 +12:00
|
|
|
|
using SystemTrayMenu.Helpers;
|
2022-12-04 10:41:03 +13:00
|
|
|
|
using SystemTrayMenu.Properties;
|
2020-07-07 07:15:45 +12:00
|
|
|
|
using SystemTrayMenu.Utilities;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Logic of Menu window.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public partial class Menu : Window
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2022-12-04 13:24:30 +13:00
|
|
|
|
private const int CornerRadius = 10;
|
|
|
|
|
|
2023-04-24 09:53:20 +12:00
|
|
|
|
private static readonly RoutedEvent FadeToTransparentEvent = EventManager.RegisterRoutedEvent(
|
|
|
|
|
nameof(FadeToTransparent), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Menu));
|
|
|
|
|
|
2022-12-04 13:24:30 +13:00
|
|
|
|
private static readonly RoutedEvent FadeInEvent = EventManager.RegisterRoutedEvent(
|
|
|
|
|
nameof(FadeIn), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Menu));
|
|
|
|
|
|
|
|
|
|
private static readonly RoutedEvent FadeOutEvent = EventManager.RegisterRoutedEvent(
|
|
|
|
|
nameof(FadeOut), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Menu));
|
|
|
|
|
|
2023-04-16 07:23:28 +12:00
|
|
|
|
private readonly string folderPath;
|
2023-08-13 04:37:26 +12:00
|
|
|
|
|
2023-09-12 05:25:38 +12:00
|
|
|
|
private int countLeftMouseButtonClicked;
|
2023-06-03 11:17:05 +12:00
|
|
|
|
private bool isShellContextMenuOpen;
|
2021-04-17 12:39:48 +12:00
|
|
|
|
private bool directionToRight;
|
2021-11-25 07:01:59 +13:00
|
|
|
|
private Point lastLocation;
|
2023-04-20 10:50:29 +12:00
|
|
|
|
|
2023-05-19 08:16:39 +12:00
|
|
|
|
internal Menu(RowData? rowDataParent, string path)
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
2020-07-07 07:15:45 +12:00
|
|
|
|
|
2023-04-17 01:45:47 +12:00
|
|
|
|
if (!Config.ShowDirectoryTitleAtTop)
|
|
|
|
|
{
|
2023-08-17 08:45:43 +12:00
|
|
|
|
txtTitle.Visibility = Visibility.Collapsed;
|
2023-04-17 01:45:47 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Config.ShowSearchBar)
|
|
|
|
|
{
|
|
|
|
|
searchPanel.Visibility = Visibility.Collapsed;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-19 04:20:21 +12:00
|
|
|
|
buttonOpenFolder.Visibility = Visibility.Collapsed;
|
2023-04-17 01:45:47 +12:00
|
|
|
|
|
|
|
|
|
if (!Config.ShowFunctionKeySettings)
|
|
|
|
|
{
|
|
|
|
|
buttonSettings.Visibility = Visibility.Collapsed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Config.ShowFunctionKeyRestart)
|
|
|
|
|
{
|
|
|
|
|
buttonRestart.Visibility = Visibility.Collapsed;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-16 07:23:28 +12:00
|
|
|
|
folderPath = path;
|
2023-05-19 08:16:39 +12:00
|
|
|
|
RowDataParent = rowDataParent;
|
2023-04-30 04:57:39 +12:00
|
|
|
|
if (RowDataParent == null)
|
2022-12-04 09:23:19 +13:00
|
|
|
|
{
|
2023-04-30 04:57:39 +12:00
|
|
|
|
// This will be a main menu
|
|
|
|
|
Level = 0;
|
2023-05-08 10:14:23 +12:00
|
|
|
|
MainMenu = this;
|
2023-04-30 04:57:39 +12:00
|
|
|
|
|
2022-12-04 09:23:19 +13:00
|
|
|
|
// Use Main Menu DPI for all further calculations
|
|
|
|
|
Scaling.CalculateFactorByDpi(this);
|
2023-05-17 05:57:02 +12:00
|
|
|
|
|
|
|
|
|
// Moving the window is only supported for the main menu
|
|
|
|
|
MouseDown += MainMenu_MoveStart;
|
2023-08-19 04:20:21 +12:00
|
|
|
|
|
|
|
|
|
if (!Config.ShowFunctionKeyPinMenu)
|
|
|
|
|
{
|
|
|
|
|
buttonMenuAlwaysOpen.Visibility = Visibility.Collapsed;
|
|
|
|
|
}
|
2022-12-04 09:23:19 +13:00
|
|
|
|
}
|
2023-04-16 07:23:28 +12:00
|
|
|
|
else
|
|
|
|
|
{
|
2023-04-30 04:57:39 +12:00
|
|
|
|
// This will be a sub menu
|
2023-05-08 10:14:23 +12:00
|
|
|
|
if (ParentMenu == null)
|
|
|
|
|
{
|
|
|
|
|
// Should never happen as each parent menu must have a valid entry which's owner is set
|
2023-08-12 12:33:11 +12:00
|
|
|
|
throw new ArgumentNullException(new (nameof(ParentMenu)));
|
2023-05-08 10:14:23 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-30 04:57:39 +12:00
|
|
|
|
Level = RowDataParent.Level + 1;
|
2023-05-08 10:14:23 +12:00
|
|
|
|
MainMenu = ParentMenu.MainMenu;
|
2023-04-30 04:57:39 +12:00
|
|
|
|
RowDataParent.SubMenu = this;
|
2023-04-17 01:45:47 +12:00
|
|
|
|
|
2023-08-19 04:20:21 +12:00
|
|
|
|
buttonMenuAlwaysOpen.Visibility = Visibility.Collapsed;
|
2023-04-17 01:45:47 +12:00
|
|
|
|
buttonSettings.Visibility = Visibility.Collapsed;
|
|
|
|
|
buttonRestart.Visibility = Visibility.Collapsed;
|
2023-04-16 07:23:28 +12:00
|
|
|
|
}
|
2022-07-10 11:53:36 +12:00
|
|
|
|
|
2023-04-16 07:23:28 +12:00
|
|
|
|
string title = new DirectoryInfo(path).Name;
|
2022-12-04 09:23:19 +13:00
|
|
|
|
if (title.Length > MenuDefines.LengthMax)
|
|
|
|
|
{
|
|
|
|
|
title = $"{title[..MenuDefines.LengthMax]}...";
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-02 06:41:58 +12:00
|
|
|
|
#if DEBUG
|
|
|
|
|
txtTitle.Text = Title = "v"
|
|
|
|
|
+ System.Reflection.Assembly.GetExecutingAssembly().GetName().Version!.Major.ToString()
|
|
|
|
|
+ "."
|
|
|
|
|
+ System.Reflection.Assembly.GetExecutingAssembly().GetName().Version!.Minor.ToString()
|
|
|
|
|
+ " - " + title;
|
|
|
|
|
#else
|
2023-04-16 22:42:42 +12:00
|
|
|
|
txtTitle.Text = Title = title;
|
2023-09-02 06:41:58 +12:00
|
|
|
|
#endif
|
2021-06-26 23:24:56 +12:00
|
|
|
|
|
2022-10-23 11:02:31 +13:00
|
|
|
|
foreach (FrameworkElement control in
|
|
|
|
|
new List<FrameworkElement>()
|
|
|
|
|
{
|
|
|
|
|
buttonMenuAlwaysOpen,
|
|
|
|
|
buttonOpenFolder,
|
|
|
|
|
buttonSettings,
|
|
|
|
|
buttonRestart,
|
|
|
|
|
pictureBoxSearch,
|
|
|
|
|
pictureBoxMenuAlwaysOpen,
|
|
|
|
|
pictureBoxOpenFolder,
|
|
|
|
|
pictureBoxSettings,
|
|
|
|
|
pictureBoxRestart,
|
2022-11-14 07:12:49 +13:00
|
|
|
|
pictureBoxLoading,
|
2022-10-23 11:02:31 +13:00
|
|
|
|
})
|
|
|
|
|
{
|
|
|
|
|
control.Width = Scaling.Scale(control.Width);
|
|
|
|
|
control.Height = Scaling.Scale(control.Height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
labelTitle.FontSize = Scaling.ScaleFontByPoints(8.25F);
|
|
|
|
|
textBoxSearch.FontSize = Scaling.ScaleFontByPoints(8.25F);
|
2022-12-04 09:23:19 +13:00
|
|
|
|
labelStatus.FontSize = Scaling.ScaleFontByPoints(7F);
|
2022-10-23 11:02:31 +13:00
|
|
|
|
dgv.FontSize = Scaling.ScaleFontByPoints(9F);
|
|
|
|
|
|
2023-04-28 09:24:25 +12:00
|
|
|
|
textBoxSearch.TextChanged += (_, _) => TextBoxSearch_TextChanged(false);
|
2023-04-16 04:48:53 +12:00
|
|
|
|
textBoxSearch.ContextMenu = new()
|
|
|
|
|
{
|
|
|
|
|
Background = SystemColors.ControlBrush,
|
|
|
|
|
};
|
|
|
|
|
textBoxSearch.ContextMenu.Items.Add(new MenuItem()
|
|
|
|
|
{
|
2023-08-12 22:01:38 +12:00
|
|
|
|
Header = Translator.GetText("To cut out"),
|
2023-04-16 04:48:53 +12:00
|
|
|
|
Command = new ActionCommand((_) => textBoxSearch.Cut()),
|
|
|
|
|
});
|
|
|
|
|
textBoxSearch.ContextMenu.Items.Add(new MenuItem()
|
|
|
|
|
{
|
|
|
|
|
Header = Translator.GetText("Copy"),
|
|
|
|
|
Command = new ActionCommand((_) => Clipboard.SetData(DataFormats.Text, textBoxSearch.SelectedText)),
|
|
|
|
|
});
|
|
|
|
|
textBoxSearch.ContextMenu.Items.Add(new MenuItem()
|
|
|
|
|
{
|
2023-08-12 22:01:38 +12:00
|
|
|
|
Header = Translator.GetText("To paste"),
|
2023-04-16 04:48:53 +12:00
|
|
|
|
Command = new ActionCommand((_) =>
|
|
|
|
|
{
|
|
|
|
|
if (Clipboard.ContainsText(TextDataFormat.Text))
|
|
|
|
|
{
|
|
|
|
|
textBoxSearch.SelectedText = Clipboard.GetData(DataFormats.Text).ToString();
|
|
|
|
|
}
|
|
|
|
|
}),
|
|
|
|
|
});
|
|
|
|
|
textBoxSearch.ContextMenu.Items.Add(new MenuItem()
|
|
|
|
|
{
|
|
|
|
|
Header = Translator.GetText("Undo"),
|
|
|
|
|
Command = new ActionCommand((_) => textBoxSearch.Undo()),
|
|
|
|
|
});
|
|
|
|
|
textBoxSearch.ContextMenu.Items.Add(new MenuItem()
|
|
|
|
|
{
|
2023-08-12 22:01:38 +12:00
|
|
|
|
Header = Translator.GetText("Selecting All"),
|
2023-04-16 04:48:53 +12:00
|
|
|
|
Command = new ActionCommand((_) => textBoxSearch.SelectAll()),
|
|
|
|
|
});
|
|
|
|
|
|
2023-04-28 09:24:25 +12:00
|
|
|
|
Loaded += (_, _) =>
|
2023-05-04 09:18:03 +12:00
|
|
|
|
{
|
2023-08-19 05:15:28 +12:00
|
|
|
|
// This will remove the outer padding from the ListView's Control Template
|
|
|
|
|
Border? dgv_border = dgv.FindVisualChildOfType<Border>(0);
|
|
|
|
|
if (dgv_border != null)
|
|
|
|
|
{
|
|
|
|
|
dgv_border.Padding = new(0);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 09:18:03 +12:00
|
|
|
|
NativeMethods.HideFromAltTab(this);
|
2022-12-04 13:24:30 +13:00
|
|
|
|
|
2023-05-04 09:18:03 +12:00
|
|
|
|
RaiseEvent(new(routedEvent: FadeInEvent));
|
2023-06-04 21:34:29 +12:00
|
|
|
|
|
|
|
|
|
FocusTextBox();
|
2023-05-04 09:18:03 +12:00
|
|
|
|
};
|
2022-11-26 11:31:20 +13:00
|
|
|
|
|
2023-04-28 09:24:25 +12:00
|
|
|
|
Closed += (_, _) =>
|
2023-05-04 09:18:03 +12:00
|
|
|
|
{
|
|
|
|
|
if (RowDataParent?.SubMenu == this)
|
2022-11-26 11:31:20 +13:00
|
|
|
|
{
|
2023-05-04 09:18:03 +12:00
|
|
|
|
RowDataParent.SubMenu = null;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-14 08:17:16 +12:00
|
|
|
|
foreach (RowData item in dgv.Items.SourceCollection)
|
2023-05-04 09:18:03 +12:00
|
|
|
|
{
|
2023-05-19 09:28:52 +12:00
|
|
|
|
item.SubMenu?.Close();
|
2023-05-04 09:18:03 +12:00
|
|
|
|
}
|
|
|
|
|
};
|
2023-09-03 03:42:43 +12:00
|
|
|
|
|
|
|
|
|
bool isTouchEnabled = NativeMethods.IsTouchEnabled();
|
|
|
|
|
if ((isTouchEnabled && Settings.Default.DragDropItemsEnabledTouch) ||
|
|
|
|
|
(!isTouchEnabled && Settings.Default.DragDropItemsEnabled))
|
|
|
|
|
{
|
|
|
|
|
AllowDrop = true;
|
|
|
|
|
DragEnter += DragDropHelper.DragEnter;
|
|
|
|
|
Drop += DragDropHelper.DragDrop;
|
|
|
|
|
}
|
2020-06-08 00:28:59 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-19 06:42:46 +12:00
|
|
|
|
internal event Action<RowData>? StartLoadSubMenu;
|
|
|
|
|
|
2022-12-04 10:41:03 +13:00
|
|
|
|
internal event Action? MenuScrolled;
|
2020-07-07 09:37:55 +12:00
|
|
|
|
|
2022-12-04 10:41:03 +13:00
|
|
|
|
internal event Action<Menu, Key, ModifierKeys>? CmdKeyProcessed;
|
2020-07-07 09:37:55 +12:00
|
|
|
|
|
2022-12-04 10:41:03 +13:00
|
|
|
|
internal event Action? SearchTextChanging;
|
2020-07-07 09:37:55 +12:00
|
|
|
|
|
2023-04-28 09:24:25 +12:00
|
|
|
|
internal event Action<Menu, bool, bool>? SearchTextChanged;
|
2020-07-07 09:37:55 +12:00
|
|
|
|
|
2023-05-19 09:28:52 +12:00
|
|
|
|
internal event Action<RowData>? RowSelectionChanged;
|
2023-05-15 05:13:44 +12:00
|
|
|
|
|
2023-05-19 09:28:52 +12:00
|
|
|
|
internal event Action<RowData>? CellMouseEnter;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
|
2023-05-11 10:53:02 +12:00
|
|
|
|
internal event Action? CellMouseLeave;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
|
2023-05-19 09:28:52 +12:00
|
|
|
|
internal event Action<RowData>? CellMouseDown;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
|
2023-05-19 09:28:52 +12:00
|
|
|
|
internal event Action<RowData>? CellOpenOnClick;
|
2023-04-25 08:38:36 +12:00
|
|
|
|
|
2023-04-24 09:53:20 +12:00
|
|
|
|
internal event RoutedEventHandler FadeToTransparent
|
|
|
|
|
{
|
|
|
|
|
add { AddHandler(FadeToTransparentEvent, value); }
|
|
|
|
|
remove { RemoveHandler(FadeToTransparentEvent, value); }
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-05 10:03:57 +13:00
|
|
|
|
internal event RoutedEventHandler FadeIn
|
2022-12-04 13:24:30 +13:00
|
|
|
|
{
|
|
|
|
|
add { AddHandler(FadeInEvent, value); }
|
|
|
|
|
remove { RemoveHandler(FadeInEvent, value); }
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-05 10:03:57 +13:00
|
|
|
|
internal event RoutedEventHandler FadeOut
|
2022-12-04 13:24:30 +13:00
|
|
|
|
{
|
|
|
|
|
add { AddHandler(FadeOutEvent, value); }
|
|
|
|
|
remove { RemoveHandler(FadeOutEvent, value); }
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-21 05:19:21 +12:00
|
|
|
|
internal enum StartLocation
|
|
|
|
|
{
|
2023-04-24 08:36:15 +12:00
|
|
|
|
Point,
|
2020-09-21 05:19:21 +12:00
|
|
|
|
Predecessor,
|
|
|
|
|
BottomLeft,
|
|
|
|
|
BottomRight,
|
|
|
|
|
TopRight,
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-12 11:13:02 +12:00
|
|
|
|
internal Point Location => new (Left, Top); // TODO WPF Replace Forms wrapper
|
2022-10-23 11:02:31 +13:00
|
|
|
|
|
|
|
|
|
internal int Level { get; set; }
|
|
|
|
|
|
2023-04-16 07:23:28 +12:00
|
|
|
|
internal RowData? RowDataParent { get; set; }
|
2022-12-04 10:41:03 +13:00
|
|
|
|
|
2023-05-19 09:28:52 +12:00
|
|
|
|
internal RowData? SelectedItem
|
2023-05-11 10:14:05 +12:00
|
|
|
|
{
|
2023-05-19 09:28:52 +12:00
|
|
|
|
get => (RowData?)dgv.SelectedItem;
|
2023-05-11 10:14:05 +12:00
|
|
|
|
set => dgv.SelectedItem = value;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-19 08:16:39 +12:00
|
|
|
|
internal Menu MainMenu { get; private set; }
|
2023-05-08 10:14:23 +12:00
|
|
|
|
|
2023-05-04 09:18:03 +12:00
|
|
|
|
internal Menu? ParentMenu => RowDataParent?.Owner;
|
|
|
|
|
|
|
|
|
|
internal Menu? SubMenu
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2023-08-14 08:17:16 +12:00
|
|
|
|
foreach (RowData rowData in dgv.Items.SourceCollection)
|
2023-05-04 09:18:03 +12:00
|
|
|
|
{
|
2023-05-19 09:28:52 +12:00
|
|
|
|
if (rowData.SubMenu != null)
|
2023-05-04 09:18:03 +12:00
|
|
|
|
{
|
2023-05-19 09:28:52 +12:00
|
|
|
|
return rowData.SubMenu;
|
2023-05-04 09:18:03 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-23 07:04:34 +12:00
|
|
|
|
internal bool RelocateOnNextShow { get; set; } = true;
|
|
|
|
|
|
2023-05-03 08:05:08 +12:00
|
|
|
|
public override string ToString() => nameof(Menu) + " L" + Level.ToString() + ": " + Title;
|
|
|
|
|
|
2023-09-18 09:22:29 +12:00
|
|
|
|
internal void RiseItemExecuted(RowData rowData)
|
|
|
|
|
{
|
2023-09-20 08:09:54 +12:00
|
|
|
|
ListViewItem? lvi;
|
|
|
|
|
int i = 0;
|
|
|
|
|
while ((lvi = dgv.FindVisualChildOfType<ListViewItem>(i++)) != null)
|
2023-09-18 09:22:29 +12:00
|
|
|
|
{
|
|
|
|
|
if (lvi.Content == rowData)
|
|
|
|
|
{
|
|
|
|
|
Border? border_outer = lvi.FindVisualChildOfType<Border>();
|
|
|
|
|
Border? border_inner = border_outer?.FindVisualChildOfType<Border>();
|
|
|
|
|
border_inner?.BeginStoryboard((Storyboard)dgv.FindResource("OpenAnimationStoryboard"));
|
|
|
|
|
|
2023-09-20 08:09:54 +12:00
|
|
|
|
return;
|
2023-09-18 09:22:29 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void RiseItemOpened(RowData rowData) => CellOpenOnClick?.Invoke(rowData);
|
2023-05-19 08:48:18 +12:00
|
|
|
|
|
|
|
|
|
internal void RiseStartLoadSubMenu(RowData rowData) => StartLoadSubMenu?.Invoke(rowData);
|
|
|
|
|
|
2021-11-11 11:39:52 +13:00
|
|
|
|
internal void ResetSearchText()
|
|
|
|
|
{
|
|
|
|
|
textBoxSearch.Text = string.Empty;
|
2022-11-04 11:35:58 +13:00
|
|
|
|
if (dgv.Items.Count > 0)
|
2022-06-18 00:38:09 +12:00
|
|
|
|
{
|
2022-11-04 11:35:58 +13:00
|
|
|
|
dgv.ScrollIntoView(dgv.Items[0]);
|
2022-06-18 00:38:09 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-28 09:24:25 +12:00
|
|
|
|
internal void OnWatcherUpdate()
|
2022-06-18 00:38:09 +12:00
|
|
|
|
{
|
2023-04-28 09:24:25 +12:00
|
|
|
|
TextBoxSearch_TextChanged(true);
|
2022-11-04 11:35:58 +13:00
|
|
|
|
if (dgv.Items.Count > 0)
|
2022-06-18 00:38:09 +12:00
|
|
|
|
{
|
2022-11-04 11:35:58 +13:00
|
|
|
|
dgv.ScrollIntoView(dgv.Items[0]);
|
2022-06-18 00:38:09 +12:00
|
|
|
|
}
|
2021-11-11 11:39:52 +13:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-21 06:14:28 +12:00
|
|
|
|
internal void FocusTextBox(bool selectAll = false)
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2023-08-21 06:14:28 +12:00
|
|
|
|
if (selectAll)
|
|
|
|
|
{
|
|
|
|
|
textBoxSearch.SelectAll();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
textBoxSearch.CaretIndex = textBoxSearch.Text.Length;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-04 21:34:29 +12:00
|
|
|
|
textBoxSearch.Focus();
|
2020-06-08 00:28:59 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-08 10:14:23 +12:00
|
|
|
|
// TODO: Check if we can just use original IsMouseOver instead? (Check if it requires Mouse.Capture(this))
|
|
|
|
|
internal new bool IsMouseOver()
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2022-10-23 11:02:31 +13:00
|
|
|
|
Point mousePos = NativeMethods.Screen.CursorPosition;
|
2023-05-08 10:14:23 +12:00
|
|
|
|
bool isMouseOver = Visibility == Visibility.Visible &&
|
2022-10-23 11:02:31 +13:00
|
|
|
|
mousePos.X >= 0 && mousePos.X < Width &&
|
|
|
|
|
mousePos.Y >= 0 && mousePos.Y < Height;
|
2023-05-08 10:14:23 +12:00
|
|
|
|
return isMouseOver;
|
2020-06-08 00:28:59 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-05 10:08:39 +12:00
|
|
|
|
internal ListView GetDataGridView() => dgv; // TODO WPF Replace Forms wrapper
|
2020-06-08 00:28:59 +12:00
|
|
|
|
|
2023-04-30 05:51:44 +12:00
|
|
|
|
// Not used as refreshing should be done automatically due to databinding
|
|
|
|
|
// TODO: As long as WPF transition from Forms is incomplete, keep it for testing.
|
2023-04-16 22:42:42 +12:00
|
|
|
|
internal void RefreshDataGridView()
|
|
|
|
|
{
|
|
|
|
|
((CollectionView)CollectionViewSource.GetDefaultView(dgv.ItemsSource)).Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-09 10:19:29 +12:00
|
|
|
|
// TODO: Check if it is implicitly already running due to SelectionChanged event
|
2023-05-19 06:42:46 +12:00
|
|
|
|
// In case it is needed, run it within HideWithFade/ShowWithFade?
|
2023-05-09 10:19:29 +12:00
|
|
|
|
internal void RefreshSelection() => ListView_SelectionChanged(GetDataGridView(), null);
|
|
|
|
|
|
2023-05-12 11:13:02 +12:00
|
|
|
|
internal bool TrySelectAt(int index, int indexAlternative = -1)
|
|
|
|
|
{
|
2023-05-19 09:28:52 +12:00
|
|
|
|
RowData itemData;
|
2023-05-12 11:13:02 +12:00
|
|
|
|
if (index >= 0 && dgv.Items.Count > index)
|
|
|
|
|
{
|
2023-05-19 09:28:52 +12:00
|
|
|
|
itemData = (RowData)dgv.Items[index];
|
2023-05-12 11:13:02 +12:00
|
|
|
|
}
|
|
|
|
|
else if (indexAlternative >= 0 && dgv.Items.Count > indexAlternative)
|
|
|
|
|
{
|
2023-05-19 09:28:52 +12:00
|
|
|
|
itemData = (RowData)dgv.Items[indexAlternative];
|
2023-05-15 05:13:44 +12:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
2023-05-12 11:13:02 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-15 05:13:44 +12:00
|
|
|
|
dgv.SelectedItem = itemData;
|
|
|
|
|
dgv.ScrollIntoView(itemData);
|
|
|
|
|
|
2023-05-19 06:42:46 +12:00
|
|
|
|
RowSelectionChanged?.Invoke(itemData);
|
2023-05-15 05:13:44 +12:00
|
|
|
|
|
|
|
|
|
return true;
|
2023-05-12 11:13:02 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-04 06:18:10 +12:00
|
|
|
|
internal void AddItemsToMenu(List<RowData> data, MenuDataDirectoryState? state)
|
2023-04-17 01:45:47 +12:00
|
|
|
|
{
|
2023-05-19 09:28:52 +12:00
|
|
|
|
for (int index = 0; index < data.Count; index++)
|
2023-04-17 01:45:47 +12:00
|
|
|
|
{
|
2023-05-19 09:28:52 +12:00
|
|
|
|
RowData rowData = data[index];
|
|
|
|
|
rowData.RowIndex = index;
|
2023-05-04 09:18:03 +12:00
|
|
|
|
rowData.Owner = this;
|
2023-05-19 09:28:52 +12:00
|
|
|
|
rowData.SortIndex = rowData.IsAdditionalItem && Settings.Default.ShowOnlyAsSearchResult ? 99 : 0;
|
2023-04-17 01:45:47 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-19 09:28:52 +12:00
|
|
|
|
dgv.ItemsSource = data;
|
2023-04-17 01:45:47 +12:00
|
|
|
|
|
2023-08-13 04:37:26 +12:00
|
|
|
|
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(dgv.ItemsSource);
|
|
|
|
|
view.Filter = (object item) => Filter_Default((RowData)item);
|
2023-04-28 09:24:25 +12:00
|
|
|
|
|
|
|
|
|
if (state != null)
|
|
|
|
|
{
|
|
|
|
|
SetSubMenuState(state.Value);
|
|
|
|
|
}
|
2023-04-17 01:45:47 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-08 10:14:23 +12:00
|
|
|
|
internal void ActivateWithFade(bool recursive)
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2023-05-08 10:14:23 +12:00
|
|
|
|
if (recursive)
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2023-05-08 10:14:23 +12:00
|
|
|
|
SubMenu?.ActivateWithFade(true);
|
2020-06-08 00:28:59 +12:00
|
|
|
|
}
|
2023-05-08 10:14:23 +12:00
|
|
|
|
|
|
|
|
|
if (Opacity != 1D)
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2023-05-08 10:14:23 +12:00
|
|
|
|
if (Settings.Default.UseFading)
|
|
|
|
|
{
|
|
|
|
|
RaiseEvent(new(routedEvent: FadeInEvent));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Opacity = 1D;
|
|
|
|
|
}
|
2020-06-08 00:28:59 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-08 10:14:23 +12:00
|
|
|
|
internal void ShowWithFade(bool transparency, bool recursive)
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2023-05-08 10:14:23 +12:00
|
|
|
|
if (recursive)
|
|
|
|
|
{
|
|
|
|
|
SubMenu?.ShowWithFade(transparency, true);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-24 09:53:20 +12:00
|
|
|
|
if (Level > 0)
|
2022-12-04 13:24:30 +13:00
|
|
|
|
{
|
|
|
|
|
ShowActivated = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Opacity = 0D;
|
|
|
|
|
Show();
|
|
|
|
|
|
2023-05-16 08:34:17 +12:00
|
|
|
|
if (!Settings.Default.UseFading)
|
2022-12-04 13:24:30 +13:00
|
|
|
|
{
|
2023-05-16 08:34:17 +12:00
|
|
|
|
Opacity = transparency ? 0.80D : 1D;
|
|
|
|
|
}
|
|
|
|
|
else if (transparency)
|
|
|
|
|
{
|
|
|
|
|
RaiseEvent(new(routedEvent: FadeToTransparentEvent));
|
2022-12-04 13:24:30 +13:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-05-16 08:34:17 +12:00
|
|
|
|
RaiseEvent(new(routedEvent: FadeInEvent));
|
2022-12-04 13:24:30 +13:00
|
|
|
|
}
|
2020-06-08 00:28:59 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-17 05:32:48 +12:00
|
|
|
|
internal void HideAllMenus()
|
|
|
|
|
{
|
|
|
|
|
// Find main menu and close/hide all
|
|
|
|
|
Menu menu = this;
|
|
|
|
|
while (menu.ParentMenu != null)
|
|
|
|
|
{
|
|
|
|
|
menu = menu.ParentMenu;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
menu.HideWithFade(true);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-08 10:14:23 +12:00
|
|
|
|
internal void HideWithFade(bool recursive)
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2023-05-08 10:14:23 +12:00
|
|
|
|
if (recursive)
|
|
|
|
|
{
|
|
|
|
|
SubMenu?.HideWithFade(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (RowDataParent != null)
|
|
|
|
|
{
|
|
|
|
|
RowDataParent.SubMenu = null;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 13:24:30 +13:00
|
|
|
|
if (Settings.Default.UseFading)
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2022-12-04 13:24:30 +13:00
|
|
|
|
RaiseEvent(new(routedEvent: FadeOutEvent));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FadeOut_Completed(this, new());
|
2020-06-08 00:28:59 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-21 06:29:53 +12:00
|
|
|
|
internal void StartFadeIn()
|
|
|
|
|
{
|
|
|
|
|
if (Settings.Default.UseFading)
|
|
|
|
|
{
|
|
|
|
|
RaiseEvent(new(routedEvent: FadeInEvent));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-21 07:47:46 +12:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Update the position and size of the menu.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="bounds">Screen coordinates where the menu is allowed to be drawn in.</param>
|
|
|
|
|
/// <param name="menuPredecessor">Predecessor menu (when available).</param>
|
|
|
|
|
/// <param name="startLocation">Defines where the first menu is drawn (when no predecessor is set).</param>
|
2023-04-17 06:17:24 +12:00
|
|
|
|
/// <param name="useCustomLocation">Use CustomLocation as start position.</param>
|
2020-07-07 07:15:45 +12:00
|
|
|
|
internal void AdjustSizeAndLocation(
|
2022-11-14 07:58:54 +13:00
|
|
|
|
Rect bounds,
|
2022-12-05 13:27:57 +13:00
|
|
|
|
Menu? menuPredecessor,
|
2021-12-28 00:22:52 +13:00
|
|
|
|
StartLocation startLocation,
|
2023-04-17 06:17:24 +12:00
|
|
|
|
bool useCustomLocation)
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2023-04-24 09:53:20 +12:00
|
|
|
|
Point originLocation = new(0D, 0D);
|
2023-04-23 07:04:34 +12:00
|
|
|
|
|
2021-05-29 09:23:05 +12:00
|
|
|
|
// Update the height and width
|
|
|
|
|
AdjustDataGridViewHeight(menuPredecessor, bounds.Height);
|
|
|
|
|
AdjustDataGridViewWidth();
|
|
|
|
|
|
2023-04-17 06:17:24 +12:00
|
|
|
|
if (Level > 0)
|
2020-09-21 05:19:21 +12:00
|
|
|
|
{
|
2023-04-23 07:04:34 +12:00
|
|
|
|
if (menuPredecessor == null)
|
|
|
|
|
{
|
|
|
|
|
// should never happen
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-17 06:17:24 +12:00
|
|
|
|
// Sub Menu location depends on the location of its predecessor
|
2020-09-21 05:19:21 +12:00
|
|
|
|
startLocation = StartLocation.Predecessor;
|
2023-04-23 07:04:34 +12:00
|
|
|
|
originLocation = menuPredecessor.Location;
|
2020-09-21 05:19:21 +12:00
|
|
|
|
}
|
2023-04-17 06:17:24 +12:00
|
|
|
|
else if (useCustomLocation)
|
2021-11-25 07:01:59 +13:00
|
|
|
|
{
|
2023-04-23 07:04:34 +12:00
|
|
|
|
if (!RelocateOnNextShow)
|
2021-11-25 07:01:59 +13:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-23 07:04:34 +12:00
|
|
|
|
RelocateOnNextShow = false;
|
|
|
|
|
startLocation = StartLocation.Point;
|
2023-04-24 08:36:15 +12:00
|
|
|
|
originLocation = new(Settings.Default.CustomLocationX, Settings.Default.CustomLocationY);
|
2021-11-25 07:01:59 +13:00
|
|
|
|
}
|
2022-12-05 13:27:57 +13:00
|
|
|
|
else if (Settings.Default.AppearAtMouseLocation)
|
2021-04-29 08:58:33 +12:00
|
|
|
|
{
|
2023-04-23 07:04:34 +12:00
|
|
|
|
if (!RelocateOnNextShow)
|
2021-06-27 22:24:05 +12:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-23 07:04:34 +12:00
|
|
|
|
RelocateOnNextShow = false;
|
|
|
|
|
startLocation = StartLocation.Point;
|
2023-04-24 08:36:15 +12:00
|
|
|
|
originLocation = NativeMethods.Screen.CursorPosition;
|
2021-04-29 08:58:33 +12:00
|
|
|
|
}
|
2020-09-21 05:19:21 +12:00
|
|
|
|
|
2022-12-01 12:16:30 +13:00
|
|
|
|
if (IsLoaded)
|
|
|
|
|
{
|
2023-08-21 08:38:28 +12:00
|
|
|
|
AdjustWindowPositionInternal(originLocation);
|
2022-12-01 12:16:30 +13:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Layout cannot be calculated during loading, postpone this event
|
2023-08-21 08:38:28 +12:00
|
|
|
|
Loaded += (_, _) => AdjustWindowPositionInternal(originLocation);
|
2022-12-01 12:16:30 +13:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-21 08:38:28 +12:00
|
|
|
|
void AdjustWindowPositionInternal(in Point originLocation)
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2023-04-24 08:36:15 +12:00
|
|
|
|
double scaling = Math.Round(Scaling.Factor, 0, MidpointRounding.AwayFromZero);
|
2023-04-24 09:53:20 +12:00
|
|
|
|
double overlappingOffset = 0D;
|
2023-04-23 07:04:34 +12:00
|
|
|
|
|
2023-04-17 06:17:24 +12:00
|
|
|
|
// Make sure we have latest values of own window size
|
|
|
|
|
UpdateLayout();
|
|
|
|
|
|
2023-04-23 07:04:34 +12:00
|
|
|
|
// Prepare parameters
|
2023-04-24 08:36:15 +12:00
|
|
|
|
if (startLocation == StartLocation.Predecessor)
|
2023-04-23 07:04:34 +12:00
|
|
|
|
{
|
2023-04-24 08:36:15 +12:00
|
|
|
|
if (menuPredecessor == null)
|
|
|
|
|
{
|
|
|
|
|
// should never happen
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// When (later in calculation) a list item is not found,
|
|
|
|
|
// its values might be invalidated due to resizing or moving.
|
|
|
|
|
// After updating the layout the location should be available again.
|
|
|
|
|
menuPredecessor.UpdateLayout();
|
|
|
|
|
|
2023-04-23 07:04:34 +12:00
|
|
|
|
directionToRight = menuPredecessor.directionToRight; // try keeping same direction from predecessor
|
2023-04-24 08:36:15 +12:00
|
|
|
|
|
|
|
|
|
if (!Settings.Default.AppearNextToPreviousMenu &&
|
2023-08-21 02:18:40 +12:00
|
|
|
|
menuPredecessor.windowFrame.ActualWidth > Settings.Default.OverlappingOffsetPixels)
|
2023-04-24 08:36:15 +12:00
|
|
|
|
{
|
|
|
|
|
if (directionToRight)
|
|
|
|
|
{
|
2023-08-21 02:18:40 +12:00
|
|
|
|
overlappingOffset = Settings.Default.OverlappingOffsetPixels - menuPredecessor.windowFrame.ActualWidth;
|
2023-04-24 08:36:15 +12:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-08-21 02:18:40 +12:00
|
|
|
|
overlappingOffset = menuPredecessor.windowFrame.ActualWidth - Settings.Default.OverlappingOffsetPixels;
|
2023-04-24 08:36:15 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-23 07:04:34 +12:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
directionToRight = true; // use right as default direction
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 11:02:31 +13:00
|
|
|
|
// Calculate X position
|
|
|
|
|
double x;
|
|
|
|
|
switch (startLocation)
|
|
|
|
|
{
|
2023-04-23 07:04:34 +12:00
|
|
|
|
case StartLocation.Point:
|
2023-04-24 08:36:15 +12:00
|
|
|
|
x = originLocation.X;
|
|
|
|
|
break;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
case StartLocation.Predecessor:
|
2023-04-24 08:36:15 +12:00
|
|
|
|
if (menuPredecessor == null)
|
|
|
|
|
{
|
|
|
|
|
// should never happen
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-04-23 07:04:34 +12:00
|
|
|
|
|
2022-10-23 11:02:31 +13:00
|
|
|
|
if (directionToRight)
|
2020-09-21 06:45:12 +12:00
|
|
|
|
{
|
2023-08-21 02:18:40 +12:00
|
|
|
|
x = originLocation.X + menuPredecessor.windowFrame.ActualWidth - scaling;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
|
2023-04-23 07:04:34 +12:00
|
|
|
|
// Change direction when out of bounds (predecessor only)
|
|
|
|
|
if (startLocation == StartLocation.Predecessor &&
|
2023-08-21 02:18:40 +12:00
|
|
|
|
bounds.X + bounds.Width <= x + windowFrame.ActualWidth - scaling)
|
2022-02-23 04:52:02 +13:00
|
|
|
|
{
|
2023-08-21 02:18:40 +12:00
|
|
|
|
x = originLocation.X - windowFrame.ActualWidth + scaling;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
if (x < bounds.X &&
|
2023-08-21 02:18:40 +12:00
|
|
|
|
originLocation.X + menuPredecessor.windowFrame.ActualWidth < bounds.X + bounds.Width &&
|
|
|
|
|
bounds.X + (bounds.Width / 2) > originLocation.X + (windowFrame.ActualWidth / 2))
|
2022-02-23 04:52:02 +13:00
|
|
|
|
{
|
2023-08-21 02:18:40 +12:00
|
|
|
|
x = bounds.X + bounds.Width - windowFrame.ActualWidth + scaling;
|
2022-02-23 04:52:02 +13:00
|
|
|
|
}
|
2022-10-23 11:02:31 +13:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (x < bounds.X)
|
|
|
|
|
{
|
|
|
|
|
x = bounds.X;
|
|
|
|
|
}
|
2022-02-23 04:52:02 +13:00
|
|
|
|
|
2022-10-23 11:02:31 +13:00
|
|
|
|
directionToRight = !directionToRight;
|
|
|
|
|
}
|
2022-02-23 04:52:02 +13:00
|
|
|
|
}
|
2020-09-21 06:45:12 +12:00
|
|
|
|
}
|
2022-10-23 11:02:31 +13:00
|
|
|
|
else
|
2020-09-21 06:45:12 +12:00
|
|
|
|
{
|
2023-08-21 02:18:40 +12:00
|
|
|
|
x = originLocation.X - windowFrame.ActualWidth + scaling;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
|
2023-04-23 07:04:34 +12:00
|
|
|
|
// Change direction when out of bounds (predecessor only)
|
|
|
|
|
if (startLocation == StartLocation.Predecessor &&
|
2022-10-23 11:02:31 +13:00
|
|
|
|
x < bounds.X)
|
2022-02-23 04:52:02 +13:00
|
|
|
|
{
|
2023-08-21 02:18:40 +12:00
|
|
|
|
x = originLocation.X + menuPredecessor.windowFrame.ActualWidth - scaling;
|
|
|
|
|
if (x + windowFrame.ActualWidth > bounds.X + bounds.Width &&
|
2023-04-23 07:04:34 +12:00
|
|
|
|
originLocation.X > bounds.X &&
|
2023-08-21 02:18:40 +12:00
|
|
|
|
bounds.X + (bounds.Width / 2) < originLocation.X + (windowFrame.ActualWidth / 2))
|
2022-02-23 04:52:02 +13:00
|
|
|
|
{
|
2022-10-23 11:02:31 +13:00
|
|
|
|
x = bounds.X;
|
2022-02-23 04:52:02 +13:00
|
|
|
|
}
|
2022-10-23 11:02:31 +13:00
|
|
|
|
else
|
|
|
|
|
{
|
2023-08-21 02:18:40 +12:00
|
|
|
|
if (x + windowFrame.ActualWidth > bounds.X + bounds.Width)
|
2022-10-23 11:02:31 +13:00
|
|
|
|
{
|
2023-08-21 02:18:40 +12:00
|
|
|
|
x = bounds.X + bounds.Width - windowFrame.ActualWidth + scaling;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
}
|
2022-02-23 04:52:02 +13:00
|
|
|
|
|
2022-10-23 11:02:31 +13:00
|
|
|
|
directionToRight = !directionToRight;
|
|
|
|
|
}
|
2022-02-23 04:52:02 +13:00
|
|
|
|
}
|
2020-09-21 06:45:12 +12:00
|
|
|
|
}
|
2020-06-08 00:28:59 +12:00
|
|
|
|
|
2022-10-23 11:02:31 +13:00
|
|
|
|
break;
|
|
|
|
|
case StartLocation.BottomLeft:
|
|
|
|
|
x = bounds.X;
|
|
|
|
|
directionToRight = true;
|
|
|
|
|
break;
|
|
|
|
|
case StartLocation.TopRight:
|
|
|
|
|
case StartLocation.BottomRight:
|
|
|
|
|
default:
|
2023-08-21 02:18:40 +12:00
|
|
|
|
x = bounds.Width - windowFrame.ActualWidth;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
directionToRight = false;
|
|
|
|
|
break;
|
2022-01-16 02:44:56 +13:00
|
|
|
|
}
|
2022-10-23 11:02:31 +13:00
|
|
|
|
|
2023-08-21 02:18:40 +12:00
|
|
|
|
// Besides overlapping setting we need to subtract the left margin from x as it was not part of x calculation
|
|
|
|
|
x += overlappingOffset - windowFrame.Margin.Left;
|
2021-06-26 23:24:56 +12:00
|
|
|
|
|
2022-10-23 11:02:31 +13:00
|
|
|
|
// Calculate Y position
|
|
|
|
|
double y;
|
|
|
|
|
switch (startLocation)
|
|
|
|
|
{
|
2023-04-23 07:04:34 +12:00
|
|
|
|
case StartLocation.Point:
|
2023-04-24 08:36:15 +12:00
|
|
|
|
y = originLocation.Y;
|
|
|
|
|
if (Settings.Default.AppearAtMouseLocation)
|
|
|
|
|
{
|
|
|
|
|
y -= labelTitle.ActualHeight; // Mouse should point below title
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
case StartLocation.Predecessor:
|
2023-04-24 08:36:15 +12:00
|
|
|
|
if (menuPredecessor == null)
|
|
|
|
|
{
|
|
|
|
|
// should never happen
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-06-08 00:28:59 +12:00
|
|
|
|
|
2023-04-23 07:04:34 +12:00
|
|
|
|
y = originLocation.Y;
|
2023-04-24 08:36:15 +12:00
|
|
|
|
|
|
|
|
|
// Set position on same height as the selected row from predecessor
|
|
|
|
|
RowData? trigger = RowDataParent;
|
2023-08-14 09:59:40 +12:00
|
|
|
|
if (trigger != null)
|
2022-10-23 11:02:31 +13:00
|
|
|
|
{
|
2023-09-02 05:49:34 +12:00
|
|
|
|
double offset = menuPredecessor.GetDataGridViewChildRect(trigger).Top;
|
2022-12-03 07:34:24 +13:00
|
|
|
|
|
2022-12-03 14:14:15 +13:00
|
|
|
|
if (offset < 0)
|
|
|
|
|
{
|
|
|
|
|
// Do not allow to show window higher than previous window
|
|
|
|
|
offset = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-09-01 07:09:58 +12:00
|
|
|
|
ListView dgv = menuPredecessor.GetDataGridView();
|
2022-12-03 14:14:15 +13:00
|
|
|
|
double offsetList = menuPredecessor.GetRelativeChildPositionTo(dgv).Y;
|
|
|
|
|
offsetList += dgv.ActualHeight;
|
|
|
|
|
if (offsetList < offset)
|
|
|
|
|
{
|
|
|
|
|
// Do not allow to show window below last entry position of list
|
|
|
|
|
offset = offsetList;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-24 08:36:15 +12:00
|
|
|
|
y += offset;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
}
|
2021-11-14 07:44:32 +13:00
|
|
|
|
|
2022-12-03 14:14:15 +13:00
|
|
|
|
if (searchPanel.Visibility == Visibility.Collapsed)
|
2022-10-23 11:02:31 +13:00
|
|
|
|
{
|
2022-12-03 14:14:15 +13:00
|
|
|
|
y += menuPredecessor.searchPanel.ActualHeight;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case StartLocation.TopRight:
|
|
|
|
|
y = bounds.Y;
|
|
|
|
|
break;
|
|
|
|
|
case StartLocation.BottomLeft:
|
|
|
|
|
case StartLocation.BottomRight:
|
|
|
|
|
default:
|
2023-08-21 02:18:40 +12:00
|
|
|
|
y = bounds.Height - windowFrame.ActualHeight;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
break;
|
2021-11-19 09:12:03 +13:00
|
|
|
|
}
|
2021-12-11 08:35:00 +13:00
|
|
|
|
|
2023-04-24 08:36:15 +12:00
|
|
|
|
// Move vertically when out of bounds
|
2023-08-21 02:18:40 +12:00
|
|
|
|
// Besides that we need to subtract the top margin from y as it was not part of y calculation
|
|
|
|
|
if (bounds.Y + bounds.Height < y + windowFrame.ActualHeight)
|
2023-04-24 08:36:15 +12:00
|
|
|
|
{
|
2023-08-21 02:18:40 +12:00
|
|
|
|
y = bounds.Y + bounds.Height - windowFrame.ActualHeight - windowFrame.Margin.Top;
|
2023-04-24 08:36:15 +12:00
|
|
|
|
}
|
|
|
|
|
else if (y < bounds.Y)
|
|
|
|
|
{
|
2023-08-21 02:18:40 +12:00
|
|
|
|
y = bounds.Y - windowFrame.Margin.Top;
|
2023-04-24 08:36:15 +12:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 11:02:31 +13:00
|
|
|
|
// Update position
|
|
|
|
|
Left = x;
|
|
|
|
|
Top = y;
|
|
|
|
|
|
2022-12-05 13:27:57 +13:00
|
|
|
|
if (Settings.Default.RoundCorners)
|
2021-12-11 08:35:00 +13:00
|
|
|
|
{
|
2022-10-23 11:02:31 +13:00
|
|
|
|
windowFrame.CornerRadius = new CornerRadius(CornerRadius);
|
2021-12-11 08:35:00 +13:00
|
|
|
|
}
|
2022-11-30 10:48:45 +13:00
|
|
|
|
|
2022-12-01 12:16:30 +13:00
|
|
|
|
UpdateLayout();
|
|
|
|
|
}
|
2022-08-02 10:49:56 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-02 05:49:34 +12:00
|
|
|
|
internal Rect GetDataGridViewChildRect(RowData rowData)
|
2023-09-01 07:09:58 +12:00
|
|
|
|
{
|
|
|
|
|
// When scrolled, we have to reduce the index number as we calculate based on visual tree
|
|
|
|
|
int rowIndex = rowData.RowIndex;
|
|
|
|
|
int startIndex = 0;
|
2023-09-02 05:49:34 +12:00
|
|
|
|
double offsetY = 0D;
|
2023-09-01 07:09:58 +12:00
|
|
|
|
if (VisualTreeHelper.GetChild(dgv, 0) is Decorator { Child: ScrollViewer scrollViewer })
|
|
|
|
|
{
|
|
|
|
|
startIndex = (int)scrollViewer.VerticalOffset;
|
|
|
|
|
if (rowIndex < startIndex)
|
|
|
|
|
{
|
|
|
|
|
// calculate position above starting point
|
|
|
|
|
for (int i = rowIndex; i < startIndex; i++)
|
|
|
|
|
{
|
|
|
|
|
ListViewItem? item = dgv.FindVisualChildOfType<ListViewItem>(i);
|
|
|
|
|
if (item != null)
|
|
|
|
|
{
|
2023-09-02 05:49:34 +12:00
|
|
|
|
offsetY -= item.ActualHeight;
|
2023-09-01 07:09:58 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (startIndex < rowIndex)
|
|
|
|
|
{
|
|
|
|
|
// calculate position below starting point
|
|
|
|
|
// outer loop check for max RowIndex, independend of currently active filter
|
|
|
|
|
// inner loop check for filtered and shown items
|
|
|
|
|
for (int i = startIndex; i < rowIndex; i++)
|
|
|
|
|
{
|
|
|
|
|
ListViewItem? item = dgv.FindVisualChildOfType<ListViewItem>(i);
|
|
|
|
|
if (item != null)
|
|
|
|
|
{
|
|
|
|
|
if (((RowData)item.Content).RowIndex >= rowIndex)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-02 05:49:34 +12:00
|
|
|
|
offsetY += item.ActualHeight;
|
2023-09-01 07:09:58 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-02 05:49:34 +12:00
|
|
|
|
// All childs are using same width and height, so we simply fill in values from parent instead of individual child
|
|
|
|
|
return new(0D, offsetY, dgv.ActualWidth, (double)Resources["RowHeight"]);
|
2023-09-01 07:09:58 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-17 09:07:32 +12:00
|
|
|
|
private static bool Filter_Default(RowData itemData)
|
|
|
|
|
{
|
|
|
|
|
if (Settings.Default.ShowOnlyAsSearchResult && itemData.IsAdditionalItem)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool Filter_ByUserPattern(RowData itemData, string userPattern)
|
|
|
|
|
{
|
|
|
|
|
// Instead implementing in-string wildcards, simply split into multiple search pattersy
|
|
|
|
|
// Look for each space separated string if it is part of an entry's text (case insensitive)
|
|
|
|
|
foreach (string pattern in userPattern.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries))
|
|
|
|
|
{
|
|
|
|
|
if (!itemData.ColumnText.ToLower().Contains(pattern))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-23 08:35:56 +12:00
|
|
|
|
private void SetSubMenuState(MenuDataDirectoryState state)
|
|
|
|
|
{
|
|
|
|
|
if (Config.ShowFunctionKeyOpenFolder)
|
|
|
|
|
{
|
|
|
|
|
buttonOpenFolder.Visibility = Visibility.Visible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pictureBoxLoading.Visibility = Visibility.Collapsed;
|
|
|
|
|
|
|
|
|
|
switch (state)
|
|
|
|
|
{
|
|
|
|
|
case MenuDataDirectoryState.Valid:
|
|
|
|
|
if (Config.ShowCountOfElementsBelow)
|
|
|
|
|
{
|
|
|
|
|
((INotifyCollectionChanged)dgv.Items).CollectionChanged += ListView_CollectionChanged;
|
|
|
|
|
ListView_CollectionChanged(this, new(NotifyCollectionChangedAction.Reset));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
labelStatus.Visibility = Visibility.Collapsed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case MenuDataDirectoryState.Empty:
|
|
|
|
|
searchPanel.Visibility = Visibility.Collapsed;
|
|
|
|
|
labelStatus.Content = Translator.GetText("Directory empty");
|
|
|
|
|
break;
|
|
|
|
|
case MenuDataDirectoryState.NoAccess:
|
|
|
|
|
searchPanel.Visibility = Visibility.Collapsed;
|
|
|
|
|
labelStatus.Content = Translator.GetText("Directory inaccessible");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-16 08:34:17 +12:00
|
|
|
|
private void FadeOut_Completed(object sender, EventArgs e) => Hide();
|
2022-12-04 13:24:30 +13:00
|
|
|
|
|
2022-11-29 08:27:52 +13:00
|
|
|
|
private void HandlePreviewKeyDown(object sender, KeyEventArgs e)
|
2020-07-08 03:05:19 +12:00
|
|
|
|
{
|
2022-12-04 13:24:30 +13:00
|
|
|
|
searchPanel.Visibility = Visibility.Visible;
|
2022-12-03 14:14:15 +13:00
|
|
|
|
|
2022-11-29 08:27:52 +13:00
|
|
|
|
ModifierKeys modifiers = Keyboard.Modifiers;
|
|
|
|
|
switch (e.Key)
|
2020-07-08 03:05:19 +12:00
|
|
|
|
{
|
2022-11-29 08:27:52 +13:00
|
|
|
|
case Key.F4:
|
|
|
|
|
if (modifiers != ModifierKeys.Alt)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case Key.F:
|
|
|
|
|
if (modifiers != ModifierKeys.Control)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case Key.Tab:
|
|
|
|
|
if ((modifiers != ModifierKeys.Shift) && (modifiers != ModifierKeys.None))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
case Key.Enter:
|
|
|
|
|
case Key.Home:
|
|
|
|
|
case Key.End:
|
|
|
|
|
case Key.Up:
|
|
|
|
|
case Key.Down:
|
|
|
|
|
case Key.Left:
|
|
|
|
|
case Key.Right:
|
|
|
|
|
case Key.Escape:
|
|
|
|
|
case Key.Apps:
|
2022-11-29 08:27:52 +13:00
|
|
|
|
if (modifiers != ModifierKeys.None)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-08 03:05:19 +12:00
|
|
|
|
break;
|
2022-11-29 08:27:52 +13:00
|
|
|
|
default:
|
|
|
|
|
return;
|
2020-07-08 03:05:19 +12:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-29 08:27:52 +13:00
|
|
|
|
CmdKeyProcessed?.Invoke(this, e.Key, modifiers);
|
|
|
|
|
e.Handled = true;
|
2020-07-08 03:05:19 +12:00
|
|
|
|
}
|
2022-11-29 08:27:52 +13:00
|
|
|
|
|
2022-12-05 13:27:57 +13:00
|
|
|
|
private void AdjustDataGridViewHeight(Menu? menuPredecessor, double screenHeightMax)
|
2020-09-21 07:47:46 +12:00
|
|
|
|
{
|
2022-12-05 13:27:57 +13:00
|
|
|
|
double factor = Settings.Default.RowHeighteInPercentage / 100f;
|
2020-09-21 07:47:46 +12:00
|
|
|
|
if (NativeMethods.IsTouchEnabled())
|
|
|
|
|
{
|
2022-12-05 13:27:57 +13:00
|
|
|
|
factor = Settings.Default.RowHeighteInPercentageTouch / 100f;
|
2020-09-21 07:47:46 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (menuPredecessor == null)
|
|
|
|
|
{
|
2022-10-23 11:02:31 +13:00
|
|
|
|
if (dgv.Tag == null && dgv.Items.Count > 0)
|
2020-09-21 07:47:46 +12:00
|
|
|
|
{
|
2022-07-28 07:35:09 +12:00
|
|
|
|
// dgv.AutoResizeRows(); slightly incorrect depending on dpi
|
|
|
|
|
// 100% = 20 instead 21
|
|
|
|
|
// 125% = 23 instead 27, 150% = 28 instead 32
|
|
|
|
|
// 175% = 33 instead 37, 200% = 35 instead 42
|
|
|
|
|
// #418 use 21 as default and scale it manually
|
2023-08-13 05:53:14 +12:00
|
|
|
|
double rowHeightDefault = 21.24d * Scaling.FactorByDpi;
|
2023-08-17 08:45:43 +12:00
|
|
|
|
Resources["RowHeight"] = Math.Round(rowHeightDefault * factor * Scaling.Factor);
|
2020-09-21 07:47:46 +12:00
|
|
|
|
dgv.Tag = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Take over the height from predecessor menu
|
2022-11-10 12:18:21 +13:00
|
|
|
|
Resources["RowHeight"] = menuPredecessor.Resources["RowHeight"];
|
2020-09-21 07:47:46 +12:00
|
|
|
|
dgv.Tag = true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 11:02:31 +13:00
|
|
|
|
double heightMaxByOptions = Scaling.Factor * Scaling.FactorByDpi *
|
2022-12-05 13:27:57 +13:00
|
|
|
|
450f * (Settings.Default.HeightMaxInPercent / 100f);
|
2023-08-21 02:18:40 +12:00
|
|
|
|
|
|
|
|
|
// Margin of the windowFrame is allowed to exceed the boundaries, so we just add them afterwards
|
|
|
|
|
MaxHeight = Math.Min(screenHeightMax, heightMaxByOptions)
|
|
|
|
|
+ windowFrame.Margin.Top + windowFrame.Margin.Bottom;
|
2020-09-21 07:47:46 +12:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-08 00:28:59 +12:00
|
|
|
|
private void AdjustDataGridViewWidth()
|
|
|
|
|
{
|
2022-06-18 00:38:09 +12:00
|
|
|
|
if (!string.IsNullOrEmpty(textBoxSearch.Text))
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2022-06-18 00:38:09 +12:00
|
|
|
|
return;
|
2020-06-08 00:28:59 +12:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-05 13:27:57 +13:00
|
|
|
|
double factorIconSizeInPercent = Settings.Default.IconSizeInPercent / 100f;
|
2022-12-04 13:24:30 +13:00
|
|
|
|
|
2023-08-13 05:53:14 +12:00
|
|
|
|
// IcoWidth 100% = 21px, 175% is 33
|
|
|
|
|
double icoWidth = 16 * Scaling.FactorByDpi;
|
2023-08-16 08:21:54 +12:00
|
|
|
|
Resources["ColumnIconWidth"] = Math.Ceiling(icoWidth * factorIconSizeInPercent * Scaling.Factor);
|
2022-06-18 00:38:09 +12:00
|
|
|
|
|
2023-08-21 02:18:40 +12:00
|
|
|
|
// Margin of the windowFrame is allowed to exceed the boundaries, so we just add them afterwards
|
2023-08-22 06:05:31 +12:00
|
|
|
|
Resources["ColumnTextMaxWidth"] = Math.Ceiling(
|
|
|
|
|
((double)Scaling.Factor * Scaling.FactorByDpi * 400D * (Settings.Default.WidthMaxInPercent / 100D))
|
2023-08-21 02:18:40 +12:00
|
|
|
|
+ windowFrame.Margin.Left + windowFrame.Margin.Right);
|
2020-06-08 00:28:59 +12:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-01 12:16:30 +13:00
|
|
|
|
private void HandleScrollChanged(object sender, ScrollChangedEventArgs e)
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2022-12-01 12:16:30 +13:00
|
|
|
|
if (IsLoaded)
|
|
|
|
|
{
|
2022-12-03 14:14:15 +13:00
|
|
|
|
MenuScrolled?.Invoke();
|
2022-12-01 12:16:30 +13:00
|
|
|
|
}
|
2020-06-08 00:28:59 +12:00
|
|
|
|
}
|
2022-12-01 12:16:30 +13:00
|
|
|
|
|
2023-04-28 09:24:25 +12:00
|
|
|
|
private void TextBoxSearch_TextChanged(bool causedByWatcherUpdate)
|
2020-06-08 00:28:59 +12:00
|
|
|
|
{
|
2020-06-29 06:56:03 +12:00
|
|
|
|
SearchTextChanging?.Invoke();
|
2020-06-08 00:28:59 +12:00
|
|
|
|
|
2022-12-04 07:30:40 +13:00
|
|
|
|
string? userPattern = textBoxSearch.Text?.Replace("%", " ").Replace("*", " ").ToLower();
|
2022-01-31 04:52:42 +13:00
|
|
|
|
|
2022-11-04 11:35:58 +13:00
|
|
|
|
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(dgv.ItemsSource);
|
2022-12-04 07:30:40 +13:00
|
|
|
|
if (string.IsNullOrEmpty(userPattern))
|
2022-11-04 11:35:58 +13:00
|
|
|
|
{
|
2023-05-06 07:07:23 +12:00
|
|
|
|
SizeToContent = SizeToContent.WidthAndHeight;
|
2023-08-13 04:37:26 +12:00
|
|
|
|
view.Filter = (object item) => Filter_Default((RowData)item);
|
2022-11-04 11:35:58 +13:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-08-13 04:54:17 +12:00
|
|
|
|
SizeToContent = SizeToContent.Manual;
|
2023-08-13 04:37:26 +12:00
|
|
|
|
view.Filter = (object item) => Filter_ByUserPattern((RowData)item, userPattern);
|
2020-06-08 00:28:59 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-28 09:24:25 +12:00
|
|
|
|
SearchTextChanged?.Invoke(this, string.IsNullOrEmpty(userPattern), causedByWatcherUpdate);
|
2020-06-08 00:28:59 +12:00
|
|
|
|
}
|
2021-06-26 23:24:56 +12:00
|
|
|
|
|
2022-10-23 11:02:31 +13:00
|
|
|
|
private void PictureBoxOpenFolder_Click(object sender, RoutedEventArgs e)
|
2021-06-28 00:44:12 +12:00
|
|
|
|
{
|
2023-04-16 07:23:28 +12:00
|
|
|
|
Menus.OpenFolder(folderPath);
|
2021-06-28 00:44:12 +12:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 11:02:31 +13:00
|
|
|
|
private void PictureBoxMenuAlwaysOpen_Click(object sender, RoutedEventArgs e)
|
2021-10-04 07:24:22 +13:00
|
|
|
|
{
|
2022-10-23 11:02:31 +13:00
|
|
|
|
if (Config.AlwaysOpenByPin = !Config.AlwaysOpenByPin)
|
|
|
|
|
{
|
|
|
|
|
pictureBoxMenuAlwaysOpen.Source = (DrawingImage)Resources["ic_fluent_pin_48_filledDrawingImage"];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pictureBoxMenuAlwaysOpen.Source = (DrawingImage)Resources["ic_fluent_pin_48_regularDrawingImage"];
|
|
|
|
|
}
|
2021-10-04 07:24:22 +13:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 11:02:31 +13:00
|
|
|
|
private void PictureBoxSettings_MouseClick(object sender, RoutedEventArgs e)
|
2021-11-22 05:24:01 +13:00
|
|
|
|
{
|
2022-10-23 11:02:31 +13:00
|
|
|
|
SettingsWindow.ShowSingleInstance();
|
2021-11-22 05:24:01 +13:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 11:02:31 +13:00
|
|
|
|
private void PictureBoxRestart_MouseClick(object sender, RoutedEventArgs e)
|
2021-06-26 23:24:56 +12:00
|
|
|
|
{
|
2022-10-23 11:02:31 +13:00
|
|
|
|
AppRestart.ByMenuButton();
|
2021-06-26 23:24:56 +12:00
|
|
|
|
}
|
2021-09-24 08:53:46 +12:00
|
|
|
|
|
2023-05-17 05:57:02 +12:00
|
|
|
|
private void MainMenu_MoveStart(object sender, MouseButtonEventArgs e)
|
2021-11-25 07:01:59 +13:00
|
|
|
|
{
|
2023-05-17 05:57:02 +12:00
|
|
|
|
// Hide all sub menus to clear the view for repositioning of the main menu
|
|
|
|
|
if (SubMenu != null)
|
2021-12-10 08:00:33 +13:00
|
|
|
|
{
|
2023-05-17 05:57:02 +12:00
|
|
|
|
SubMenu?.HideWithFade(true);
|
|
|
|
|
RefreshSelection();
|
2021-12-10 08:00:33 +13:00
|
|
|
|
}
|
2023-05-17 05:57:02 +12:00
|
|
|
|
|
|
|
|
|
lastLocation = NativeMethods.Screen.CursorPosition;
|
|
|
|
|
MouseMove += MainMenu_MoveRelocate;
|
|
|
|
|
MouseUp += MainMenu_MoveEnd;
|
|
|
|
|
Deactivated += MainMenu_MoveEnd;
|
|
|
|
|
Mouse.Capture(this);
|
2021-11-25 07:01:59 +13:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-17 05:57:02 +12:00
|
|
|
|
private void MainMenu_MoveRelocate(object sender, MouseEventArgs e)
|
2021-11-25 07:01:59 +13:00
|
|
|
|
{
|
2023-05-17 05:57:02 +12:00
|
|
|
|
Point mousePos = NativeMethods.Screen.CursorPosition;
|
|
|
|
|
Left = Left + mousePos.X - lastLocation.X;
|
|
|
|
|
Top = Top + mousePos.Y - lastLocation.Y;
|
|
|
|
|
lastLocation = mousePos;
|
2021-11-25 07:01:59 +13:00
|
|
|
|
|
2023-05-17 05:57:02 +12:00
|
|
|
|
Settings.Default.CustomLocationX = (int)Left;
|
|
|
|
|
Settings.Default.CustomLocationY = (int)Top;
|
2021-11-25 07:01:59 +13:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-17 05:57:02 +12:00
|
|
|
|
private void MainMenu_MoveEnd(object? sender, EventArgs? e)
|
2021-11-25 07:01:59 +13:00
|
|
|
|
{
|
2023-04-28 05:48:17 +12:00
|
|
|
|
Mouse.Capture(null);
|
2023-05-17 05:57:02 +12:00
|
|
|
|
MouseMove -= MainMenu_MoveRelocate;
|
|
|
|
|
MouseUp -= MainMenu_MoveEnd;
|
|
|
|
|
Deactivated -= MainMenu_MoveEnd;
|
|
|
|
|
|
2022-12-05 13:27:57 +13:00
|
|
|
|
if (Settings.Default.UseCustomLocation)
|
2021-12-27 18:31:23 +13:00
|
|
|
|
{
|
2022-10-23 11:02:31 +13:00
|
|
|
|
if (!SettingsWindow.IsOpen())
|
2021-12-27 18:31:23 +13:00
|
|
|
|
{
|
2022-12-05 13:27:57 +13:00
|
|
|
|
Settings.Default.Save();
|
2021-12-27 18:31:23 +13:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-11-25 07:01:59 +13:00
|
|
|
|
}
|
2022-10-23 11:02:31 +13:00
|
|
|
|
|
2023-05-09 10:19:29 +12:00
|
|
|
|
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs? e)
|
|
|
|
|
{
|
|
|
|
|
if (e != null)
|
|
|
|
|
{
|
2023-05-19 09:28:52 +12:00
|
|
|
|
foreach (RowData itemData in e.AddedItems)
|
2023-05-09 10:19:29 +12:00
|
|
|
|
{
|
|
|
|
|
itemData.IsSelected = true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-19 09:28:52 +12:00
|
|
|
|
foreach (RowData itemData in e.RemovedItems)
|
2023-05-09 10:19:29 +12:00
|
|
|
|
{
|
|
|
|
|
itemData.IsSelected = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// TODO: Refactor item selection to prevent running this loop
|
|
|
|
|
ListView lv = (ListView)sender;
|
2023-08-14 08:17:16 +12:00
|
|
|
|
foreach (RowData itemData in lv.Items.SourceCollection)
|
2023-05-09 10:19:29 +12:00
|
|
|
|
{
|
2023-05-11 10:14:05 +12:00
|
|
|
|
itemData.IsSelected = lv.SelectedItem == itemData;
|
2023-05-09 10:19:29 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-19 04:20:21 +12:00
|
|
|
|
private void ListView_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
int count = dgv.Items.Count;
|
|
|
|
|
labelStatus.Content = count.ToString() + " " + Translator.GetText(count == 1 ? "element" : "elements");
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-03 11:17:05 +12:00
|
|
|
|
private void ListViewItem_MouseEnter(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (!isShellContextMenuOpen)
|
|
|
|
|
{
|
2023-09-18 04:29:51 +12:00
|
|
|
|
// "DisconnectedItem" protection
|
|
|
|
|
if (((ListViewItem)sender).Content is RowData rowData)
|
|
|
|
|
{
|
|
|
|
|
CellMouseEnter?.Invoke(rowData);
|
|
|
|
|
}
|
2023-06-03 11:17:05 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-05-06 07:07:23 +12:00
|
|
|
|
|
2023-06-03 11:17:05 +12:00
|
|
|
|
private void ListViewItem_MouseLeave(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
2023-09-18 04:29:51 +12:00
|
|
|
|
// "DisconnectedItem" protection
|
|
|
|
|
if (((ListViewItem)sender).Content is RowData rowData)
|
2023-06-03 11:17:05 +12:00
|
|
|
|
{
|
2023-09-17 20:40:32 +12:00
|
|
|
|
rowData.IsClicked = false;
|
|
|
|
|
countLeftMouseButtonClicked = 0;
|
|
|
|
|
if (!isShellContextMenuOpen)
|
2023-09-03 03:42:43 +12:00
|
|
|
|
{
|
2023-09-17 20:40:32 +12:00
|
|
|
|
CellMouseLeave?.Invoke();
|
|
|
|
|
if (e.LeftButton == MouseButtonState.Pressed)
|
|
|
|
|
{
|
|
|
|
|
string[] files = new string[] { rowData.Path };
|
|
|
|
|
DragDrop.DoDragDrop(this, new DataObject(DataFormats.FileDrop, files), DragDropEffects.Copy);
|
|
|
|
|
}
|
2023-09-03 03:42:43 +12:00
|
|
|
|
}
|
2023-06-03 11:17:05 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-23 11:02:31 +13:00
|
|
|
|
|
2023-09-18 04:29:51 +12:00
|
|
|
|
private void ListViewItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// "DisconnectedItem" protection
|
|
|
|
|
if (((ListViewItem)sender).Content is RowData rowData)
|
|
|
|
|
{
|
|
|
|
|
CellMouseDown?.Invoke(rowData);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-02 06:08:36 +12:00
|
|
|
|
|
2023-09-12 05:25:38 +12:00
|
|
|
|
private void ListViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
|
|
|
|
{
|
2023-09-18 04:29:51 +12:00
|
|
|
|
// "DisconnectedItem" protection
|
|
|
|
|
if (((ListViewItem)sender).Content is RowData rowData)
|
|
|
|
|
{
|
|
|
|
|
rowData.IsClicked = true;
|
|
|
|
|
countLeftMouseButtonClicked = e.ClickCount;
|
|
|
|
|
}
|
2023-09-12 05:25:38 +12:00
|
|
|
|
}
|
2023-09-12 04:44:56 +12:00
|
|
|
|
|
|
|
|
|
private void ListViewItem_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
{
|
2023-09-18 04:29:51 +12:00
|
|
|
|
// "DisconnectedItem" protection
|
|
|
|
|
if (((ListViewItem)sender).Content is RowData rowData)
|
2023-09-12 04:44:56 +12:00
|
|
|
|
{
|
2023-09-18 04:29:51 +12:00
|
|
|
|
if (rowData.IsClicked)
|
|
|
|
|
{
|
|
|
|
|
// Same row has been called with PreviewMouseLeftButtonDown without leaving the item, so we can call it a "click".
|
|
|
|
|
// The click count is also taken from Down event as it seems not being correct in Up event.
|
|
|
|
|
rowData.OpenItem(countLeftMouseButtonClicked);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rowData.IsClicked = false;
|
2023-09-12 04:44:56 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-12 05:25:38 +12:00
|
|
|
|
countLeftMouseButtonClicked = 0;
|
2023-09-12 04:44:56 +12:00
|
|
|
|
}
|
2023-09-02 06:08:36 +12:00
|
|
|
|
|
|
|
|
|
private void ListViewItem_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
|
2022-10-23 11:02:31 +13:00
|
|
|
|
{
|
2023-09-18 04:29:51 +12:00
|
|
|
|
// "DisconnectedItem" protection
|
|
|
|
|
if (((ListViewItem)sender).Content is RowData rowData)
|
|
|
|
|
{
|
|
|
|
|
// At mouse location
|
|
|
|
|
Point position = Mouse.GetPosition(this);
|
|
|
|
|
position.Offset(Left, Top);
|
2023-09-02 05:49:34 +12:00
|
|
|
|
|
2023-09-18 04:29:51 +12:00
|
|
|
|
isShellContextMenuOpen = true;
|
|
|
|
|
rowData.OpenShellContextMenu(position);
|
|
|
|
|
isShellContextMenuOpen = false;
|
|
|
|
|
}
|
2022-10-23 11:02:31 +13:00
|
|
|
|
}
|
2020-06-08 00:28:59 +12:00
|
|
|
|
}
|
2022-10-23 11:02:31 +13:00
|
|
|
|
}
|