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-04-30 05:51:44 +12:00
using System.ComponentModel ;
2020-07-07 07:15:45 +12:00
using System.Globalization ;
2023-04-16 07:23:28 +12:00
using System.IO ;
2023-04-30 05:51:44 +12:00
using System.Runtime.CompilerServices ;
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 ;
using System.Windows.Threading ;
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 ;
2022-12-04 10:41:03 +13:00
using SystemTrayMenu.Properties ;
2020-07-07 07:15:45 +12:00
using SystemTrayMenu.Utilities ;
2022-11-29 08:27:52 +13:00
using KeyEventArgs = System . Windows . Input . KeyEventArgs ;
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-30 05:51:44 +12:00
private readonly DispatcherTimer timerUpdateIcons = new ( DispatcherPriority . Background , Dispatcher . CurrentDispatcher ) ;
2023-04-16 07:23:28 +12:00
private readonly string folderPath ;
2022-11-30 10:48:45 +13:00
#if TODO // SEARCH
2022-06-18 23:03:28 +12:00
public const string RowFilterShowAll = "[SortIndex] LIKE '%0%'" ;
2022-10-23 11:02:31 +13:00
#endif
2022-12-04 13:24:30 +13:00
private bool isFading ;
2021-04-17 12:39:48 +12:00
private bool directionToRight ;
2021-11-25 07:01:59 +13:00
private bool mouseDown ;
private Point lastLocation ;
2023-04-20 10:50:29 +12:00
2022-11-30 10:48:45 +13:00
#if TODO // SEARCH
2022-02-21 06:00:04 +13:00
private bool isSetSearchText ;
2022-10-23 11:02:31 +13:00
#endif
2023-04-16 07:23:28 +12:00
internal Menu ( MenuData menuData , string path )
2020-06-08 00:28:59 +12:00
{
2022-10-23 11:02:31 +13:00
timerUpdateIcons . Tick + = TimerUpdateIcons_Tick ;
Closed + = ( _ , _ ) = >
{
timerUpdateIcons . Stop ( ) ;
2023-04-20 10:50:29 +12:00
IsClosed = true ; // TODO WPF Replace Forms wrapper
2022-10-23 11:02:31 +13:00
} ;
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 )
{
txtTitle . Visibility = Visibility . Hidden ;
}
if ( ! Config . ShowSearchBar )
{
searchPanel . Visibility = Visibility . Collapsed ;
}
if ( ! Config . ShowFunctionKeyOpenFolder )
{
buttonOpenFolder . Visibility = Visibility . Collapsed ;
}
if ( ! Config . ShowFunctionKeyPinMenu )
{
buttonMenuAlwaysOpen . Visibility = Visibility . Collapsed ;
}
if ( ! Config . ShowFunctionKeySettings )
{
buttonSettings . Visibility = Visibility . Collapsed ;
}
if ( ! Config . ShowFunctionKeyRestart )
{
buttonRestart . Visibility = Visibility . Collapsed ;
}
2023-04-16 07:23:28 +12:00
folderPath = path ;
RowDataParent = menuData . 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 ;
2022-12-04 09:23:19 +13:00
// Use Main Menu DPI for all further calculations
Scaling . CalculateFactorByDpi ( this ) ;
}
2023-04-16 07:23:28 +12:00
else
{
2023-04-30 04:57:39 +12:00
// This will be a sub menu
Level = RowDataParent . Level + 1 ;
RowDataParent . SubMenu = this ;
2023-04-17 01:45:47 +12:00
buttonOpenFolder . Visibility = Visibility . Collapsed ;
buttonSettings . Visibility = Visibility . Collapsed ;
buttonRestart . Visibility = Visibility . Collapsed ;
labelStatus . Content = Translator . GetText ( "loading" ) ;
// Todo: use embedded resources that we can assign image in XAML already
pictureBoxLoading . Source = SystemTrayMenu . Resources . StaticResources . LoadingIcon . ToImageSource ( ) ;
pictureBoxLoading . Visibility = Visibility . Visible ;
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-04-16 22:42:42 +12:00
txtTitle . Text = Title = title ;
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 ) ;
MouseDown + = Menu_MouseDown ;
MouseUp + = Menu_MouseUp ;
MouseMove + = Menu_MouseMove ;
2022-12-01 12:16:30 +13:00
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 ( )
{
Header = Translator . GetText ( "Cut" ) ,
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 ( )
{
Header = Translator . GetText ( "Paste" ) ,
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 ( )
{
Header = Translator . GetText ( "Select All" ) ,
Command = new ActionCommand ( ( _ ) = > textBoxSearch . SelectAll ( ) ) ,
} ) ;
2022-11-14 07:58:54 +13:00
SolidColorBrush foreColor = new ( Colors . Black ) ;
2022-10-23 11:02:31 +13:00
SolidColorBrush backColor = AppColors . Background . ToSolidColorBrush ( ) ;
SolidColorBrush backColorSearch = AppColors . SearchField . ToSolidColorBrush ( ) ;
SolidColorBrush backgroundBorder = AppColors . BackgroundBorder . ToSolidColorBrush ( ) ;
2021-06-06 23:15:01 +12:00
2022-10-23 11:02:31 +13:00
if ( Config . IsDarkMode ( ) )
2020-06-08 00:28:59 +12:00
{
2022-11-14 07:58:54 +13:00
foreColor = new ( Colors . White ) ;
2022-10-23 11:02:31 +13:00
backColor = AppColors . DarkModeBackground . ToSolidColorBrush ( ) ;
backColorSearch = AppColors . DarkModeSearchField . ToSolidColorBrush ( ) ;
backgroundBorder = AppColors . DarkModeBackgroundBorder . ToSolidColorBrush ( ) ;
2022-12-05 11:56:21 +13:00
Resources [ "ic_fluent_svgColor" ] = WPFExtensions . SolidColorBrushFromString ( Settings . Default . ColorDarkModeIcons ) ;
2022-12-04 10:41:03 +13:00
}
else
{
2022-12-05 11:56:21 +13:00
Resources [ "ic_fluent_svgColor" ] = WPFExtensions . SolidColorBrushFromString ( Settings . Default . ColorIcons ) ;
2022-10-23 11:02:31 +13:00
}
2020-06-08 00:28:59 +12:00
2022-10-23 11:02:31 +13:00
labelTitle . Foreground = foreColor ;
textBoxSearch . Foreground = foreColor ;
dgv . Foreground = foreColor ;
2022-12-04 09:23:19 +13:00
labelStatus . Foreground = MenuDefines . ColorIcons . ToSolidColorBrush ( ) ;
2022-10-23 11:02:31 +13:00
windowFrame . BorderBrush = backgroundBorder ;
windowFrame . Background = backColor ;
searchPanel . Background = backColorSearch ;
panelLine . Background = AppColors . Icons . ToSolidColorBrush ( ) ;
dgv . GotFocus + = ( _ , _ ) = > FocusTextBox ( ) ;
2022-11-30 10:48:45 +13:00
#if TODO // Misc MouseEvents
2020-06-08 00:28:59 +12:00
dgv . MouseEnter + = ControlsMouseEnter ;
labelTitle . MouseEnter + = ControlsMouseEnter ;
2021-10-29 03:29:04 +13:00
textBoxSearch . MouseEnter + = ControlsMouseEnter ;
pictureBoxOpenFolder . MouseEnter + = ControlsMouseEnter ;
2021-11-22 05:24:01 +13:00
pictureBoxMenuAlwaysOpen . MouseEnter + = ControlsMouseEnter ;
pictureBoxSettings . MouseEnter + = ControlsMouseEnter ;
pictureBoxRestart . MouseEnter + = ControlsMouseEnter ;
2021-10-29 03:29:04 +13:00
pictureBoxSearch . MouseEnter + = ControlsMouseEnter ;
2021-12-10 08:00:33 +13:00
tableLayoutPanelMenu . MouseEnter + = ControlsMouseEnter ;
2023-04-20 10:50:29 +12:00
dgv . MouseEnter + = ControlsMouseEnter ;
2021-12-10 08:00:33 +13:00
tableLayoutPanelBottom . MouseEnter + = ControlsMouseEnter ;
2022-12-04 09:23:19 +13:00
labelStatus . MouseEnter + = ControlsMouseEnter ;
2020-06-08 00:28:59 +12:00
void ControlsMouseEnter ( object sender , EventArgs e )
{
2020-06-29 06:57:03 +12:00
MouseEnter ? . Invoke ( ) ;
2020-06-08 00:28:59 +12:00
}
2020-07-07 07:15:45 +12:00
2020-06-08 00:28:59 +12:00
dgv . MouseLeave + = ControlsMouseLeave ;
labelTitle . MouseLeave + = ControlsMouseLeave ;
2021-10-29 03:29:04 +13:00
textBoxSearch . MouseLeave + = ControlsMouseLeave ;
pictureBoxMenuAlwaysOpen . MouseLeave + = ControlsMouseLeave ;
pictureBoxOpenFolder . MouseLeave + = ControlsMouseLeave ;
2021-11-22 05:24:01 +13:00
pictureBoxSettings . MouseLeave + = ControlsMouseLeave ;
pictureBoxRestart . MouseLeave + = ControlsMouseLeave ;
2021-10-29 03:29:04 +13:00
pictureBoxSearch . MouseLeave + = ControlsMouseLeave ;
2021-12-10 08:00:33 +13:00
tableLayoutPanelMenu . MouseLeave + = ControlsMouseLeave ;
2023-04-20 10:50:29 +12:00
dgv . MouseLeave + = ControlsMouseLeave ;
2021-12-10 08:00:33 +13:00
tableLayoutPanelBottom . MouseLeave + = ControlsMouseLeave ;
2022-12-04 09:23:19 +13:00
labelStatus . MouseLeave + = ControlsMouseLeave ;
2020-06-08 00:28:59 +12:00
void ControlsMouseLeave ( object sender , EventArgs e )
{
2020-06-29 06:57:03 +12:00
MouseLeave ? . Invoke ( ) ;
2020-06-08 00:28:59 +12:00
}
2022-11-30 10:48:45 +13:00
#endif
2023-04-20 10:50:29 +12:00
#if TODO // Misc MouseEvents
2022-05-03 05:55:15 +12:00
bool isTouchEnabled = NativeMethods . IsTouchEnabled ( ) ;
2022-12-05 13:27:57 +13:00
if ( ( isTouchEnabled & & Settings . Default . DragDropItemsEnabledTouch ) | |
( ! isTouchEnabled & & Settings . Default . DragDropItemsEnabled ) )
2022-05-03 05:55:15 +12:00
{
AllowDrop = true ;
DragEnter + = DragDropHelper . DragEnter ;
DragDrop + = DragDropHelper . DragDrop ;
}
2022-10-23 11:02:31 +13:00
#endif
2023-04-28 09:24:25 +12:00
Loaded + = ( _ , _ ) = >
2022-10-23 11:02:31 +13:00
{
NativeMethods . HideFromAltTab ( this ) ;
2022-12-04 13:24:30 +13:00
RaiseEvent ( new ( routedEvent : FadeInEvent ) ) ;
2022-10-23 11:02:31 +13:00
} ;
2022-11-26 11:31:20 +13:00
2023-04-28 09:24:25 +12:00
Closed + = ( _ , _ ) = >
2022-11-26 11:31:20 +13:00
{
foreach ( ListViewItemData item in dgv . Items )
{
item . data . SubMenu ? . Close ( ) ;
}
} ;
2023-04-28 08:19:02 +12:00
2023-04-28 09:24:25 +12:00
AddItemsToMenu ( menuData . RowDatas , null , false ) ;
2020-06-08 00:28:59 +12:00
}
2022-12-04 10:41:03 +13:00
internal event Action ? MenuScrolled ;
2020-07-07 09:37:55 +12:00
2022-12-01 12:16:30 +13:00
#if TODO // Misc MouseEvents
2022-10-23 11:02:31 +13:00
internal new event Action MouseEnter ;
2020-07-07 09:37:55 +12:00
2022-10-23 11:02:31 +13:00
internal new event Action MouseLeave ;
#endif
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
2022-10-23 11:02:31 +13:00
internal event Action ? UserDragsMenu ;
2023-04-25 10:24:48 +12:00
internal event Action < ListView , ListViewItemData > ? CellMouseEnter ;
2022-10-23 11:02:31 +13:00
2023-04-28 06:27:16 +12:00
internal event Action < ListView , ListViewItemData > ? CellMouseLeave ;
2022-10-23 11:02:31 +13:00
2023-04-25 10:24:48 +12:00
internal event Action < ListView , ListViewItemData , MouseButtonEventArgs > ? CellMouseDown ;
2022-10-23 11:02:31 +13:00
2023-04-25 10:24:48 +12:00
internal event Action < ListView , ListViewItemData , MouseButtonEventArgs > ? CellMouseUp ;
2022-10-23 11:02:31 +13:00
2023-04-25 10:24:48 +12:00
internal event Action < ListView , ListViewItemData > ? CellOpenOnClick ;
2023-04-25 08:38:36 +12:00
internal event Action ? ClosePressed ;
2022-10-23 11:02:31 +13: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-04-23 07:04:34 +12:00
public 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-04-23 07:04:34 +12:00
internal bool RelocateOnNextShow { get ; set ; } = true ;
2023-04-20 10:50:29 +12:00
internal bool IsClosed { get ; private set ; } = false ;
2022-10-23 11:02:31 +13:00
2023-04-20 10:50:29 +12:00
internal bool IsUsable = > Visibility = = Visibility . Visible & & ! isFading & & ! IsClosed ;
2022-12-04 13:24:30 +13:00
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
}
2020-07-08 03:05:19 +12:00
internal void FocusTextBox ( )
2020-06-08 00:28:59 +12:00
{
2022-11-30 10:48:45 +13:00
#if TODO // SEARCH
2022-02-21 06:00:04 +13:00
if ( isSetSearchText )
{
isSetSearchText = false ;
textBoxSearch . SelectAll ( ) ;
textBoxSearch . Focus ( ) ;
textBoxSearch . SelectionStart = textBoxSearch . Text . Length ;
textBoxSearch . SelectionLength = 0 ;
}
else
{
textBoxSearch . SelectAll ( ) ;
textBoxSearch . Focus ( ) ;
}
2022-10-23 11:02:31 +13:00
#endif
2020-06-08 00:28:59 +12:00
}
2023-04-17 01:45:47 +12:00
internal void SetSubMenuState ( MenuDataDirectoryState state )
2020-06-08 00:28:59 +12:00
{
2023-04-17 01:45:47 +12:00
if ( Config . ShowFunctionKeyOpenFolder )
2022-12-04 09:23:19 +13:00
{
2023-04-17 01:45:47 +12:00
buttonOpenFolder . Visibility = Visibility . Visible ;
2022-12-04 09:23:19 +13:00
}
2023-04-17 01:45:47 +12:00
buttonMenuAlwaysOpen . Visibility = Visibility . Collapsed ;
pictureBoxLoading . Visibility = Visibility . Collapsed ;
2022-12-04 09:23:19 +13:00
2023-04-17 01:45:47 +12:00
switch ( state )
2022-12-04 09:23:19 +13:00
{
2023-04-17 01:45:47 +12:00
case MenuDataDirectoryState . Valid :
if ( ! Config . ShowCountOfElementsBelow )
{
labelStatus . Visibility = Visibility . Collapsed ;
}
2022-12-04 09:23:19 +13:00
2023-04-17 01:45:47 +12:00
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 ;
2020-06-08 00:28:59 +12:00
}
}
2022-10-23 11:02:31 +13:00
internal bool IsMouseOn ( )
2020-06-08 00:28:59 +12:00
{
2022-10-23 11:02:31 +13:00
Point mousePos = NativeMethods . Screen . CursorPosition ;
bool isMouseOn = Visibility = = Visibility . Visible & &
mousePos . X > = 0 & & mousePos . X < Width & &
mousePos . Y > = 0 & & mousePos . Y < Height ;
2020-06-08 00:28:59 +12:00
return isMouseOn ;
}
2022-10-23 11:02:31 +13:00
internal ListView ? GetDataGridView ( ) // TODO WPF Replace Forms wrapper
2020-06-08 00:28:59 +12:00
{
return dgv ;
}
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-04-28 09:24:25 +12:00
internal void AddItemsToMenu ( List < RowData > data , MenuDataDirectoryState ? state , bool startIconLoading )
2023-04-17 01:45:47 +12:00
{
int foldersCount = 0 ;
int filesCount = 0 ;
List < ListViewItemData > items = new ( ) ;
foreach ( RowData rowData in data )
{
2023-04-17 06:17:24 +12:00
if ( ! ( rowData . IsAdditionalItem & & Settings . Default . ShowOnlyAsSearchResult ) )
2023-04-17 01:45:47 +12:00
{
2023-04-30 04:57:39 +12:00
if ( rowData . IsPointingToFolder )
2023-04-17 01:45:47 +12:00
{
foldersCount + + ;
}
else
{
filesCount + + ;
}
}
rowData . RowIndex = items . Count ; // Index
items . Add ( new (
( rowData . HiddenEntry ? IconReader . AddIconOverlay ( rowData . Icon , Properties . Resources . White50Percentage ) : rowData . Icon ) ? . ToImageSource ( ) ,
rowData . Text ? ? "?" ,
rowData ,
2023-04-17 06:17:24 +12:00
rowData . IsAdditionalItem & & Settings . Default . ShowOnlyAsSearchResult ? 99 : 0 ) ) ;
2023-04-17 01:45:47 +12:00
}
dgv . ItemsSource = items ;
SetCounts ( foldersCount , filesCount ) ;
2023-04-28 09:24:25 +12:00
if ( state ! = null )
{
SetSubMenuState ( state . Value ) ;
}
if ( startIconLoading )
{
timerUpdateIcons . Start ( ) ;
}
2023-04-17 01:45:47 +12:00
}
2023-04-24 09:53:20 +12:00
internal void ActivateWithFade ( )
2020-06-08 00:28:59 +12:00
{
2023-04-24 09:53:20 +12:00
if ( Settings . Default . UseFading )
2020-06-08 00:28:59 +12:00
{
2023-04-24 09:53:20 +12:00
isFading = true ;
RaiseEvent ( new ( routedEvent : FadeInEvent ) ) ;
2020-06-08 00:28:59 +12:00
}
else
{
2023-04-24 09:53:20 +12:00
Opacity = 1D ;
FadeIn_Completed ( this , new ( ) ) ;
2020-06-08 00:28:59 +12:00
}
}
2023-04-24 09:53:20 +12:00
internal void ShowWithFade ( bool transparency = false )
2020-06-08 00:28:59 +12:00
{
2022-12-04 13:24:30 +13:00
timerUpdateIcons . Start ( ) ;
2023-04-24 09:53:20 +12:00
if ( Level > 0 )
2022-12-04 13:24:30 +13:00
{
ShowActivated = false ;
}
Opacity = 0D ;
Show ( ) ;
if ( Settings . Default . UseFading )
{
isFading = true ;
if ( transparency )
{
2023-04-24 09:53:20 +12:00
RaiseEvent ( new ( routedEvent : FadeToTransparentEvent ) ) ;
2022-12-04 13:24:30 +13:00
}
else
{
RaiseEvent ( new ( routedEvent : FadeInEvent ) ) ;
}
}
else
{
Opacity = transparency ? 0.80D : 1D ;
FadeIn_Completed ( this , new ( ) ) ;
}
2020-06-08 00:28:59 +12:00
}
internal void HideWithFade ( )
{
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
isFading = true ;
RaiseEvent ( new ( routedEvent : FadeOutEvent ) ) ;
}
else
{
FadeOut_Completed ( this , new ( ) ) ;
2020-06-08 00:28:59 +12:00
}
}
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-04-23 07:04:34 +12:00
AdjustWindowPositionInternal ( originLocation ) ;
2022-12-01 12:16:30 +13:00
}
else
{
// Layout cannot be calculated during loading, postpone this event
2023-04-23 07:04:34 +12:00
Loaded + = ( _ , _ ) = > AdjustWindowPositionInternal ( originLocation ) ;
2022-12-01 12:16:30 +13:00
}
2023-04-24 08:36:15 +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 & &
menuPredecessor . Width > Settings . Default . OverlappingOffsetPixels )
{
if ( directionToRight )
{
overlappingOffset = Settings . Default . OverlappingOffsetPixels - menuPredecessor . Width ;
}
else
{
overlappingOffset = menuPredecessor . Width - Settings . Default . OverlappingOffsetPixels ;
}
}
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-04-23 07:04:34 +12:00
x = originLocation . X + menuPredecessor . Width - 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
bounds . X + bounds . Width < = x + Width - scaling )
2022-02-23 04:52:02 +13:00
{
2023-04-23 07:04:34 +12:00
x = originLocation . X - Width + scaling ;
2022-10-23 11:02:31 +13:00
if ( x < bounds . X & &
2023-04-23 07:04:34 +12:00
originLocation . X + menuPredecessor . Width < bounds . X + bounds . Width & &
bounds . X + ( bounds . Width / 2 ) > originLocation . X + ( Width / 2 ) )
2022-02-23 04:52:02 +13:00
{
2022-10-23 11:02:31 +13:00
x = bounds . X + bounds . Width - Width + 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-04-23 07:04:34 +12:00
x = originLocation . X - Width + 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-04-23 07:04:34 +12:00
x = originLocation . X + menuPredecessor . Width - scaling ;
2022-10-23 11:02:31 +13:00
if ( x + Width > bounds . X + bounds . Width & &
2023-04-23 07:04:34 +12:00
originLocation . X > bounds . X & &
bounds . X + ( bounds . Width / 2 ) < originLocation . X + ( Width / 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
{
if ( x + Width > bounds . X + bounds . Width )
{
x = bounds . X + bounds . Width - Width + scaling ;
}
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 :
x = bounds . Width - Width ;
directionToRight = false ;
break ;
2022-01-16 02:44:56 +13:00
}
2022-10-23 11:02:31 +13:00
2023-04-24 08:36:15 +12:00
x + = overlappingOffset ;
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
ListView dgv = menuPredecessor . GetDataGridView ( ) ! ;
RowData ? trigger = RowDataParent ;
2023-04-17 06:17:24 +12:00
if ( trigger ! = null & & dgv . Items . Count > trigger . RowIndex )
2022-10-23 11:02:31 +13:00
{
2022-12-03 07:34:24 +13:00
// When scrolled, we have to reduce the index number as we calculate based on visual tree
int startIndex = 0 ;
double offset = 0D ;
2023-04-17 09:27:27 +12:00
if ( VisualTreeHelper . GetChild ( dgv , 0 ) is Decorator { Child : ScrollViewer scrollViewer } )
2022-12-03 07:34:24 +13:00
{
startIndex = ( int ) scrollViewer . VerticalOffset ;
if ( trigger . RowIndex < startIndex )
2022-12-01 12:16:30 +13:00
{
2022-12-03 07:34:24 +13:00
// calculate position above starting point
for ( int i = trigger . RowIndex ; i < startIndex ; i + + )
2022-12-01 12:16:30 +13:00
{
2022-12-03 07:34:24 +13:00
ListViewItem ? item = dgv . FindVisualChildOfType < ListViewItem > ( i ) ;
if ( item ! = null )
2022-12-01 12:16:30 +13:00
{
2022-12-03 07:34:24 +13:00
offset - = item . ActualHeight ;
2022-12-01 12:16:30 +13:00
}
}
}
2022-12-03 07:34:24 +13:00
}
2022-12-01 12:16:30 +13:00
2022-12-03 07:34:24 +13:00
if ( startIndex < trigger . RowIndex )
{
// calculate position below starting point
for ( int i = startIndex ; i < trigger . RowIndex ; i + + )
2022-12-01 12:16:30 +13:00
{
ListViewItem ? item = dgv . FindVisualChildOfType < ListViewItem > ( i ) ;
if ( item ! = null )
{
offset + = item . ActualHeight ;
}
}
2022-10-23 11:02:31 +13:00
}
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
{
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 :
y = bounds . Height - Height ;
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
if ( bounds . Y + bounds . Height < y + Height )
{
y = bounds . Y + bounds . Height - Height ;
}
else if ( y < bounds . Y )
{
y = bounds . Y ;
}
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
}
2021-06-28 01:42:34 +12:00
internal void SetCounts ( int foldersCount , int filesCount )
{
2021-12-10 08:00:33 +13:00
int filesAndFoldersCount = foldersCount + filesCount ;
2021-12-11 08:35:00 +13:00
string elements = filesAndFoldersCount = = 1 ? "element" : "elements" ;
2022-12-04 09:23:19 +13:00
labelStatus . Content = $"{filesAndFoldersCount} {Translator.GetText(elements)}" ;
2021-06-28 01:42:34 +12:00
}
2022-12-04 13:24:30 +13:00
private void FadeIn_Completed ( object sender , EventArgs e )
{
isFading = false ;
}
private void FadeOut_Completed ( object sender , EventArgs e )
{
isFading = false ;
Hide ( ) ;
}
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
2022-10-23 11:02:31 +13:00
double rowHeightDefault = 21.24f * Scaling . FactorByDpi ;
2022-11-10 11:34:27 +13:00
Resources [ "RowHeight" ] = ( double ) ( int ) ( ( rowHeightDefault * factor * Scaling . Factor ) + 0.5 ) ;
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 ) ;
2022-10-23 11:02:31 +13:00
MaxHeight = Math . Min ( screenHeightMax , heightMaxByOptions ) ;
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
2022-10-23 11:02:31 +13:00
// IcoWidth 100% = 21px, 175% is 33, +3+2 is padding from ColumnIcon
double icoWidth = ( 16 * Scaling . FactorByDpi ) + 5 ;
2022-11-10 11:34:27 +13:00
Resources [ "ColumnIconWidth" ] = ( double ) ( int ) ( ( icoWidth * factorIconSizeInPercent * Scaling . Factor ) + 0.5 ) ;
2022-06-18 00:38:09 +12:00
2022-10-23 11:02:31 +13:00
double renderedMaxWidth = 0D ;
foreach ( ListViewItemData item in dgv . Items )
{
double renderedWidth = new FormattedText (
item . ColumnText ,
CultureInfo . CurrentCulture ,
FlowDirection . LeftToRight ,
new Typeface ( dgv . FontFamily , dgv . FontStyle , dgv . FontWeight , dgv . FontStretch ) ,
dgv . FontSize ,
dgv . Foreground ,
VisualTreeHelper . GetDpi ( this ) . PixelsPerDip ) . Width ;
if ( renderedWidth > renderedMaxWidth )
{
renderedMaxWidth = renderedWidth ;
}
}
Resources [ "ColumnTextWidth" ] = Math . Min (
renderedMaxWidth ,
2022-12-05 13:27:57 +13:00
( double ) ( Scaling . Factor * Scaling . FactorByDpi * 400f * ( Settings . Default . WidthMaxInPercent / 100f ) ) ) ;
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
{
view . Filter = null ;
}
else
{
2022-12-04 07:30:40 +13:00
// Instead implementing in-string wildcards, simply split into multiple search patters
view . Filter = ( object item ) = >
2022-11-04 11:35:58 +13:00
{
2022-12-04 07:30:40 +13:00
// Look for each space separated string if it is part of an entries text (case insensitive)
2023-04-25 10:24:48 +12:00
ListViewItemData itemData = ( ListViewItemData ) item ;
2022-12-04 07:30:40 +13:00
foreach ( string pattern in userPattern . Split ( ' ' , StringSplitOptions . TrimEntries | StringSplitOptions . RemoveEmptyEntries ) )
{
2023-04-25 10:24:48 +12:00
if ( ! itemData . ColumnText . ToLower ( ) . Contains ( pattern ) )
2022-12-04 07:30:40 +13:00
{
return false ;
}
}
return true ;
} ;
2021-04-15 09:12:14 +12:00
}
2021-04-15 07:06:54 +12:00
2022-12-04 07:30:40 +13:00
#if TODO // SEARCH
DataTable data = ( DataTable ) dgv . DataSource ;
2022-01-08 23:39:23 +13:00
string columnSortIndex = "SortIndex" ;
2022-12-04 07:30:40 +13:00
if ( string . IsNullOrEmpty ( userPattern ) )
2020-06-08 00:28:59 +12:00
{
2022-01-31 01:51:23 +13:00
foreach ( DataRow row in data . Rows )
2022-01-08 23:39:23 +13:00
{
2022-01-31 01:51:23 +13:00
RowData rowData = ( RowData ) row [ 2 ] ;
2022-12-05 13:27:57 +13:00
if ( rowData . IsAddionalItem & & Settings . Default . ShowOnlyAsSearchResult )
2022-01-08 23:39:23 +13:00
{
2022-01-31 01:51:23 +13:00
row [ columnSortIndex ] = 99 ;
}
else
{
row [ columnSortIndex ] = 0 ;
2022-01-08 23:39:23 +13:00
}
}
2022-01-31 01:51:23 +13:00
data . DefaultView . Sort = string . Empty ;
data . AcceptChanges ( ) ;
2021-04-15 07:06:54 +12:00
}
else
{
foreach ( DataRow row in data . Rows )
{
if ( row [ 1 ] . ToString ( ) . StartsWith (
2021-04-15 09:12:14 +12:00
searchString ,
2021-04-15 07:06:54 +12:00
StringComparison . InvariantCultureIgnoreCase ) )
{
row [ columnSortIndex ] = 0 ;
}
else
{
row [ columnSortIndex ] = 1 ;
}
}
data . DefaultView . Sort = columnSortIndex ;
2020-06-08 00:28:59 +12:00
}
2021-06-28 00:44:12 +12:00
int foldersCount = 0 ;
int filesCount = 0 ;
2021-10-22 08:28:58 +13:00
bool anyIconNotUpdated = false ;
2021-06-28 00:44:12 +12:00
2021-04-17 09:14:39 +12:00
foreach ( DataGridViewRow row in dgv . Rows )
{
RowData rowData = ( RowData ) row . Cells [ 2 ] . Value ;
2021-06-28 00:44:12 +12:00
2022-12-04 07:30:40 +13:00
if ( ! string . IsNullOrEmpty ( userPattern ) | |
2022-12-05 13:27:57 +13:00
! ( rowData . IsAddionalItem & & Settings . Default . ShowOnlyAsSearchResult ) )
2021-06-28 00:44:12 +12:00
{
2022-01-08 23:39:23 +13:00
rowData . RowIndex = row . Index ;
2021-10-22 08:28:58 +13:00
2022-01-08 23:39:23 +13:00
if ( rowData . ContainsMenu )
{
foldersCount + + ;
}
else
{
filesCount + + ;
}
if ( rowData . IconLoading )
{
anyIconNotUpdated = true ;
}
2021-10-22 08:28:58 +13:00
}
2021-04-17 09:14:39 +12:00
}
2021-06-28 00:44:12 +12:00
SetCounts ( foldersCount , filesCount ) ;
2023-04-17 06:17:24 +12:00
#endif
2023-04-28 09:24:25 +12:00
SearchTextChanged ? . Invoke ( this , string . IsNullOrEmpty ( userPattern ) , causedByWatcherUpdate ) ;
2023-04-17 06:17:24 +12:00
#if TODO // SEARCH
2021-10-22 08:28:58 +13:00
if ( anyIconNotUpdated )
{
timerUpdateIcons . Start ( ) ;
}
2022-10-23 11:02:31 +13:00
#endif
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
2022-10-23 11:02:31 +13:00
private void TimerUpdateIcons_Tick ( object? sender , EventArgs e )
2021-09-24 08:53:46 +12:00
{
int iconsToUpdate = 0 ;
2023-04-25 10:24:48 +12:00
foreach ( ListViewItemData itemData in dgv . Items )
2021-09-24 08:53:46 +12:00
{
2023-04-25 10:24:48 +12:00
RowData rowData = itemData . data ;
rowData . RowIndex = dgv . Items . IndexOf ( itemData ) ;
2021-09-24 08:53:46 +12:00
if ( rowData . IconLoading )
{
iconsToUpdate + + ;
2022-12-05 13:27:57 +13:00
rowData . ReadIcon ( false ) ;
if ( rowData . Icon ! = null )
{
2023-04-25 10:24:48 +12:00
itemData . ColumnIcon = rowData . Icon . ToImageSource ( ) ;
2022-12-05 13:27:57 +13:00
}
2021-09-24 08:53:46 +12:00
}
}
if ( iconsToUpdate < 1 )
{
timerUpdateIcons . Stop ( ) ;
}
}
2021-11-25 07:01:59 +13:00
2022-10-23 11:02:31 +13:00
private void Menu_MouseDown ( object sender , MouseButtonEventArgs e )
2021-11-25 07:01:59 +13:00
{
2021-12-10 08:00:33 +13:00
if ( Level = = 0 )
{
mouseDown = true ;
2022-10-23 11:02:31 +13:00
lastLocation = NativeMethods . Screen . CursorPosition ;
UserDragsMenu ? . Invoke ( ) ;
2023-04-28 05:48:17 +12:00
Mouse . Capture ( this ) ;
2021-12-10 08:00:33 +13:00
}
2021-11-25 07:01:59 +13:00
}
private void Menu_MouseMove ( object sender , MouseEventArgs e )
{
if ( mouseDown )
{
2022-10-23 11:02:31 +13: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
2022-12-05 13:27:57 +13:00
Settings . Default . CustomLocationX = ( int ) Left ;
Settings . Default . CustomLocationY = ( int ) Top ;
2021-11-25 07:01:59 +13:00
}
}
2022-10-23 11:02:31 +13:00
private void Menu_MouseUp ( object sender , MouseButtonEventArgs e )
2021-11-25 07:01:59 +13:00
{
mouseDown = false ;
2023-04-28 05:48:17 +12:00
Mouse . Capture ( null ) ;
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
private void ListViewItem_MouseEnter ( object sender , MouseEventArgs e )
{
2023-04-25 10:24:48 +12:00
CellMouseEnter ? . Invoke ( dgv , ( ListViewItemData ) ( ( ListViewItem ) sender ) . Content ) ;
2022-10-23 11:02:31 +13:00
}
private void ListViewItem_MouseLeave ( object sender , MouseEventArgs e )
{
2023-04-28 06:27:16 +12:00
CellMouseLeave ? . Invoke ( dgv , ( ListViewItemData ) ( ( ListViewItem ) sender ) . Content ) ;
2022-10-23 11:02:31 +13:00
}
2022-11-26 11:31:20 +13:00
private void ListViewItem_PreviewMouseDown ( object sender , MouseButtonEventArgs e )
2022-10-23 11:02:31 +13:00
{
2023-04-25 10:24:48 +12:00
ListViewItemData itemData = ( ListViewItemData ) ( ( ListViewItem ) sender ) . Content ;
2023-04-25 08:38:36 +12:00
2023-04-25 10:24:48 +12:00
CellMouseDown ? . Invoke ( dgv , itemData , e ) ;
2023-04-25 08:38:36 +12:00
2023-04-30 04:57:39 +12:00
if ( e . LeftButton = = MouseButtonState . Pressed )
{
itemData . data . IsClicking = true ;
}
if ( e . RightButton = = MouseButtonState . Pressed )
{
var position = Mouse . GetPosition ( this ) ;
position . Offset ( Left , Top ) ;
itemData . data . OpenShellContextMenu ( position ) ;
}
2022-10-23 11:02:31 +13:00
}
private void ListViewItem_MouseUp ( object sender , MouseButtonEventArgs e )
{
2023-04-25 10:24:48 +12:00
CellMouseUp ? . Invoke ( dgv , ( ListViewItemData ) ( ( ListViewItem ) sender ) . Content , e ) ;
2022-10-23 11:02:31 +13:00
}
private void ListViewxItem_PreviewMouseLeftButtonDown ( object sender , MouseButtonEventArgs e )
{
2023-04-25 10:24:48 +12:00
ListViewItemData itemData = ( ListViewItemData ) ( ( ListViewItem ) sender ) . Content ;
2023-04-25 08:38:36 +12:00
2023-04-25 10:24:48 +12:00
itemData . data . OpenItem ( out bool doClose , e . ClickCount ) ;
2023-04-25 08:38:36 +12:00
if ( e . ClickCount = = 1 )
{
2023-04-25 10:24:48 +12:00
CellOpenOnClick ? . Invoke ( dgv , itemData ) ;
2023-04-25 08:38:36 +12:00
}
if ( doClose )
{
ClosePressed ? . Invoke ( ) ;
}
2022-10-23 11:02:31 +13:00
}
/// <summary>
/// Type for ListView items.
/// </summary>
2023-04-30 05:51:44 +12:00
internal class ListViewItemData : INotifyPropertyChanged
2022-10-23 11:02:31 +13:00
{
2023-04-30 08:42:28 +12:00
private Brush ? backgroundBrush ;
private Brush ? borderBrush ;
2023-04-30 05:51:44 +12:00
private ImageSource ? columnIcon ;
internal ListViewItemData ( ImageSource ? columnIcon , string columnText , RowData rowData , int sortIndex )
2022-10-23 11:02:31 +13:00
{
2023-04-30 05:51:44 +12:00
this . columnIcon = columnIcon ;
2022-10-23 11:02:31 +13:00
ColumnText = columnText ;
data = rowData ;
SortIndex = sortIndex ;
}
2023-04-30 05:51:44 +12:00
public event PropertyChangedEventHandler ? PropertyChanged ;
2023-04-30 08:42:28 +12:00
public Brush ? BackgroundBrush
{
get = > backgroundBrush ;
set
{
backgroundBrush = value ;
CallPropertyChanged ( ) ;
}
}
public Brush ? BorderBrush
{
get = > borderBrush ;
set
{
borderBrush = value ;
CallPropertyChanged ( ) ;
}
}
2023-04-30 05:51:44 +12:00
public ImageSource ? ColumnIcon
{
get = > columnIcon ;
set
{
columnIcon = value ;
CallPropertyChanged ( ) ;
}
}
2022-10-23 11:02:31 +13:00
2023-04-30 05:51:44 +12:00
public string ColumnText { get ; }
2022-10-23 11:02:31 +13:00
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Benennungsstile", Justification = "Temporarily retained for compatibility reasons")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "Temporarily retained for compatibility reasons")]
2023-04-30 05:51:44 +12:00
internal RowData data { get ; set ; }
internal int SortIndex { get ; set ; }
2022-10-23 11:02:31 +13:00
2023-04-30 05:51:44 +12:00
/// <summary>
/// Triggers an PropertyChanged event of INotifyPropertyChanged.
/// </summary>
/// <param name="propertyName">Name of the changing property.</param>
public void CallPropertyChanged ( [ CallerMemberName ] string? propertyName = null ) = > PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( propertyName ) ) ;
2022-10-23 11:02:31 +13:00
}
2020-06-08 00:28:59 +12:00
}
2022-10-23 11:02:31 +13:00
}