SystemTrayMenu/UserInterface/Menu.cs

483 lines
15 KiB
C#
Raw Normal View History

2019-07-05 05:04:14 +12:00
using System;
2020-05-14 05:14:51 +12:00
using System.Data;
2019-07-05 05:04:14 +12:00
using System.Drawing;
2020-05-14 05:14:51 +12:00
using System.Globalization;
2019-07-05 05:04:14 +12:00
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.DllImports;
using SystemTrayMenu.Utilities;
2019-07-05 05:04:14 +12:00
namespace SystemTrayMenu.UserInterface
2019-07-05 05:04:14 +12:00
{
internal partial class Menu : Form
2019-07-05 05:04:14 +12:00
{
internal new event EventHandlerEmpty MouseWheel;
internal new event EventHandlerEmpty MouseEnter;
internal new event EventHandlerEmpty MouseLeave;
internal event EventHandlerEmpty UserClickedOpenFolder;
2020-05-14 05:14:51 +12:00
internal event EventHandler<Keys> CmdKeyProcessed;
internal event EventHandlerEmpty SearchTextChanging;
internal event EventHandler SearchTextChanged;
#warning #68 => use event and not a action here?
2019-07-05 05:04:14 +12:00
internal bool IsUsable => Visible && !fading.IsHiding &&
!IsDisposed && !Disposing;
internal enum MenuType
2019-07-05 05:04:14 +12:00
{
Main,
Sub,
Empty,
NoAccess,
2019-07-05 05:04:14 +12:00
MaxReached
}
internal int Level = 0;
private readonly Fading fading = new Fading();
2020-06-06 21:47:19 +12:00
private bool isShowing = false;
private bool dgvAutoResizeRowDone = false;
2020-04-08 05:29:02 +12:00
internal Menu()
2019-07-05 05:04:14 +12:00
{
fading.ChangeOpacity += Fading_ChangeOpacity;
void Fading_ChangeOpacity(object sender, double newOpacity)
{
Opacity = newOpacity;
}
fading.Show += Fading_Show;
void Fading_Show()
{
if (Level == 0)
{
try
{
2020-04-30 23:22:47 +12:00
isShowing = true;
Visible = true;
2020-04-30 23:22:47 +12:00
isShowing = false;
}
catch (ObjectDisposedException)
{
Visible = false;
2020-04-30 23:22:47 +12:00
isShowing = false;
Log.Info($"Could not open menu, old menu was disposing," +
$" IsDisposed={IsDisposed}");
}
if (Visible)
{
Activate();
2020-05-14 05:14:51 +12:00
textBoxSearch.Focus();
2020-04-30 23:22:47 +12:00
NativeMethods.User32ShowInactiveTopmost(this);
NativeMethods.ForceForegroundWindow(Handle);
SetTitleColorActive();
}
}
else
{
NativeMethods.User32ShowInactiveTopmost(this);
2020-05-14 05:14:51 +12:00
textBoxSearch.Focus();
}
}
fading.Hide += Hide;
2019-07-05 05:04:14 +12:00
InitializeComponent();
2020-05-07 02:38:05 +12:00
pictureBoxSearch.Paint += PictureBoxSearch_Paint;
void PictureBoxSearch_Paint(object sender, PaintEventArgs e)
{
2020-05-14 05:14:51 +12:00
e.Graphics.DrawIcon(Properties.Resources.search2,
2020-05-07 02:38:05 +12:00
new Rectangle(0, 0, pictureBoxSearch.Width, pictureBoxSearch.Height));
}
2019-07-05 05:04:14 +12:00
SetDoubleBuffer(dgv, true);
DataGridViewCellStyle dgvCellStyle = new DataGridViewCellStyle
{
SelectionBackColor = MenuDefines.ColorSelectedItem,
SelectionForeColor = Color.Black
};
dgv.DefaultCellStyle = dgvCellStyle;
2020-03-14 02:31:31 +13:00
VScrollBar scrollBar = dgv.Controls.OfType<VScrollBar>().First();
scrollBar.MouseWheel += dgv_MouseWheel;
scrollBar.MouseEnter += ControlsMouseEnter;
dgv.MouseEnter += ControlsMouseEnter;
labelTitle.MouseEnter += ControlsMouseEnter;
void ControlsMouseEnter(object sender, EventArgs e)
{
MouseEnter.Invoke();
}
scrollBar.MouseLeave += ControlsMouseLeave;
dgv.MouseLeave += ControlsMouseLeave;
labelTitle.MouseLeave += ControlsMouseLeave;
void ControlsMouseLeave(object sender, EventArgs e)
{
MouseLeave.Invoke();
}
2019-07-05 05:04:14 +12:00
}
2020-05-14 05:14:51 +12:00
internal void FocusTextBox()
{
textBoxSearch.Focus();
}
private static void SetDoubleBuffer(Control ctl, bool DoubleBuffered)
2019-07-05 05:04:14 +12:00
{
typeof(Control).InvokeMember("DoubleBuffered",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty,
null, ctl, new object[] { DoubleBuffered },
2020-05-14 05:14:51 +12:00
CultureInfo.InvariantCulture);
2019-07-05 05:04:14 +12:00
}
internal void SetTypeSub()
2019-07-05 05:04:14 +12:00
{
SetType(MenuType.Sub);
2019-07-05 05:04:14 +12:00
}
internal void SetTypeEmpty()
2019-07-05 05:04:14 +12:00
{
SetType(MenuType.Empty);
2019-07-05 05:04:14 +12:00
}
internal void SetTypeNoAccess()
{
SetType(MenuType.NoAccess);
}
2019-07-05 05:04:14 +12:00
internal void SetType(MenuType type)
2019-07-05 05:04:14 +12:00
{
switch (type)
{
case MenuType.Sub:
2019-07-05 05:04:14 +12:00
if (!labelTitle.IsDisposed)
{
labelTitle.Dispose();
}
break;
case MenuType.Empty:
2020-05-05 05:43:47 +12:00
SetTitle(Translator.GetText("Folder empty"));
labelTitle.BackColor = MenuDefines.ColorTitleWarning;
this.pictureBoxSearch.Visible = false;
this.textBoxSearch.Visible = false;
this.tableLayoutPanelSearch.Visible = false;
2019-07-05 05:04:14 +12:00
break;
case MenuType.NoAccess:
2020-05-05 05:43:47 +12:00
SetTitle(Translator.GetText("Folder inaccessible"));
labelTitle.BackColor = MenuDefines.ColorTitleWarning;
this.pictureBoxSearch.Visible = false;
this.textBoxSearch.Visible = false;
this.tableLayoutPanelSearch.Visible = false;
break;
case MenuType.MaxReached:
2019-07-05 05:04:14 +12:00
SetTitle($"Max {MenuDefines.MenusMax - 1} Menus");
labelTitle.BackColor = MenuDefines.ColorTitleWarning;
this.pictureBoxSearch.Visible = false;
this.textBoxSearch.Visible = false;
this.tableLayoutPanelSearch.Visible = false;
2019-07-05 05:04:14 +12:00
break;
case MenuType.Main:
2019-07-05 05:04:14 +12:00
break;
default:
break;
}
}
internal bool IsMouseOn(Point mousePosition)
2019-07-05 05:04:14 +12:00
{
bool isMouseOn = Visible && ClientRectangle.Contains(
2019-07-05 05:04:14 +12:00
PointToClient(mousePosition));
return isMouseOn;
}
internal DataGridView GetDataGridView()
2019-07-05 05:04:14 +12:00
{
return dgv;
}
internal void SetTitle(string title)
2019-07-05 05:04:14 +12:00
{
if (!string.IsNullOrEmpty(title))
2019-07-05 05:04:14 +12:00
{
if (title.Length > MenuDefines.LengthMax)
{
title = $"{title.Substring(0, MenuDefines.LengthMax)}...";
}
labelTitle.Text = title;
2019-07-05 05:04:14 +12:00
}
}
internal void ShowWithFadeOrTransparent(bool formActiveFormIsMenu)
{
if (formActiveFormIsMenu)
{
ShowWithFade();
}
else
{
ShowTransparent();
}
}
internal void ShowWithFade()
2019-07-05 05:04:14 +12:00
{
fading.Fade(Fading.FadingState.Show);
2019-07-05 05:04:14 +12:00
}
internal void ShowTransparent()
2019-07-05 05:04:14 +12:00
{
fading.Fade(Fading.FadingState.ShowTransparent);
2019-07-05 05:04:14 +12:00
}
internal void HideWithFade()
2019-07-05 05:04:14 +12:00
{
2020-05-14 05:14:51 +12:00
if (!isShowing)
2020-04-30 23:22:47 +12:00
{
fading.Fade(Fading.FadingState.Hide);
}
2019-07-05 05:04:14 +12:00
}
internal void AdjustSizeAndLocation(Menu menuPredecessor = null,
bool directionToRight = false)
2019-07-05 05:04:14 +12:00
{
2020-06-06 21:47:19 +12:00
if (!dgvAutoResizeRowDone)
{
dgv.AutoResizeRows();
dgvAutoResizeRowDone = true;
}
2019-07-05 05:04:14 +12:00
2020-05-06 12:39:38 +12:00
int dgvHeightNeeded = dgv.Rows.GetRowsHeight(
DataGridViewElementStates.None);
int menuRestNeeded = Height - dgv.Height;
int dgvHeightMax = Statics.ScreenHeight - Statics.TaskbarHeight -
menuRestNeeded;
if (dgvHeightNeeded > dgvHeightMax)
2019-07-05 05:04:14 +12:00
{
2020-05-06 12:39:38 +12:00
dgvHeightNeeded = dgvHeightMax;
2019-07-05 05:04:14 +12:00
}
2020-05-14 05:14:51 +12:00
DataTable data = (DataTable)dgv.DataSource;
if (string.IsNullOrEmpty(data.DefaultView.RowFilter))
{
dgv.Height = dgvHeightNeeded;
}
2019-07-05 05:04:14 +12:00
2020-05-06 12:39:38 +12:00
AdjustDataGridViewWidth();
2019-07-05 05:04:14 +12:00
2020-05-06 12:39:38 +12:00
int x;
if (menuPredecessor == null)
{
x = Statics.ScreenRight - Width;
}
else
{
if (directionToRight)
{
x = menuPredecessor.Location.X + Width -
(int)Math.Round(Scaling.Factor, 0,
MidpointRounding.AwayFromZero);
}
else
{
x = menuPredecessor.Location.X - Width +
(int)Math.Round(Scaling.Factor, 0,
MidpointRounding.AwayFromZero);
}
}
if (x < 0)
{
x += menuPredecessor.Width;
x += Width;
2020-05-06 12:39:38 +12:00
}
int y;
if (menuPredecessor == null)
{
y = Statics.ScreenHeight - Statics.TaskbarHeight - Height;
2020-05-14 05:14:51 +12:00
}
2020-05-06 12:39:38 +12:00
else
2019-07-05 05:04:14 +12:00
{
2020-05-06 12:39:38 +12:00
RowData trigger = (RowData)Tag;
DataGridView dgv = menuPredecessor.GetDataGridView();
2020-05-14 05:14:51 +12:00
int distanceToDgvTop = 0;
2020-05-15 02:48:16 +12:00
if (dgv.Rows.Count > trigger.RowIndex)
2020-05-14 05:14:51 +12:00
{
Rectangle cellRectangle = dgv.GetCellDisplayRectangle(
0, trigger.RowIndex, false);
distanceToDgvTop = cellRectangle.Top;
}
2020-05-06 12:39:38 +12:00
y = menuPredecessor.Location.Y +
2019-07-05 05:04:14 +12:00
menuPredecessor.dgv.Location.Y +
2020-05-14 05:14:51 +12:00
distanceToDgvTop;
2020-05-06 12:39:38 +12:00
if ((y + Height) > dgvHeightMax)
2019-07-05 05:04:14 +12:00
{
2020-05-06 12:39:38 +12:00
y = dgvHeightMax - Height + menuRestNeeded;
2019-07-05 05:04:14 +12:00
}
}
2020-05-06 12:39:38 +12:00
Location = new Point(x, y);
2019-07-05 05:04:14 +12:00
}
2020-05-06 12:39:38 +12:00
private void AdjustDataGridViewWidth()
2019-07-05 05:04:14 +12:00
{
2020-03-14 02:31:31 +13:00
DataGridViewExtensions.FastAutoSizeColumns(dgv);
2020-05-06 12:39:38 +12:00
int newWidth = dgv.Columns[0].Width + dgv.Columns[1].Width;
if (IsScrollbarShown())
{
newWidth += SystemInformation.VerticalScrollBarWidth;
}
if (labelTitle.Width > newWidth)
{
dgv.Width = labelTitle.Width;
dgv.Columns[1].Width = labelTitle.Width - dgv.Columns[0].Width;
}
else
{
dgv.Width = newWidth;
}
2020-05-06 12:39:38 +12:00
//Only scaling correct with Sans Serif for textBoxSearch. Workaround:
textBoxSearch.Font = new Font("Segoe UI", 8.25F * Scaling.Factor,
2020-05-14 05:14:51 +12:00
FontStyle.Regular, GraphicsUnit.Point, 0);
2020-03-14 02:31:31 +13:00
2020-05-06 12:39:38 +12:00
//Ancor not working like in the label
textBoxSearch.Width = newWidth -
pictureBoxSearch.Width -
pictureBoxSearch.Margin.Horizontal -
textBoxSearch.Margin.Horizontal;
}
private bool IsScrollbarShown()
{
bool isScrollbarShown = false;
foreach (VScrollBar scroll in dgv.Controls.OfType<VScrollBar>())
2019-07-05 05:04:14 +12:00
{
if (scroll.Visible)
{
2020-05-06 12:39:38 +12:00
isScrollbarShown = true;
2019-07-05 05:04:14 +12:00
}
}
2020-05-06 12:39:38 +12:00
return isScrollbarShown;
2019-07-05 05:04:14 +12:00
}
private void dgv_MouseWheel(object sender, MouseEventArgs e)
{
((HandledMouseEventArgs)e).Handled = true;
int scrollspeed = MenuDefines.Scrollspeed;
if (e.Delta < 0)
{
if (dgv.FirstDisplayedScrollingRowIndex < dgv.Rows.Count - scrollspeed)
{
dgv.FirstDisplayedScrollingRowIndex += scrollspeed;
}
else
{
dgv.FirstDisplayedScrollingRowIndex = dgv.Rows.Count - 1;
}
}
else
{
if (dgv.FirstDisplayedScrollingRowIndex > 0 + scrollspeed)
{
dgv.FirstDisplayedScrollingRowIndex -= scrollspeed;
}
else
{
dgv.FirstDisplayedScrollingRowIndex = 0;
}
}
2020-06-06 21:47:19 +12:00
MouseWheel?.Invoke();
2019-07-05 05:04:14 +12:00
}
internal void SetTitleColorDeactive()
2019-07-05 05:04:14 +12:00
{
labelTitle.ForeColor = Color.LightGray;
2019-07-05 05:04:14 +12:00
}
internal void SetTitleColorActive()
2019-07-05 05:04:14 +12:00
{
labelTitle.ForeColor = Color.Black;
2019-07-05 05:04:14 +12:00
}
private void LabelTitle_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
UserClickedOpenFolder?.Invoke();
}
}
private void LabelTitle_MouseEnter(object sender, EventArgs e)
{
labelTitle.BackColor = MenuDefines.ColorTitleSelected;
2019-07-05 05:04:14 +12:00
}
private void LabelTitle_MouseLeave(object sender, EventArgs e)
{
labelTitle.BackColor = MenuDefines.ColorTitleBackground;
2019-07-05 05:04:14 +12:00
}
protected override CreateParams CreateParams
{
get
{
CreateParams Params = base.CreateParams;
2019-07-05 05:04:14 +12:00
Params.ExStyle |= 0x80;
return Params;
}
}
protected override bool ProcessCmdKey(ref Message msg, Keys keys)
{
switch (keys)
{
case Keys.Enter:
case Keys.Up:
case Keys.Down:
case Keys.Left:
case Keys.Right:
case Keys.Escape:
2020-05-14 05:14:51 +12:00
case Keys.Control | Keys.F:
case Keys.Tab:
case Keys.Tab | Keys.Shift:
case Keys.Apps:
2020-05-14 05:14:51 +12:00
CmdKeyProcessed.Invoke(this, keys);
2019-07-05 05:04:14 +12:00
return true;
default:
break;
}
return base.ProcessCmdKey(ref msg, keys);
}
2020-05-14 05:14:51 +12:00
private void textBoxSearch_TextChanged(object sender, EventArgs e)
{
DataTable data = (DataTable)dgv.DataSource;
string filterField = dgv.Columns[1].Name;
SearchTextChanging.Invoke();
data.DefaultView.RowFilter = string.Format(CultureInfo.InvariantCulture,
"[{0}] LIKE '%{1}%'", filterField, textBoxSearch.Text);
foreach (DataGridViewRow row in dgv.Rows)
{
RowData rowData = (RowData)row.Cells[2].Value;
rowData.RowIndex = row.Index;
}
SearchTextChanged.Invoke(this, null);
}
internal void KeyPressedSearch(string letter)
{
textBoxSearch.Text += letter;
textBoxSearch.SelectionStart = textBoxSearch.Text.Length;
textBoxSearch.SelectionLength = 0;
textBoxSearch.Focus();
}
2019-07-05 05:04:14 +12:00
}
}