Change Game Filter Text to PlaceHolder Text

- Removed the game search label in favor of textbox placeholder text.
 - Added methods to ensure the placeholder text renders properly
- Added inline comments to explain what NativeMethods is for
This commit is contained in:
Frog
2026-05-25 02:35:50 -07:00
parent fe55efc072
commit b7067c2621
2 changed files with 44 additions and 14 deletions
+3 -14
View File
@@ -33,7 +33,6 @@ namespace CreamInstaller.Forms
saveButton = new Button();
uninstallAllButton = new Button();
selectionTreeView = new CustomTreeView();
filterLabel = new System.Windows.Forms.Label();
filterTextBox = new System.Windows.Forms.TextBox();
groupBox.SuspendLayout();
allCheckBoxFlowPanel.SuspendLayout();
@@ -53,21 +52,13 @@ namespace CreamInstaller.Forms
acceptButton.Text = "OK";
acceptButton.UseVisualStyleBackColor = true;
//
// filterLabel
//
filterLabel.AutoSize = true;
filterLabel.Location = new System.Drawing.Point(12, 17);
filterLabel.Name = "filterLabel";
filterLabel.Size = new System.Drawing.Size(68, 15);
filterLabel.TabIndex = 1008;
filterLabel.Text = "Game search:";
//
// filterTextBox
//
filterTextBox.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
filterTextBox.Location = new System.Drawing.Point(100, 14);
filterTextBox.Location = new System.Drawing.Point(12, 14);
filterTextBox.Name = "filterTextBox";
filterTextBox.Size = new System.Drawing.Size(436, 23);
filterTextBox.PlaceholderText = "Enter the name of a game to search";
filterTextBox.Size = new System.Drawing.Size(524, 23);
filterTextBox.TabIndex = 0;
filterTextBox.TextChanged += OnFilterTextChanged;
//
@@ -209,7 +200,6 @@ namespace CreamInstaller.Forms
Controls.Add(acceptButton);
Controls.Add(groupBox);
Controls.Add(filterTextBox);
Controls.Add(filterLabel);
FormBorderStyle = FormBorderStyle.FixedSingle;
MaximizeBox = false;
MinimizeBox = false;
@@ -237,7 +227,6 @@ namespace CreamInstaller.Forms
private Button saveButton;
private CheckBox sortCheckBox;
private Button uninstallAllButton;
private System.Windows.Forms.Label filterLabel;
private System.Windows.Forms.TextBox filterTextBox;
}
}
+41
View File
@@ -211,6 +211,7 @@ internal static class ThemeManager
tb.BackColor = DarkBackAlt;
tb.ForeColor = DarkFore;
tb.BorderStyle = BorderStyle.FixedSingle;
NativeMethods.RefreshCueBanner(tb);
break;
// Layout panels set a consistent background
@@ -269,6 +270,7 @@ internal static class ThemeManager
tb.BackColor = LightBackAlt;
tb.ForeColor = LightFore;
tb.BorderStyle = BorderStyle.Fixed3D;
NativeMethods.RefreshCueBanner(tb);
break;
case TableLayoutPanel tlp:
tlp.BackColor = LightBack;
@@ -462,15 +464,54 @@ internal static class ThemeManager
}
}
/// <summary>
/// Wraps Win32 API calls that have no managed equivalent in WinForms.
/// These P/Invoke declarations are required because .NET does not expose
/// the underlying Windows messages or DWM attributes through its own APIs.
/// </summary>
internal static class NativeMethods
{
// DWM attribute index for enabling/disabling the immersive dark title bar.
// Documented in dwmapi.h; value 20 corresponds to DWMWA_USE_IMMERSIVE_DARK_MODE
// (Windows 10 build 19041+ / Windows 11).
private const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20;
// DwmSetWindowAttribute allows setting per-window Desktop Window Manager attributes.
// We use it here to flip the title bar to dark or light depending on the active theme,
// since WinForms has no built-in API to control title bar coloring.
[System.Runtime.InteropServices.DllImport("dwmapi.dll")]
private static extern int DwmSetWindowAttribute(System.IntPtr hwnd, int attr, ref int attrValue, int attrSize);
/// <summary>
/// Toggles the dark/light title bar chrome for the given window handle.
/// Pass <c>1</c> for dark mode, <c>0</c> for light mode.
/// </summary>
internal static void EnableDarkTitleBar(System.IntPtr handle, int useDark)
{
_ = DwmSetWindowAttribute(handle, DWMWA_USE_IMMERSIVE_DARK_MODE, ref useDark, sizeof(int));
}
// Win32 Edit control message that sets or updates the cue (placeholder) banner text.
// WinForms sets PlaceholderText once at creation time via this same message internally,
// but does not re-send it when the control's colors change. When we restyle a TextBox
// for dark/light mode the cue banner can disappear, so we must re-send the message
// manually to make the placeholder visible again.
private const int EM_SETCUEBANNER = 0x1501;
// SendMessage is the standard Win32 mechanism for posting messages directly to a
// window/control handle. We use the Unicode variant so the placeholder string is
// transmitted without any ANSI conversion.
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
private static extern System.IntPtr SendMessage(System.IntPtr hWnd, int msg, System.IntPtr wParam, string lParam);
/// <summary>
/// Re-sends <c>EM_SETCUEBANNER</c> to the given TextBox so its placeholder text
/// is redrawn after a theme change has altered the control's background or foreground colors.
/// Does nothing if the control handle has not yet been created or the placeholder is empty.
/// </summary>
internal static void RefreshCueBanner(System.Windows.Forms.TextBox textBox)
{
if (textBox?.IsHandleCreated == true && textBox.PlaceholderText is { Length: > 0 })
SendMessage(textBox.Handle, EM_SETCUEBANNER, (System.IntPtr)1, textBox.PlaceholderText);
}
}