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>
2022-10-23 11:02:31 +13:00
#nullable enable
2020-07-07 09:37:55 +12:00
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 ;
2020-07-07 07:15:45 +12:00
using System.Globalization ;
using System.Reflection ;
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 ;
2020-07-07 07:15:45 +12:00
using SystemTrayMenu.DataClasses ;
using SystemTrayMenu.DllImports ;
2021-10-26 08:45:49 +13:00
using SystemTrayMenu.Helper ;
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-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
private const int CornerRadius = 10 ;
2021-11-17 12:13:46 +13:00
private readonly Fading fading = new ( ) ;
2021-04-17 12:39:48 +12:00
private bool isShowing ;
private bool directionToRight ;
2021-11-25 07:01:59 +13:00
private bool mouseDown ;
private Point lastLocation ;
2022-11-30 10:48:45 +13:00
#if TODO // SEARCH
2022-02-21 06:00:04 +13:00
private bool isSetSearchText ;
2022-08-02 10:49:56 +12:00
private bool dgvHeightSet ;
2022-10-23 11:02:31 +13:00
#endif
private bool isClosed = false ; // TODO WPF Replace Forms wrapper
private DispatcherTimer timerUpdateIcons = new DispatcherTimer ( DispatcherPriority . Render , Dispatcher . CurrentDispatcher ) ;
2020-06-06 21:47:19 +12:00
2020-06-08 00:28:59 +12:00
internal Menu ( )
{
2022-10-23 11:02:31 +13:00
timerUpdateIcons . Tick + = TimerUpdateIcons_Tick ;
Closed + = ( _ , _ ) = >
{
2022-11-14 07:58:54 +13:00
fading . Fade ( Fading . FadingState . Idle ) ;
2022-10-23 11:02:31 +13:00
timerUpdateIcons . Stop ( ) ;
isClosed = true ; // TODO WPF Replace Forms wrapper
} ;
Opacity = 0D ;
2020-06-08 00:28:59 +12:00
fading . ChangeOpacity + = Fading_ChangeOpacity ;
2022-10-23 11:02:31 +13:00
void Fading_ChangeOpacity ( object? sender , double newOpacity )
2020-06-08 00:28:59 +12:00
{
2022-02-22 07:34:16 +13:00
if ( newOpacity ! = Opacity & & ! IsDisposed & & ! Disposing )
2020-06-21 06:11:25 +12:00
{
2021-12-10 08:00:33 +13:00
Opacity = newOpacity ;
2020-06-21 06:11:25 +12:00
}
2020-06-08 00:28:59 +12:00
}
2020-07-07 07:15:45 +12:00
2020-06-08 00:28:59 +12:00
fading . Show + = Fading_Show ;
void Fading_Show ( )
{
2021-05-29 06:48:17 +12:00
try
2020-06-08 00:28:59 +12:00
{
2021-05-29 06:48:17 +12:00
isShowing = true ;
2022-10-23 11:02:31 +13:00
Visibility = Visibility . Visible ;
2021-05-29 06:48:17 +12:00
isShowing = false ;
2021-09-24 08:53:46 +12:00
timerUpdateIcons . Start ( ) ;
2021-05-29 06:48:17 +12:00
}
catch ( ObjectDisposedException )
{
2022-10-23 11:02:31 +13:00
Visibility = Visibility . Hidden ;
2021-05-29 06:48:17 +12:00
isShowing = false ;
Log . Info ( $"Could not open menu, old menu was disposing," +
$" IsDisposed={IsDisposed}" ) ;
}
2020-06-08 00:28:59 +12:00
2022-10-23 11:02:31 +13:00
if ( Visibility = = Visibility . Visible )
2021-05-29 06:48:17 +12:00
{
if ( Level = = 0 )
2020-06-08 00:28:59 +12:00
{
Activate ( ) ;
2022-10-23 11:02:31 +13:00
Show ( ) ;
2020-06-08 00:28:59 +12:00
}
2021-05-29 06:48:17 +12:00
else
{
2022-10-23 11:02:31 +13:00
ShowActivated = false ;
Show ( ) ;
2021-05-29 06:48:17 +12:00
}
2020-06-08 00:28:59 +12:00
}
}
2020-07-07 07:15:45 +12:00
2020-06-08 00:28:59 +12:00
fading . Hide + = Hide ;
InitializeComponent ( ) ;
2020-07-07 07:15:45 +12:00
2022-10-23 11:02:31 +13:00
Assembly myassembly = Assembly . GetExecutingAssembly ( ) ;
string myname = myassembly . GetName ( ) . Name ? ? string . Empty ;
2022-07-10 11:53:36 +12:00
2022-10-23 11:02:31 +13:00
txtTitle . Text = myname ;
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 ) ;
labelItems . FontSize = Scaling . ScaleFontByPoints ( 7F ) ;
dgv . FontSize = Scaling . ScaleFontByPoints ( 9F ) ;
MouseDown + = Menu_MouseDown ;
MouseUp + = Menu_MouseUp ;
MouseMove + = Menu_MouseMove ;
2022-12-01 12:16:30 +13:00
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 ( ) ;
}
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 ;
labelItems . Foreground = MenuDefines . ColorIcons . ToSolidColorBrush ( ) ;
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 ;
tableLayoutPanelDgvAndScrollbar . MouseEnter + = ControlsMouseEnter ;
tableLayoutPanelBottom . MouseEnter + = ControlsMouseEnter ;
labelItems . 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 ;
tableLayoutPanelDgvAndScrollbar . MouseLeave + = ControlsMouseLeave ;
tableLayoutPanelBottom . MouseLeave + = ControlsMouseLeave ;
labelItems . 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
#if TODO // TOUCH
2022-05-03 05:55:15 +12:00
bool isTouchEnabled = NativeMethods . IsTouchEnabled ( ) ;
if ( ( isTouchEnabled & & Properties . Settings . Default . DragDropItemsEnabledTouch ) | |
( ! isTouchEnabled & & Properties . Settings . Default . DragDropItemsEnabled ) )
{
AllowDrop = true ;
DragEnter + = DragDropHelper . DragEnter ;
DragDrop + = DragDropHelper . DragDrop ;
}
2022-10-23 11:02:31 +13:00
#endif
Loaded + = ( sender , e ) = >
{
NativeMethods . HideFromAltTab ( this ) ;
// TODO WPF Replace Forms wrapper
IsHandleCreated = true ;
HandleCreated ? . Invoke ( sender , e ) ;
} ;
2022-11-26 11:31:20 +13:00
Closed + = ( sender , e ) = >
{
foreach ( ListViewItemData item in dgv . Items )
{
item . data . SubMenu ? . Close ( ) ;
}
} ;
2020-06-08 00:28:59 +12:00
}
2022-12-01 12:16:30 +13:00
internal new event Action Scrolled ;
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-10-23 11:02:31 +13:00
internal event Action ? UserClickedOpenFolder ;
2020-07-07 09:37:55 +12:00
2022-11-29 08:27:52 +13:00
internal event Action < Menu , Key , ModifierKeys > CmdKeyProcessed ;
2022-11-30 10:48:45 +13:00
#if TODO // SEARCH
2020-07-07 09:37:55 +12:00
2022-02-21 09:35:38 +13:00
internal event EventHandler < KeyPressEventArgs > KeyPressCheck ;
2022-10-23 11:02:31 +13:00
internal event Action SearchTextChanging ;
2020-07-07 09:37:55 +12:00
2022-06-11 23:04:21 +12:00
internal event EventHandler < bool > SearchTextChanged ;
2022-10-23 11:02:31 +13:00
#endif
2020-07-07 09:37:55 +12:00
2022-10-23 11:02:31 +13:00
internal event Action ? UserDragsMenu ;
internal event RoutedEventHandler ? HandleCreated ; // TODO WPF Replace Forms wrapper
internal event Action < ListView , int > ? CellMouseEnter ;
internal event Action < ListView , int > ? CellMouseLeave ;
internal event Action < ListView , int , MouseButtonEventArgs > ? CellMouseDown ;
internal event Action < ListView , int , MouseButtonEventArgs > ? CellMouseUp ;
internal event Action < ListView , int , MouseButtonEventArgs > ? CellMouseClick ;
2020-07-07 09:37:55 +12:00
internal enum MenuType
{
2022-11-04 11:35:58 +13:00
/// <summary>
/// Root menu
/// </summary>
2020-07-07 09:37:55 +12:00
Main ,
2022-11-04 11:35:58 +13:00
/// <summary>
/// Sub menu
/// </summary>
2020-07-07 09:37:55 +12:00
Sub ,
2022-11-04 11:35:58 +13:00
/// <summary>
/// Sub menu with no content
/// </summary>
2020-07-07 09:37:55 +12:00
Empty ,
2022-11-04 11:35:58 +13:00
/// <summary>
/// Sub menu with no access
/// </summary>
2020-07-07 09:37:55 +12:00
NoAccess ,
2022-11-04 11:35:58 +13:00
/// <summary>
/// TODO: Not used - remove?
/// </summary>
2020-07-07 09:37:55 +12:00
MaxReached ,
2022-11-04 11:35:58 +13:00
/// <summary>
/// Sub menu but with yet unknown content
/// </summary>
2021-10-04 07:24:22 +13:00
Loading ,
2020-07-07 09:37:55 +12:00
}
2020-09-21 05:19:21 +12:00
internal enum StartLocation
{
Predecessor ,
BottomLeft ,
BottomRight ,
TopRight ,
}
2022-10-23 11:02:31 +13:00
public bool IsHandleCreated { get ; internal set ; } // TODO State out of window
2020-07-08 03:05:19 +12:00
2022-10-23 11:02:31 +13:00
public bool IsLoadingMenu { get ; internal set ; } // TODO State out of window
2020-07-07 09:37:55 +12:00
2022-10-23 11:02:31 +13:00
public bool IsDisposed = > isClosed ; // TODO WPF Replace Forms wrapper
2022-01-09 01:39:19 +13:00
2022-10-23 11:02:31 +13:00
public bool Disposing = > isClosed ; // TODO WPF Replace Forms wrapper
2021-12-06 05:04:48 +13:00
2022-10-23 11:02:31 +13:00
public System . Drawing . Point Location = > new System . Drawing . Point ( ( int ) Left , ( int ) Top ) ; // TODO WPF Replace Forms wrapper)
internal int Level { get ; set ; }
internal bool IsUsable = > Visibility = = Visibility . Visible & & ! fading . IsHiding & & ! IsDisposed & & ! Disposing ;
2022-11-30 10:48:45 +13:00
#if TODO // TOUCH
2022-10-23 11:02:31 +13:00
internal bool ScrollbarVisible { get ; private set ; }
2020-06-08 00:28:59 +12:00
2022-11-04 11:35:58 +13:00
private ListView tableLayoutPanelDgvAndScrollbar = > dgv ; // TODO WPF Remove and replace with dgv
#endif
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
}
}
internal void RefreshSearchText ( )
{
2022-11-04 11:35:58 +13:00
TextBoxSearch_TextChanged ( ) ;
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
}
internal void SetTypeSub ( )
{
SetType ( MenuType . Sub ) ;
}
internal void SetTypeEmpty ( )
{
SetType ( MenuType . Empty ) ;
}
internal void SetTypeNoAccess ( )
{
SetType ( MenuType . NoAccess ) ;
}
2021-10-04 07:24:22 +13:00
internal void SetTypeLoading ( )
{
SetType ( MenuType . Loading ) ;
}
2020-06-08 00:28:59 +12:00
internal void SetType ( MenuType type )
{
2021-06-26 23:24:56 +12:00
if ( type ! = MenuType . Main )
{
2022-10-23 11:02:31 +13:00
buttonSettings . Visibility = Visibility . Collapsed ;
buttonRestart . Visibility = Visibility . Collapsed ;
2021-06-26 23:24:56 +12:00
}
2020-06-08 00:28:59 +12:00
switch ( type )
{
2021-10-04 07:24:22 +13:00
case MenuType . Main :
2022-11-04 11:35:58 +13:00
textBoxSearch . TextChanged + = ( _ , _ ) = > TextBoxSearch_TextChanged ( ) ;
2021-10-04 07:24:22 +13:00
break ;
2020-06-08 00:28:59 +12:00
case MenuType . Sub :
2022-11-04 11:35:58 +13:00
textBoxSearch . TextChanged + = ( _ , _ ) = > TextBoxSearch_TextChanged ( ) ;
2022-10-23 11:02:31 +13:00
buttonMenuAlwaysOpen . Visibility = Visibility . Collapsed ;
2020-06-08 00:28:59 +12:00
break ;
case MenuType . Empty :
2022-11-04 11:35:58 +13:00
// TODO? remove search bar when searching makes no sense (take care of calculating initial position)
// searchPanel.Visibility = Visibility.Collapsed;
2022-10-23 11:02:31 +13:00
labelItems . Content = Translator . GetText ( "Directory empty" ) ;
buttonMenuAlwaysOpen . Visibility = Visibility . Collapsed ;
2020-06-08 00:28:59 +12:00
break ;
case MenuType . NoAccess :
2022-11-04 11:35:58 +13:00
// TODO? remove search bar when searching makes no sense (take care of calculating initial position)
// searchPanel.Visibility = Visibility.Collapsed;
2022-10-23 11:02:31 +13:00
labelItems . Content = Translator . GetText ( "Directory inaccessible" ) ;
buttonMenuAlwaysOpen . Visibility = Visibility . Collapsed ;
2020-06-08 00:28:59 +12:00
break ;
2021-10-04 07:24:22 +13:00
case MenuType . Loading :
2022-10-23 11:02:31 +13:00
labelItems . Content = Translator . GetText ( "loading" ) ;
buttonMenuAlwaysOpen . Visibility = Visibility . Visible ;
buttonOpenFolder . Visibility = Visibility . Collapsed ;
2022-11-14 07:12:49 +13:00
// Todo: use embedded resources that we can assign image in XAML already
2022-11-14 07:58:54 +13:00
pictureBoxLoading . Source = SystemTrayMenu . Resources . StaticResources . LoadingIcon . ToImageSource ( ) ;
2022-11-14 07:12:49 +13:00
pictureBoxLoading . Visibility = Visibility . Visible ;
2020-06-08 00:28:59 +12:00
break ;
default :
break ;
}
}
2021-12-10 08:00:33 +13:00
internal string GetSearchText ( )
{
return textBoxSearch . Text ;
}
internal void SetSearchText ( string userSearchText )
{
2022-02-21 06:00:04 +13:00
if ( ! string . IsNullOrEmpty ( userSearchText ) )
{
textBoxSearch . Text = userSearchText + "*" ;
2022-11-30 10:48:45 +13:00
#if TODO // SEARCH
2022-02-21 06:00:04 +13:00
isSetSearchText = true ;
2022-10-23 11:02:31 +13:00
#endif
2022-02-21 06:00:04 +13:00
}
2021-12-10 08:00:33 +13: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 ;
}
2022-06-01 09:23:26 +12:00
internal void AdjustControls ( string title , MenuDataValidity menuDataValidity )
2020-06-08 00:28:59 +12:00
{
2022-06-01 09:23:26 +12:00
if ( ! string . IsNullOrEmpty ( title ) & & Config . ShowDirectoryTitleAtTop )
2020-06-08 00:28:59 +12:00
{
if ( title . Length > MenuDefines . LengthMax )
{
2021-12-12 02:34:28 +13:00
title = $"{title[..MenuDefines.LengthMax]}..." ;
2020-06-08 00:28:59 +12:00
}
2020-07-07 07:15:45 +12:00
2022-10-23 11:02:31 +13:00
txtTitle . Text = title ;
2022-06-01 09:23:26 +12:00
}
else
{
2022-10-23 11:02:31 +13:00
txtTitle . Text = string . Empty ;
2022-06-01 09:23:26 +12:00
}
if ( ! Config . ShowSearchBar )
{
2022-10-23 11:02:31 +13:00
searchPanel . Visibility = Visibility . Collapsed ;
panelLine . Visibility = Visibility . Collapsed ;
2022-06-01 09:23:26 +12:00
}
if ( ! Config . ShowCountOfElementsBelow & &
menuDataValidity = = MenuDataValidity . Valid )
{
2022-10-23 11:02:31 +13:00
labelItems . Visibility = Visibility . Collapsed ;
2022-06-01 09:23:26 +12:00
}
2022-07-11 01:39:27 +12:00
if ( ! Config . ShowFunctionKeyOpenFolder )
2022-06-01 09:23:26 +12:00
{
2022-10-23 11:02:31 +13:00
buttonOpenFolder . Visibility = Visibility . Collapsed ;
2022-07-11 01:39:27 +12:00
}
if ( ! Config . ShowFunctionKeyPinMenu )
{
2022-10-23 11:02:31 +13:00
buttonMenuAlwaysOpen . Visibility = Visibility . Collapsed ;
2022-07-11 01:39:27 +12:00
}
if ( ! Config . ShowFunctionKeySettings )
{
2022-10-23 11:02:31 +13:00
buttonSettings . Visibility = Visibility . Collapsed ;
2022-07-11 01:39:27 +12:00
}
if ( ! Config . ShowFunctionKeyRestart )
{
2022-10-23 11:02:31 +13:00
buttonRestart . Visibility = Visibility . Collapsed ;
2020-06-08 00:28:59 +12:00
}
}
internal void ShowWithFadeOrTransparent ( bool formActiveFormIsMenu )
{
if ( formActiveFormIsMenu )
{
ShowWithFade ( ) ;
}
else
{
ShowTransparent ( ) ;
}
}
internal void ShowWithFade ( )
{
fading . Fade ( Fading . FadingState . Show ) ;
}
internal void ShowTransparent ( )
{
fading . Fade ( Fading . FadingState . ShowTransparent ) ;
}
internal void HideWithFade ( )
{
if ( ! isShowing )
{
fading . Fade ( Fading . FadingState . Hide ) ;
}
}
2022-06-18 00:38:09 +12:00
internal void TimerUpdateIconsStart ( )
{
timerUpdateIcons . Start ( ) ;
}
2022-10-23 11:02:31 +13:00
#if TODO // Hack for a pseudo Refresh
private delegate void NoArgDelegate ( ) ;
#endif
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>
2021-12-28 00:22:52 +13:00
/// <param name="isCustomLocationOutsideOfScreen">isCustomLocationOutsideOfScreen.</param>
2020-07-07 07:15:45 +12:00
internal void AdjustSizeAndLocation (
2022-11-14 07:58:54 +13:00
Rect bounds ,
2020-09-21 03:26:45 +12:00
Menu menuPredecessor ,
2021-12-28 00:22:52 +13:00
StartLocation startLocation ,
bool isCustomLocationOutsideOfScreen )
2020-06-08 00:28:59 +12:00
{
2021-05-29 09:23:05 +12:00
// Update the height and width
AdjustDataGridViewHeight ( menuPredecessor , bounds . Height ) ;
AdjustDataGridViewWidth ( ) ;
2022-10-23 11:02:31 +13:00
#if TODO // Hack for a pseudo Refresh
this . Dispatcher . Invoke ( System . Windows . Threading . DispatcherPriority . ApplicationIdle ,
( NoArgDelegate ) delegate { } ) ;
2021-05-29 09:23:05 +12:00
2022-10-23 11:02:31 +13:00
#endif
2021-11-25 07:01:59 +13:00
bool useCustomLocation = Properties . Settings . Default . UseCustomLocation | | lastLocation . X > 0 ;
2021-12-28 00:22:52 +13:00
bool changeDirectionWhenOutOfBounds = true ;
2021-11-25 07:01:59 +13:00
2020-09-21 05:19:21 +12:00
if ( menuPredecessor ! = null )
{
2020-09-21 06:45:12 +12:00
// Ignore start as we use predecessor
2020-09-21 05:19:21 +12:00
startLocation = StartLocation . Predecessor ;
}
2021-12-28 00:22:52 +13:00
else if ( useCustomLocation & & ! isCustomLocationOutsideOfScreen )
2021-11-25 07:01:59 +13:00
{
// Do not adjust location again because Cursor.Postion changed
if ( Tag ! = null )
{
return ;
}
// Use this menu as predecessor and overwrite location with CustomLocation
menuPredecessor = this ;
Tag = new RowData ( ) ;
2022-10-23 11:02:31 +13:00
Left = Properties . Settings . Default . CustomLocationX ;
Top = Properties . Settings . Default . CustomLocationY ;
2021-11-25 07:01:59 +13:00
directionToRight = true ;
startLocation = StartLocation . Predecessor ;
2021-12-28 00:22:52 +13:00
changeDirectionWhenOutOfBounds = false ;
2021-11-25 07:01:59 +13:00
}
2021-04-29 08:58:33 +12:00
else if ( Properties . Settings . Default . AppearAtMouseLocation )
{
2021-06-27 22:24:05 +12:00
// Do not adjust location again because Cursor.Postion changed
if ( Tag ! = null )
{
return ;
}
// Use this menu as predecessor and overwrite location with Cursor.Postion
2021-04-29 08:58:33 +12:00
menuPredecessor = this ;
Tag = new RowData ( ) ;
2022-10-23 11:02:31 +13:00
var position = Mouse . GetPosition ( this ) ;
Left = position . X ;
Top = position . Y - labelTitle . Height ;
2021-04-29 08:58:33 +12:00
directionToRight = true ;
startLocation = StartLocation . Predecessor ;
2021-12-28 00:22:52 +13:00
changeDirectionWhenOutOfBounds = false ;
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 )
{
AdjustSizeAndLocationInternal ( ) ;
}
else
{
// Layout cannot be calculated during loading, postpone this event
// TODO: Make sure lampa capture is registered only once
Loaded + = ( _ , _ ) = > AdjustSizeAndLocationInternal ( ) ;
}
void AdjustSizeAndLocationInternal ( )
2020-06-08 00:28:59 +12:00
{
2022-10-23 11:02:31 +13:00
// Calculate X position
double x ;
switch ( startLocation )
{
case StartLocation . Predecessor :
double scaling = Math . Round ( Scaling . Factor , 0 , MidpointRounding . AwayFromZero ) ;
directionToRight = menuPredecessor ! . directionToRight ; // try keeping same direction
if ( directionToRight )
2020-09-21 06:45:12 +12:00
{
2022-10-23 11:02:31 +13:00
x = menuPredecessor . Location . X + menuPredecessor . Width - scaling ;
if ( changeDirectionWhenOutOfBounds & &
bounds . X + bounds . Width < = x + Width - scaling )
2022-02-23 04:52:02 +13:00
{
2022-10-23 11:02:31 +13:00
x = menuPredecessor . Location . X - Width + scaling ;
if ( x < bounds . X & &
menuPredecessor . Location . X + menuPredecessor . Width < bounds . X + bounds . Width & &
bounds . X + ( bounds . Width / 2 ) > menuPredecessor . Location . 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
{
2022-10-23 11:02:31 +13:00
x = menuPredecessor . Location . X - Width + scaling ;
if ( changeDirectionWhenOutOfBounds & &
x < bounds . X )
2022-02-23 04:52:02 +13:00
{
2022-10-23 11:02:31 +13:00
x = menuPredecessor . Location . X + menuPredecessor . Width - scaling ;
if ( x + Width > bounds . X + bounds . Width & &
menuPredecessor . Location . X > bounds . X & &
bounds . X + ( bounds . Width / 2 ) < menuPredecessor . Location . 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
// X position for click, remove width of this menu as it is used as predecessor
if ( menuPredecessor = = this & & directionToRight )
2022-01-16 02:44:56 +13:00
{
2022-10-23 11:02:31 +13:00
x - = Width ;
2022-01-16 02:44:56 +13:00
}
2022-10-23 11:02:31 +13:00
if ( Level ! = 0 & &
! Properties . Settings . Default . AppearNextToPreviousMenu & &
menuPredecessor ! = null & & menuPredecessor . Width > Properties . Settings . Default . OverlappingOffsetPixels )
{
if ( directionToRight )
2020-09-21 05:19:21 +12:00
{
2022-10-23 11:02:31 +13:00
x = x - menuPredecessor . Width + Properties . Settings . Default . OverlappingOffsetPixels ;
2020-09-21 05:19:21 +12:00
}
2022-10-23 11:02:31 +13:00
else
2021-06-26 23:24:56 +12:00
{
2022-10-23 11:02:31 +13:00
x = x + menuPredecessor . Width - Properties . Settings . Default . OverlappingOffsetPixels ;
2021-06-26 23:24:56 +12:00
}
2022-10-23 11:02:31 +13:00
}
2021-06-26 23:24:56 +12:00
2022-10-23 11:02:31 +13:00
// Calculate Y position
double y ;
switch ( startLocation )
{
case StartLocation . Predecessor :
2020-09-21 05:19:21 +12:00
2022-10-23 11:02:31 +13:00
RowData trigger = ( RowData ) Tag ;
ListView dgv = menuPredecessor ! . GetDataGridView ( ) ! ;
2020-06-08 00:28:59 +12:00
2022-10-23 11:02:31 +13:00
// Set position on same height as the selected row from predecessor
y = menuPredecessor . Location . Y ;
if ( dgv . Items . Count > trigger . RowIndex )
{
2022-12-01 12:16:30 +13:00
// TODO: Optimize calculation and fix calculation for items that are listed "beyond" the initial window size
// When item is not found, it might be invalidated due to resizing or moving
// After updating the layout the location should be available again.
menuPredecessor . UpdateLayout ( ) ;
2022-10-23 11:02:31 +13:00
ListViewItem ? lvi = dgv . FindVisualChildOfType < ListViewItem > ( trigger . RowIndex ) ;
if ( lvi ! = null )
{
2022-12-01 12:16:30 +13:00
double offset ;
ScrollViewer ? scrollViewer = ( VisualTreeHelper . GetChild ( dgv , 0 ) as Decorator ) ? . Child as ScrollViewer ;
if ( scrollViewer ! = null )
{
if ( scrollViewer . VerticalOffset > 0 )
{
offset = 0D ;
for ( int i = 0 ; i < scrollViewer . VerticalOffset ; i + + )
{
ListViewItem ? item = dgv . FindVisualChildOfType < ListViewItem > ( i ) ;
if ( item ! = null )
{
offset + = item . ActualHeight ;
}
}
y - = ( int ) offset ;
}
}
y + = menuPredecessor . GetRelativeChildPositionTo ( dgv ) . Y ;
offset = 0D ;
for ( int i = 0 ; i < trigger . RowIndex ; i + + )
{
ListViewItem ? item = dgv . FindVisualChildOfType < ListViewItem > ( i ) ;
if ( item ! = null )
{
offset + = item . ActualHeight ;
}
}
y + = ( int ) offset ;
2022-10-23 11:02:31 +13:00
}
}
2021-11-14 07:44:32 +13:00
2022-10-23 11:02:31 +13:00
// when warning is shown, the title should appear at same height as selected row
if ( searchPanel . Visibility ! = Visibility . Visible )
{
y + = labelTitle . ActualHeight ;
}
// Move vertically when out of bounds
if ( bounds . Y + bounds . Height < y + Height )
{
y = bounds . Y + bounds . Height - Height ;
}
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
2022-10-23 11:02:31 +13:00
// Update position
Left = x ;
Top = y ;
if ( Properties . 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
// Keep its size when once created.
SizeToContent = SizeToContent . Manual ;
2022-12-01 12:16:30 +13:00
}
2020-06-08 00:28:59 +12:00
}
2022-08-02 10:49:56 +12:00
internal void ResetHeight ( )
{
2022-12-01 12:16:30 +13:00
if ( IsLoaded )
{
// TODO: WPF Check if this "reset" works
SizeToContent = SizeToContent . WidthAndHeight ;
UpdateLayout ( ) ;
SizeToContent = SizeToContent . Manual ;
2022-11-30 10:48:45 +13:00
#if TODO // SEARCH
2022-08-02 10:49:56 +12:00
dgvHeightSet = false ;
2022-10-23 11:02:31 +13:00
#endif
2022-12-01 12:16:30 +13:00
}
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-10-23 11:02:31 +13:00
labelItems . Content = $"{filesAndFoldersCount} {Translator.GetText(elements)}" ;
2021-06-28 01:42:34 +12: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-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-10-23 11:02:31 +13:00
private void AdjustDataGridViewHeight ( Menu menuPredecessor , double screenHeightMax )
2020-09-21 07:47:46 +12:00
{
2021-11-14 04:52:55 +13:00
double factor = Properties . Settings . Default . RowHeighteInPercentage / 100f ;
2020-09-21 07:47:46 +12:00
if ( NativeMethods . IsTouchEnabled ( ) )
{
2021-11-14 04:52:55 +13:00
factor = Properties . 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-11-30 10:48:45 +13:00
#if TODO // SEARCH
2022-10-08 23:50:47 +13:00
if ( ! dgvHeightSet & & dgvHeightByItems > 0 & & dgvHeightMax > 0 )
2020-09-21 07:47:46 +12:00
{
2022-10-23 11:02:31 +13:00
#endif
double heightMaxByOptions = Scaling . Factor * Scaling . FactorByDpi *
450f * ( Properties . Settings . Default . HeightMaxInPercent / 100f ) ;
MaxHeight = Math . Min ( screenHeightMax , heightMaxByOptions ) ;
2022-11-30 10:48:45 +13:00
#if TODO // SEARCH
2022-08-02 10:49:56 +12:00
dgvHeightSet = true ;
2021-06-03 22:52:47 +12:00
}
2022-10-23 11:02:31 +13:00
#endif
2022-11-30 10:48:45 +13:00
#if TODO // SEARCH and TOUCH
2022-08-02 10:49:56 +12:00
if ( dgvHeightByItems > dgvHeightMax )
2021-06-03 22:52:47 +12:00
{
2022-08-02 10:49:56 +12:00
ScrollbarVisible = true ;
2021-06-03 22:52:47 +12:00
}
else
{
2021-12-31 00:36:00 +13:00
ScrollbarVisible = false ;
2021-06-03 22:52:47 +12:00
}
2022-10-23 11:02:31 +13:00
#endif
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-10-23 11:02:31 +13:00
double factorIconSizeInPercent = Properties . Settings . Default . IconSizeInPercent / 100f ;
// 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 ;
}
}
#if TODO // Lazy value setting because of DataBinging but too late for Menues.AdjustSizeAndLocation()
renderedMaxWidth = Math . Min (
renderedMaxWidth ,
( double ) ( Scaling . Factor * Scaling . FactorByDpi * 400f * ( Properties . Settings . Default . WidthMaxInPercent / 100f ) ) ) ;
for ( int i = 0 ; i < dgv . Items . Count ; i + + )
{
ListViewItem ? lvi = dgv . FindVisualChildOfType < ListViewItem > ( i ) ;
if ( lvi ! = null )
{
Label ? columnTextLabel = lvi . FindVisualChildOfType < Label > ( ) ;
if ( columnTextLabel ! = null )
{
columnTextLabel . Content = i . ToString ( ) + " ; " + Width + " ; " + renderedMaxWidth . ToString ( ) ;
columnTextLabel . Width = renderedMaxWidth ;
}
}
}
#else
Resources [ "ColumnTextWidth" ] = Math . Min (
renderedMaxWidth ,
( double ) ( Scaling . Factor * Scaling . FactorByDpi * 400f * ( Properties . Settings . Default . WidthMaxInPercent / 100f ) ) ) ;
#endif
2022-11-26 11:31:20 +13:00
( ( CollectionView ) CollectionViewSource . GetDefaultView ( dgv . ItemsSource ) ) . Filter = null ;
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 )
{
Scrolled ? . Invoke ( ) ;
}
2020-06-08 00:28:59 +12:00
}
2022-12-01 12:16:30 +13:00
2022-11-30 10:48:45 +13:00
#if TODO // SEARCH
2022-02-21 09:35:38 +13:00
private void TextBoxSearch_KeyPress ( object sender , KeyPressEventArgs e )
{
KeyPressCheck ? . Invoke ( sender , e ) ;
}
2022-10-23 11:02:31 +13:00
#endif
2022-11-04 11:35:58 +13:00
private void TextBoxSearch_TextChanged ( )
2020-06-08 00:28:59 +12:00
{
2022-11-30 10:48:45 +13:00
#if TODO // SEARCH
2020-06-08 00:28:59 +12:00
DataTable data = ( DataTable ) dgv . DataSource ;
2022-10-23 11:02:31 +13:00
#endif
string filterField = nameof ( ListViewItemData . ColumnText ) ;
2022-11-30 10:48:45 +13:00
#if TODO // SEARCH
2020-06-29 06:56:03 +12:00
SearchTextChanging ? . Invoke ( ) ;
2020-06-08 00:28:59 +12:00
2022-01-07 01:49:07 +13:00
// Expression reference: https://docs.microsoft.com/en-us/dotnet/api/system.data.datacolumn.expression?view=net-6.0
2022-10-23 11:02:31 +13:00
#endif
2022-01-07 01:49:07 +13:00
// Instead implementing in-string wildcards, simply split into multiple search patters
2021-06-28 00:44:12 +12:00
string searchString = textBoxSearch . Text . Trim ( )
. Replace ( "%" , " " )
. Replace ( "*" , " " ) ;
2022-01-07 01:49:07 +13:00
2022-06-11 23:04:21 +12:00
string searchStringReplaceSpecialCharacters = new ( searchString ) ;
2022-01-07 01:49:07 +13:00
searchString = string . Empty ;
2022-06-11 23:04:21 +12:00
foreach ( char character in searchStringReplaceSpecialCharacters )
2022-01-07 01:49:07 +13:00
{
2022-06-11 23:04:21 +12:00
searchString + = character switch
2022-01-07 01:49:07 +13:00
{
2022-02-06 00:47:27 +13:00
'[' = > "[[]" ,
']' = > "[]]" ,
2022-06-11 23:04:21 +12:00
_ = > character ,
2022-02-06 00:47:27 +13:00
} ;
2022-01-07 01:49:07 +13:00
}
2021-04-15 09:12:14 +12:00
string like = string . Empty ;
string [ ] splittedParts = searchString . Split ( " " ) ;
if ( splittedParts . Length > 1 )
{
foreach ( string splittedPart in splittedParts )
{
string and = string . Empty ;
if ( ! string . IsNullOrEmpty ( like ) )
{
and = $" AND [{filterField}]" ;
}
like + = $"{and} LIKE '%{splittedPart}%'" ;
}
}
else
{
like = $"LIKE '%{searchString}%'" ;
}
2022-01-31 04:52:42 +13:00
bool isSearchStringEmpty = string . IsNullOrEmpty ( searchString ) ;
2022-11-04 11:35:58 +13:00
CollectionView view = ( CollectionView ) CollectionViewSource . GetDefaultView ( dgv . ItemsSource ) ;
if ( isSearchStringEmpty )
{
view . Filter = null ;
}
else
{
view . Filter = SearchFilter ;
bool SearchFilter ( object item )
{
ListViewItemData row = ( ListViewItemData ) item ;
return row . ColumnText . Contains ( textBoxSearch . Text . Trim ( ) ) ; // TODO: THIS IS JUST TEMPORARY DUMMY FILTER (see below)
}
}
2022-11-30 10:48:45 +13:00
#if TODO // SEARCH
2021-04-15 09:12:14 +12:00
try
{
2022-01-08 23:39:23 +13:00
if ( Properties . Settings . Default . ShowOnlyAsSearchResult & &
2022-01-31 04:52:42 +13:00
isSearchStringEmpty )
2022-01-08 23:39:23 +13:00
{
2022-06-18 00:38:09 +12:00
data . DefaultView . RowFilter = RowFilterShowAll ;
2022-01-08 23:39:23 +13:00
}
else
{
data . DefaultView . RowFilter = $"[{filterField}] {like}" ;
}
2021-04-15 09:12:14 +12:00
}
2021-04-17 04:39:21 +12:00
catch ( Exception ex )
2021-04-15 09:12:14 +12:00
{
2021-04-17 04:39:21 +12:00
if ( ex is EvaluateException | |
ex is SyntaxErrorException )
{
Log . Warn ( $"searchString \" { searchString } \ " is a invalid" , ex ) ;
}
else
{
throw ;
}
2021-04-15 09:12:14 +12:00
}
2021-04-15 07:06:54 +12:00
2022-01-08 23:39:23 +13:00
string columnSortIndex = "SortIndex" ;
2022-01-31 04:52:42 +13:00
if ( isSearchStringEmpty )
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-06-18 00:38:09 +12:00
if ( rowData . IsAddionalItem & & Properties . 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-06-18 00:38:09 +12:00
if ( ! isSearchStringEmpty | |
! ( rowData . IsAddionalItem & & Properties . 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 ) ;
2022-06-11 23:04:21 +12:00
SearchTextChanged . Invoke ( this , isSearchStringEmpty ) ;
2021-10-22 08:28:58 +13:00
if ( anyIconNotUpdated )
{
timerUpdateIcons . Start ( ) ;
}
2022-01-31 04:52:42 +13:00
2022-06-11 21:26:47 +12:00
if ( dgv . Rows . Count > 0 )
2022-01-31 04:52:42 +13:00
{
dgv . FirstDisplayedScrollingRowIndex = 0 ;
}
2022-10-23 11:02:31 +13:00
#endif
2020-06-08 00:28:59 +12:00
}
2022-11-30 10:48:45 +13:00
#if TODO // Misc MouseEvents and BorderColors
2021-06-26 23:24:56 +12:00
private void PictureBox_MouseEnter ( object sender , EventArgs e )
{
PictureBox pictureBox = ( PictureBox ) sender ;
pictureBox . BackColor = MenuDefines . ColorSelectedItem ;
pictureBox . Tag = true ;
}
private void PictureBox_MouseLeave ( object sender , EventArgs e )
{
PictureBox pictureBox = ( PictureBox ) sender ;
pictureBox . BackColor = Color . Transparent ;
pictureBox . Tag = false ;
}
private void PictureBox_Resize ( object sender , EventArgs e )
{
PictureBox pictureBox = ( PictureBox ) sender ;
pictureBox . Invalidate ( ) ;
}
2021-11-22 05:24:01 +13:00
private void PictureBoxOpenFolder_Paint ( object sender , PaintEventArgs e )
2021-06-26 23:24:56 +12:00
{
2021-06-27 21:35:07 +12:00
PictureBox pictureBox = ( PictureBox ) sender ;
2021-06-26 23:24:56 +12:00
2021-11-22 05:24:01 +13:00
e . Graphics . DrawImage ( AppColors . BitmapOpenFolder , new Rectangle ( Point . Empty , pictureBox . ClientSize ) ) ;
if ( pictureBox . Tag ! = null & & ( bool ) pictureBox . Tag )
{
Rectangle rowBounds = new ( 0 , 0 , pictureBox . Width , pictureBox . Height ) ;
ControlPaint . DrawBorder ( e . Graphics , rowBounds , MenuDefines . ColorSelectedItemBorder , ButtonBorderStyle . Solid ) ;
}
2021-06-28 00:44:12 +12:00
}
2022-10-23 11:02:31 +13:00
#endif
2021-06-28 00:44:12 +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
{
2022-10-23 11:02:31 +13:00
UserClickedOpenFolder ? . Invoke ( ) ;
2021-06-28 00:44:12 +12:00
}
2022-11-30 10:48:45 +13:00
#if TODO // BorderColors
2021-06-26 23:24:56 +12:00
private void PictureBoxMenuAlwaysOpen_Paint ( object sender , PaintEventArgs e )
{
PictureBox pictureBox = ( PictureBox ) sender ;
if ( pictureBox . Tag ! = null & & ( bool ) pictureBox . Tag )
{
2021-11-17 12:13:46 +13:00
Rectangle rowBounds = new ( 0 , 0 , pictureBox . Width , pictureBox . Height ) ;
2021-06-26 23:24:56 +12:00
ControlPaint . DrawBorder ( e . Graphics , rowBounds , MenuDefines . ColorSelectedItemBorder , ButtonBorderStyle . Solid ) ;
}
}
2022-10-23 11:02:31 +13:00
#endif
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-11-30 10:48:45 +13:00
#if TODO // BorderColors
2021-11-22 05:24:01 +13:00
private void PictureBoxSettings_Paint ( object sender , PaintEventArgs e )
2021-06-26 23:24:56 +12:00
{
PictureBox pictureBox = ( PictureBox ) sender ;
2021-11-22 05:24:01 +13:00
e . Graphics . DrawImage ( AppColors . BitmapSettings , new Rectangle ( Point . Empty , pictureBox . ClientSize ) ) ;
2021-06-26 23:24:56 +12:00
if ( pictureBox . Tag ! = null & & ( bool ) pictureBox . Tag )
{
2021-11-17 12:13:46 +13:00
Rectangle rowBounds = new ( 0 , 0 , pictureBox . Width , pictureBox . Height ) ;
2021-06-26 23:24:56 +12:00
ControlPaint . DrawBorder ( e . Graphics , rowBounds , MenuDefines . ColorSelectedItemBorder , ButtonBorderStyle . Solid ) ;
}
}
2022-10-23 11:02:31 +13:00
#endif
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-11-30 10:48:45 +13:00
#if TODO // BorderColors
2021-11-22 05:24:01 +13:00
private void PictureBoxRestart_Paint ( object sender , PaintEventArgs e )
2021-06-26 23:24:56 +12:00
{
PictureBox pictureBox = ( PictureBox ) sender ;
2021-11-22 05:24:01 +13:00
e . Graphics . DrawImage ( AppColors . BitmapRestart , new Rectangle ( Point . Empty , pictureBox . ClientSize ) ) ;
if ( pictureBox . Tag ! = null & & ( bool ) pictureBox . Tag )
{
Rectangle rowBounds = new ( 0 , 0 , pictureBox . Width , pictureBox . Height ) ;
ControlPaint . DrawBorder ( e . Graphics , rowBounds , MenuDefines . ColorSelectedItemBorder , ButtonBorderStyle . Solid ) ;
}
2021-06-26 23:24:56 +12:00
}
2022-10-23 11:02:31 +13:00
#endif
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-11-30 10:48:45 +13:00
#if TODO // BorderColors
2021-11-22 05:24:01 +13:00
private void PictureBoxSearch_Paint ( object sender , PaintEventArgs e )
{
PictureBox pictureBox = ( PictureBox ) sender ;
e . Graphics . DrawImage ( AppColors . BitmapSearch , new Rectangle ( Point . Empty , pictureBox . ClientSize ) ) ;
}
2022-10-23 11:02:31 +13:00
#endif
private void TimerUpdateIcons_Tick ( object? sender , EventArgs e )
2021-09-24 08:53:46 +12:00
{
int iconsToUpdate = 0 ;
2022-10-23 11:02:31 +13:00
foreach ( Menu . ListViewItemData row in dgv . Items )
2021-09-24 08:53:46 +12:00
{
2022-10-23 11:02:31 +13:00
RowData rowData = row . data ;
rowData . RowIndex = dgv . Items . IndexOf ( row ) ;
2021-09-24 08:53:46 +12:00
if ( rowData . IconLoading )
{
iconsToUpdate + + ;
2022-11-14 07:58:54 +13:00
row . ColumnIcon = rowData . ReadIcon ( false ) . ToImageSource ( ) ;
2021-09-24 08:53:46 +12:00
}
}
if ( iconsToUpdate < 1 )
{
timerUpdateIcons . Stop ( ) ;
}
2022-11-10 11:34:27 +13:00
else
{
( ( CollectionView ) CollectionViewSource . GetDefaultView ( dgv . ItemsSource ) ) . Refresh ( ) ;
}
2021-09-24 08:53:46 +12:00
}
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 ( ) ;
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-10-23 11:02:31 +13:00
Properties . Settings . Default . CustomLocationX = ( int ) Left ;
Properties . 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 ;
2021-12-27 18:31:23 +13:00
if ( Properties . Settings . Default . UseCustomLocation )
{
2022-10-23 11:02:31 +13:00
if ( ! SettingsWindow . IsOpen ( ) )
2021-12-27 18:31:23 +13:00
{
Properties . Settings . Default . Save ( ) ;
}
}
2021-11-25 07:01:59 +13:00
}
2022-10-23 11:02:31 +13:00
private void ListViewItem_MouseEnter ( object sender , MouseEventArgs e )
{
2022-11-30 10:48:45 +13:00
CellMouseEnter ? . Invoke ( dgv , dgv . IndexOfSenderItem ( ( ListViewItem ) sender ) ) ;
2022-10-23 11:02:31 +13:00
}
private void ListViewItem_MouseLeave ( object sender , MouseEventArgs e )
{
2022-11-30 10:48:45 +13:00
CellMouseLeave ? . Invoke ( dgv , dgv . IndexOfSenderItem ( ( ListViewItem ) sender ) ) ;
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
{
2022-11-30 10:48:45 +13:00
CellMouseDown ? . Invoke ( dgv , dgv . IndexOfSenderItem ( ( ListViewItem ) sender ) , e ) ;
2022-10-23 11:02:31 +13:00
}
private void ListViewItem_MouseUp ( object sender , MouseButtonEventArgs e )
{
2022-11-30 10:48:45 +13:00
CellMouseUp ? . Invoke ( dgv , dgv . IndexOfSenderItem ( ( ListViewItem ) sender ) , e ) ;
2022-10-23 11:02:31 +13:00
}
private void ListViewxItem_PreviewMouseLeftButtonDown ( object sender , MouseButtonEventArgs e )
{
2022-11-30 10:48:45 +13:00
CellMouseClick ? . Invoke ( dgv , dgv . IndexOfSenderItem ( ( ListViewItem ) sender ) , e ) ;
2022-10-23 11:02:31 +13:00
}
/// <summary>
/// Type for ListView items.
/// </summary>
internal class ListViewItemData
{
2022-11-14 07:58:54 +13:00
public ListViewItemData ( ImageSource columnIcon , string columnText , RowData rowData , int sortIndex )
2022-10-23 11:02:31 +13:00
{
ColumnIcon = columnIcon ;
ColumnText = columnText ;
data = rowData ;
SortIndex = sortIndex ;
}
2022-11-14 07:58:54 +13:00
public ImageSource ColumnIcon { get ; set ; }
2022-10-23 11:02:31 +13:00
public string ColumnText { get ; set ; }
[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")]
public RowData data { get ; set ; }
public int SortIndex { get ; set ; }
}
private void textBoxSearch_TextInput ( object sender , TextCompositionEventArgs e )
{
// TODO WPF
}
2020-06-08 00:28:59 +12:00
}
2022-10-23 11:02:31 +13:00
}