using System; using System.Drawing; using System.Linq; using System.Reflection; using System.Windows.Forms; using SystemTrayMenu.DataClasses; using SystemTrayMenu.Helper.Taskbar; using SystemTrayMenu.Utilities; using EventHandler = SystemTrayMenu.Helper.EventHandler; namespace SystemTrayMenu.UserInterface { public partial class Menu : Form { public new event EventHandler MouseWheel; public event EventHandler Deactivated; public event EventHandler UserClickedOpenFolder; public event Action CmdKeyProcessed; public enum Type { Main, Sub, Empty, NoAccess, MaxReached } public bool IsFadingIn => FadeForm.IsFadingIn; public bool IsFadingOut => FadeForm.IsFadingOut; internal int Level = 0; private readonly FadeForm FadeForm = null; private bool autoResizeRowsDone = false; public enum MenuType { Default, DisposedFake }; public Menu(MenuType menuType = MenuType.Default) { FadeForm = new FadeForm(this); InitializeComponent(); SetDoubleBuffer(dgv, true); DataGridViewCellStyle dgvCellStyle = new DataGridViewCellStyle { SelectionBackColor = MenuDefines.ColorSelectedItem, SelectionForeColor = Color.Black }; dgv.DefaultCellStyle = dgvCellStyle; VScrollBar scrollBar = dgv.Controls.OfType().First(); scrollBar.MouseWheel += dgv_MouseWheel; if (menuType == MenuType.DisposedFake) { Dispose(); } } private static void SetDoubleBuffer(Control ctl, bool DoubleBuffered) { typeof(Control).InvokeMember("DoubleBuffered", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, ctl, new object[] { DoubleBuffered }, System.Globalization.CultureInfo.InvariantCulture); } public void SetTypeSub() { SetType(Type.Sub); } public void SetTypeEmpty() { SetType(Type.Empty); } public void SetTypeNoAccess() { SetType(Type.NoAccess); } public void SetType(Type type) { switch (type) { case Type.Sub: if (!labelTitle.IsDisposed) { labelTitle.Dispose(); } break; case Type.Empty: SetTitle(Language.Translate("Folder empty")); labelTitle.BackColor = MenuDefines.ColorTitleWarning; break; case Type.NoAccess: SetTitle(Language.Translate("Folder inaccessible")); labelTitle.BackColor = MenuDefines.ColorTitleWarning; break; case Type.MaxReached: SetTitle($"Max {MenuDefines.MenusMax - 1} Menus"); labelTitle.BackColor = MenuDefines.ColorTitleWarning; break; case Type.Main: break; default: break; } } public bool IsVisible() { return Visible; } public bool IsActive(Form activeForm) { bool isActive = (this == activeForm); return isActive; } public bool IsMouseOn(Point mousePosition) { bool isMouseOn = Visible && Opacity >= MenuDefines.OpacityHalfValue && ClientRectangle.Contains( PointToClient(mousePosition)); return isMouseOn; } public DataGridView GetDataGridView() { return dgv; } public void SetTitle(string title) { if (!string.IsNullOrEmpty(title)) { if (title.Length > MenuDefines.LengthMax) { title = $"{title.Substring(0, MenuDefines.LengthMax)}..."; } labelTitle.Text = title; } } public void FadeIn() { FadeForm.FadeIn(); } public void FadeHalf() { FadeForm.FadeHalf(); } public void FadeOut() { FadeForm.FadeOut(); } public void AdjustLocationAndSize(Screen screen) { if (screen != null) { DataGridViewElementStates states = DataGridViewElementStates.None; dgv.AutoResizeRows(); int height = dgv.Rows.GetRowsHeight(states); int heightMax = screen.Bounds.Height - new Taskbar().Size.Height - labelTitle.Height; if (height > heightMax) { height = heightMax; } dgv.Height = height; AdjustDataGridViewSize(); int x = screen.Bounds.Right - Width; int y = heightMax - Height + labelTitle.Height; Location = new Point(x, y); } } public void AdjustLocationAndSize(int heightMax, Menu menuPredecessor) { DataGridViewElementStates states = DataGridViewElementStates.None; if (!autoResizeRowsDone) { autoResizeRowsDone = true; this.dgv.AutoResizeRows(); } int height = this.dgv.Rows.GetRowsHeight(states); if (height > heightMax) { height = heightMax; } this.dgv.Height = height; AdjustDataGridViewSize(); int x = menuPredecessor.Location.X - Width + (int)Math.Round(Scaling.Factor, 0, MidpointRounding.AwayFromZero); RowData trigger = (RowData)Tag; DataGridView dgv = menuPredecessor.GetDataGridView(); if (dgv.Rows.Count > trigger.RowIndex) { Rectangle cellRectangle = dgv.GetCellDisplayRectangle( 0, trigger.RowIndex, false); int y = menuPredecessor.Location.Y + menuPredecessor.dgv.Location.Y + cellRectangle.Top; if ((y + Height) > heightMax) { y = heightMax - Height; } Location = new Point(x, y); } } private void AdjustDataGridViewSize() { //dgv.AutoResizeColumns(); //AutoResizeColumns slow ~45ms DataGridViewExtensions.FastAutoSizeColumns(dgv); bool scrollbarShown = false; foreach (VScrollBar scroll in dgv.Controls.OfType()) { if (scroll.Visible) { scroll.Width = 120; scrollbarShown = true; } } int newWidth = dgv.Columns[0].Width + dgv.Columns[1].Width; if (scrollbarShown) { newWidth += SystemInformation.VerticalScrollBarWidth; } dgv.Width = newWidth; } 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; } } MouseWheel.Invoke(); } private void Menu_Deactivate(object sender, EventArgs e) { Deactivated?.Invoke(); } public void SetTitleColorDeactive() { labelTitle.ForeColor = Color.LightGray; } public void SetTitleColorActive() { labelTitle.ForeColor = Color.Black; } 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; } private void LabelTitle_MouseLeave(object sender, EventArgs e) { labelTitle.BackColor = MenuDefines.ColorTitleBackground; } protected override CreateParams CreateParams { get { CreateParams Params = base.CreateParams; 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: CmdKeyProcessed.Invoke(keys); return true; default: break; } return base.ProcessCmdKey(ref msg, keys); } } }