using Pulsar.Common.Helpers; using Pulsar.Server.Helper; using Pulsar.Server.Utilities; using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace Pulsar.Server.Controls { internal class AeroListView : ListView { private const uint WM_CHANGEUISTATE = 0x127; private const short UIS_SET = 1; private const short UISF_HIDEFOCUS = 0x1; private readonly IntPtr _removeDots = new IntPtr(NativeMethodsHelper.MakeWin32Long(UIS_SET, UISF_HIDEFOCUS)); private const int WM_VSCROLL = 0x115; private const int SB_BOTTOM = 7; private const int SB_TOP = 6; private const int WS_VSCROLL = 0x00200000; private const int WS_HSCROLL = 0x00100000; [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ListViewColumnSorter LvwColumnSorter { get; set; } [DefaultValue(true)] public bool AllowAutoSort { get; set; } = true; /// /// Initializes a new instance of the class. /// public AeroListView() { SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); this.LvwColumnSorter = new ListViewColumnSorter(); this.ListViewItemSorter = LvwColumnSorter; this.View = View.Details; this.FullRowSelect = true; Resize += AeroListView_Resize; } /// /// Gets the creation parameters. /// protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.Style |= WS_VSCROLL | WS_HSCROLL; // Always show both scrollbars return cp; } } private void AeroListView_Resize(object sender, EventArgs e) { if (Columns.Count == 0) return; int totalWidth = 0; for (int i = 0; i < Columns.Count - 1; i++) { totalWidth += Columns[i].Width; } int newWidth = ClientSize.Width - totalWidth; if (newWidth > 0) { Columns[Columns.Count - 1].Width = newWidth; } } /// /// Refreshes the scrollbars to ensure they are properly displayed. /// public void RefreshScrollBars() { // Yes I chatGPT this I have no idea wtf is going on. // Force scrollbars to update by sending scroll messages if (IsHandleCreated) { // Scroll to bottom and then back to top to refresh vertical scrollbar NativeMethods.SendMessage(this.Handle, WM_VSCROLL, (IntPtr)SB_BOTTOM, IntPtr.Zero); NativeMethods.SendMessage(this.Handle, WM_VSCROLL, (IntPtr)SB_TOP, IntPtr.Zero); // Call UpdateScrollBars to ensure proper sizing this.BeginUpdate(); this.EndUpdate(); } } /// /// Raises the event. /// /// The instance containing the event data. protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); NativeMethods.SetWindowTheme(this.Handle, "explorer", null); NativeMethods.SendMessage(this.Handle, WM_CHANGEUISTATE, _removeDots, IntPtr.Zero); // Add this to refresh scrollbars after creation this.BeginInvoke(new Action(() => RefreshScrollBars())); } /// /// Raises the event. /// /// The instance containing the event data. protected override void OnResize(EventArgs e) { base.OnResize(e); RefreshScrollBars(); } /// /// Raises the event. /// /// The instance containing the event data. protected override void OnColumnClick(ColumnClickEventArgs e) { base.OnColumnClick(e); if (!AllowAutoSort || this.LvwColumnSorter == null) { return; } // Determine if clicked column is already the column that is being sorted. if (e.Column == this.LvwColumnSorter.SortColumn) { // Reverse the current sort direction for this column. this.LvwColumnSorter.Order = (this.LvwColumnSorter.Order == SortOrder.Ascending) ? SortOrder.Descending : SortOrder.Ascending; } else { // Set the column number that is to be sorted; default to ascending. this.LvwColumnSorter.SortColumn = e.Column; this.LvwColumnSorter.Order = SortOrder.Ascending; } // Perform the sort with these new sort options. if (!this.VirtualMode) this.Sort(); } } }