#region Imports using DPumpHydr.WinFrmUI.RLT.Drawing.Poison; using DPumpHydr.WinFrmUI.RLT.Enum.Poison; using DPumpHydr.WinFrmUI.RLT.Extension.Poison; using DPumpHydr.WinFrmUI.RLT.Interface.Poison; using DPumpHydr.WinFrmUI.RLT.Manager; using DPumpHydr.WinFrmUI.RLT.Util; using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; #endregion namespace DPumpHydr.WinFrmUI.RLT.Controls { #region PoisonComboBox [ToolboxBitmap(typeof(ComboBox))] public class PoisonComboBox : ComboBox, IPoisonControl { #region Edit Control private readonly PoisonTextBox textBox = new(); #endregion #region Interface [Category(PoisonDefaults.PropertyCategory.Appearance)] public event EventHandler CustomPaintBackground; protected virtual void OnCustomPaintBackground(PoisonPaintEventArgs e) { if (GetStyle(ControlStyles.UserPaint) && CustomPaintBackground != null) { CustomPaintBackground(this, e); } } [Category(PoisonDefaults.PropertyCategory.Appearance)] public event EventHandler CustomPaint; protected virtual void OnCustomPaint(PoisonPaintEventArgs e) { if (GetStyle(ControlStyles.UserPaint) && CustomPaint != null) { CustomPaint(this, e); } } [Category(PoisonDefaults.PropertyCategory.Appearance)] public event EventHandler CustomPaintForeground; protected virtual void OnCustomPaintForeground(PoisonPaintEventArgs e) { if (GetStyle(ControlStyles.UserPaint) && CustomPaintForeground != null) { CustomPaintForeground(this, e); } } private ColorStyle poisonStyle = ColorStyle.Default; [Category(PoisonDefaults.PropertyCategory.Appearance)] [DefaultValue(ColorStyle.Default)] public ColorStyle Style { get { if (DesignMode || poisonStyle != ColorStyle.Default) { return poisonStyle; } if (StyleManager != null && poisonStyle == ColorStyle.Default) { return StyleManager.Style; } if (StyleManager == null && poisonStyle == ColorStyle.Default) { return PoisonDefaults.Style; } return poisonStyle; } set => poisonStyle = value; } private ThemeStyle poisonTheme = ThemeStyle.Default; [Category(PoisonDefaults.PropertyCategory.Appearance)] [DefaultValue(ThemeStyle.Default)] public ThemeStyle Theme { get { if (DesignMode || poisonTheme != ThemeStyle.Default) { return poisonTheme; } if (StyleManager != null && poisonTheme == ThemeStyle.Default) { return StyleManager.Theme; } if (StyleManager == null && poisonTheme == ThemeStyle.Default) { return PoisonDefaults.Theme; } return poisonTheme; } set => poisonTheme = value; } [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public PoisonStyleManager StyleManager { get; set; } = null; [DefaultValue(false)] [Category(PoisonDefaults.PropertyCategory.Appearance)] public bool UseCustomBackColor { get; set; } = false; [DefaultValue(false)] [Category(PoisonDefaults.PropertyCategory.Appearance)] public bool UseCustomForeColor { get; set; } = false; [DefaultValue(false)] [Category(PoisonDefaults.PropertyCategory.Appearance)] public bool UseStyleColors { get; set; } = false; [Browsable(false)] [Category(PoisonDefaults.PropertyCategory.Behaviour)] [DefaultValue(false)] public bool UseSelectable { get => GetStyle(ControlStyles.Selectable); set => SetStyle(ControlStyles.Selectable, value); } [Browsable(true)] [Category(PoisonDefaults.PropertyCategory.Behaviour)] [DefaultValue("")] [Description("Gets or sets the text associated with this control.")] public override string Text { get => textBox.Text; set { textBox.Text = value; base.Text = textBox.Text; OnTextChanged(EventArgs.Empty); } } #endregion #region Fields [DefaultValue(false)] [Category(PoisonDefaults.PropertyCategory.Appearance)] public bool DisplayFocus { get; set; } = false; [DefaultValue(DrawMode.OwnerDrawFixed)] [Browsable(false)] public new DrawMode DrawMode { get => DrawMode.OwnerDrawFixed; set => base.DrawMode = DrawMode.OwnerDrawFixed; } private ComboBoxStyle dropDownStyle = ComboBoxStyle.DropDownList; [DefaultValue(ComboBoxStyle.DropDownList)] [Category(PoisonDefaults.PropertyCategory.Appearance)] [Browsable(true)] public new ComboBoxStyle DropDownStyle { get => dropDownStyle; set { // we don't support the Simple style if (value == ComboBoxStyle.Simple) { value = ComboBoxStyle.DropDownList; } dropDownStyle = value; // fake out the base base.DropDownStyle = ComboBoxStyle.DropDownList; // if we are a dropdown and have focus, then show the edit box if ((value == ComboBoxStyle.DropDown) && Focused) { textBox.Visible = true; } else { textBox.Visible = false; } Invalidate(); } } [DefaultValue(PoisonComboBoxSize.Medium)] [Category(PoisonDefaults.PropertyCategory.Appearance)] public PoisonComboBoxSize FontSize { get; set; } = PoisonComboBoxSize.Medium; [DefaultValue(PoisonComboBoxWeight.Regular)] [Category(PoisonDefaults.PropertyCategory.Appearance)] public PoisonComboBoxWeight FontWeight { get; set; } = PoisonComboBoxWeight.Regular; private string promptText = ""; [Browsable(true)] [EditorBrowsable(EditorBrowsableState.Always)] [DefaultValue("")] [Category(PoisonDefaults.PropertyCategory.Appearance)] public string PromptText { get => promptText; set { promptText = value.Trim(); // when we are drop down, use the watermark property of the textbox to show the prompt text if (DropDownStyle == ComboBoxStyle.DropDown) { textBox.WaterMark = promptText; } Invalidate(); } } private bool drawPrompt = false; [Browsable(false)] public override Font Font { get => base.Font; set => base.Font = value; } private AutoCompleteMode autoCompleteMode = AutoCompleteMode.None; public new AutoCompleteMode AutoCompleteMode { get => autoCompleteMode; set { autoCompleteMode = value; textBox.AutoCompleteMode = value; if (value != AutoCompleteMode.None) { // if using autocomplete, then the source will be the item list. textBox.AutoCompleteSource = AutoCompleteSource.CustomSource; textBox.AutoCompleteCustomSource = new AutoCompleteStringCollection(); foreach (object item in Items) { textBox.AutoCompleteCustomSource.Add(item.ToString()); } } else { textBox.AutoCompleteSource = AutoCompleteSource.None; textBox.AutoCompleteCustomSource = null; } } } [Browsable(false)] public new AutoCompleteSource AutoCompleteSource { get => base.AutoCompleteSource; set => base.AutoCompleteSource = value; } [Browsable(false)] public new AutoCompleteStringCollection AutoCompleteCustomSource { get => base.AutoCompleteCustomSource; set => base.AutoCompleteCustomSource = value; } private bool isHovered = false; private bool isPressed = false; private bool isFocused = false; #endregion #region Constructor public PoisonComboBox() { SetStyle ( ControlStyles.SupportsTransparentBackColor | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true ); DropDownStyle = ComboBoxStyle.DropDownList; base.DrawMode = DrawMode.OwnerDrawFixed; drawPrompt = SelectedIndex == -1; // setup the textbox SuspendLayout(); textBox.Location = new System.Drawing.Point(0, 0); textBox.FontSize = (PoisonTextBoxSize)FontSize; textBox.FontWeight = (PoisonTextBoxWeight)FontWeight; textBox.WaterMarkFont = PoisonFonts.ComboBox(FontSize, FontWeight); textBox.Size = Size; textBox.TabIndex = 0; textBox.Margin = new Padding(0); textBox.Padding = new Padding(0); textBox.TextAlign = HorizontalAlignment.Left; textBox.Resize += TextBox_Resize; textBox.TextChanged += TextBox_TextChanged; textBox.UseSelectable = true; textBox.Enter += TextBox_Enter; textBox.Visible = false; Controls.Add(textBox); ResumeLayout(true); AdjustControls(); } #endregion #region TextBox Methods private void TextBox_Enter(object sender, EventArgs e) { if (autoCompleteMode != AutoCompleteMode.None) { textBox.AutoCompleteSource = AutoCompleteSource.CustomSource; textBox.AutoCompleteCustomSource = new AutoCompleteStringCollection(); for (int i = 0; i < Items.Count; i++) { textBox.AutoCompleteCustomSource.Add(GetItemText(Items[i])); } } } private void TextBox_Resize(object sender, EventArgs e) { AdjustControls(); } private void TextBox_TextChanged(object sender, EventArgs e) { promptText = textBox.Text; OnTextChanged(e); } #endregion #region Paint Methods protected override void OnSizeChanged(EventArgs e) { AdjustControls(); base.OnSizeChanged(e); } protected override void OnPaintBackground(PaintEventArgs e) { try { Color backColor = BackColor; if (!UseCustomBackColor) { backColor = PoisonPaint.BackColor.Form(Theme); } if (backColor.A == 255 && BackgroundImage == null) { e.Graphics.Clear(backColor); return; } base.OnPaintBackground(e); OnCustomPaintBackground(new PoisonPaintEventArgs(backColor, Color.Empty, e.Graphics)); } catch { Invalidate(); } } protected override void OnPaint(PaintEventArgs e) { try { if (GetStyle(ControlStyles.AllPaintingInWmPaint)) { OnPaintBackground(e); } OnCustomPaint(new PoisonPaintEventArgs(Color.Empty, Color.Empty, e.Graphics)); OnPaintForeground(e); } catch { Invalidate(); } } protected virtual void OnPaintForeground(PaintEventArgs e) { base.ItemHeight = GetPreferredSize(Size.Empty).Height; Color borderColor, foreColor; if (isHovered && !isPressed && Enabled) { foreColor = PoisonPaint.ForeColor.ComboBox.Hover(Theme); borderColor = PoisonPaint.BorderColor.ComboBox.Hover(Theme); } else if (isHovered && isPressed && Enabled) { foreColor = PoisonPaint.ForeColor.ComboBox.Press(Theme); borderColor = PoisonPaint.BorderColor.ComboBox.Press(Theme); } else if (!Enabled) { foreColor = PoisonPaint.ForeColor.ComboBox.Disabled(Theme); borderColor = PoisonPaint.BorderColor.ComboBox.Disabled(Theme); } else { foreColor = PoisonPaint.ForeColor.ComboBox.Normal(Theme); borderColor = PoisonPaint.BorderColor.ComboBox.Normal(Theme); } using (Pen p = new(borderColor)) { Rectangle boxRect = new(0, 0, Width - 1, Height - 1); e.Graphics.DrawRectangle(p, boxRect); } if (DropDownStyle != ComboBoxStyle.Simple) { using (SolidBrush b = new(foreColor)) { e.Graphics.FillPolygon(b, new Point[] { new(Width - 20, (Height / 2) - 2), new(Width - 9, (Height / 2) - 2), new(Width - 15, (Height / 2) + 4) }); } Rectangle textRect = new(2, 2, Width - 40, Height - 4); if (Enabled) { TextRenderer.DrawText(e.Graphics, Text, PoisonFonts.ComboBox(FontSize, FontWeight), textRect, foreColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); } else { ControlPaint.DrawStringDisabled(e.Graphics, Text, PoisonFonts.ComboBox(FontSize, FontWeight), PoisonPaint.ForeColor.ComboBox.Disabled(Theme), textRect, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); } OnCustomPaintForeground(new PoisonPaintEventArgs(Color.Empty, foreColor, e.Graphics)); if (DisplayFocus && isFocused) { ControlPaint.DrawFocusRectangle(e.Graphics, ClientRectangle); } if (drawPrompt) { DrawTextPrompt(e.Graphics); } } } protected override void OnDrawItem(DrawItemEventArgs e) { if (e.Index >= 0) { Color foreColor = PoisonPaint.ForeColor.Link.Normal(Theme); Color backColor = BackColor; if (!UseCustomBackColor) { backColor = PoisonPaint.BackColor.Form(Theme); } if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) { using (SolidBrush b = new(PoisonPaint.GetStyleColor(Style))) { e.Graphics.FillRectangle(b, new Rectangle(e.Bounds.Left, e.Bounds.Top, e.Bounds.Width, e.Bounds.Height)); } foreColor = PoisonPaint.ForeColor.Tile.Normal(Theme); } else { using SolidBrush b = new(backColor); e.Graphics.FillRectangle(b, new Rectangle(e.Bounds.Left, e.Bounds.Top, e.Bounds.Width, e.Bounds.Height)); } if (DropDownStyle != ComboBoxStyle.DropDown) { Rectangle textRect = new(0, e.Bounds.Top, e.Bounds.Width, e.Bounds.Height); TextRenderer.DrawText(e.Graphics, GetItemText(Items[e.Index]), PoisonFonts.ComboBox(FontSize, FontWeight), textRect, foreColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); } else { Rectangle textRect = new(0, e.Bounds.Top, textBox.Width, e.Bounds.Height); TextRenderer.DrawText(e.Graphics, GetItemText(Items[e.Index]), PoisonFonts.ComboBox(FontSize, FontWeight), textRect, foreColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); } } else { base.OnDrawItem(e); } } private void DrawTextPrompt() { using Graphics graphics = CreateGraphics(); DrawTextPrompt(graphics); } private void DrawTextPrompt(Graphics g) { Color backColor = BackColor; if (!UseCustomBackColor) { backColor = PoisonPaint.BackColor.Form(Theme); } Rectangle textRect = new(2, 2, Width - 20, Height - 4); TextRenderer.DrawText(g, promptText, PoisonFonts.ComboBox(FontSize, FontWeight), textRect, SystemColors.GrayText, backColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis); } #endregion #region Focus Methods protected override void OnGotFocus(EventArgs e) { isFocused = true; isHovered = true; Invalidate(); base.OnGotFocus(e); } protected override void OnLostFocus(EventArgs e) { isFocused = false; isHovered = false; isPressed = false; Invalidate(); base.OnLostFocus(e); } protected override void OnEnter(EventArgs e) { isFocused = true; isHovered = true; Invalidate(); base.OnEnter(e); } protected override void OnLeave(EventArgs e) { isFocused = false; isHovered = false; isPressed = false; if (DropDownStyle == ComboBoxStyle.DropDown) { textBox.Visible = false; } Invalidate(); base.OnLeave(e); } #endregion #region Keyboard Methods protected override void OnKeyDown(KeyEventArgs e) { if (e.KeyCode == Keys.Space) { isHovered = true; isPressed = true; Invalidate(); } base.OnKeyDown(e); } protected override void OnKeyUp(KeyEventArgs e) { //isHovered = false; //isPressed = false; Invalidate(); base.OnKeyUp(e); } #endregion #region Mouse Methods protected override void OnMouseEnter(EventArgs e) { isHovered = true; Invalidate(); base.OnMouseEnter(e); } protected override void OnMouseDown(MouseEventArgs e) { if (e.Button == MouseButtons.Left) { if (DropDownStyle == ComboBoxStyle.DropDown) { textBox.Visible = true; } isPressed = true; Invalidate(); } base.OnMouseDown(e); } protected override void OnMouseUp(MouseEventArgs e) { isPressed = false; Invalidate(); base.OnMouseUp(e); } protected override void OnMouseLeave(EventArgs e) { if (!isFocused) { isHovered = false; } Invalidate(); base.OnMouseLeave(e); } #endregion #region Overridden Methods public override Size GetPreferredSize(Size proposedSize) { Size preferredSize; base.GetPreferredSize(proposedSize); using (Graphics g = CreateGraphics()) { string measureText = Text.Length > 0 ? Text : "MeasureText"; proposedSize = new(int.MaxValue, int.MaxValue); preferredSize = TextRenderer.MeasureText(g, measureText, PoisonFonts.ComboBox(FontSize, FontWeight), proposedSize, TextFormatFlags.Left | TextFormatFlags.LeftAndRightPadding | TextFormatFlags.VerticalCenter); preferredSize.Height += 4; } return preferredSize; } protected override void OnSelectedIndexChanged(EventArgs e) { base.OnSelectedIndexChanged(e); drawPrompt = SelectedIndex == -1; Invalidate(); } private const int OCM_COMMAND = 0x2111; private const int WM_PAINT = 15; protected override void WndProc(ref Message m) { base.WndProc(ref m); if (((m.Msg == WM_PAINT) || (m.Msg == OCM_COMMAND)) && drawPrompt) { DrawTextPrompt(); } } #endregion #region Private Methods private void AdjustControls() { if (DropDownStyle == ComboBoxStyle.DropDownList) { return; } SuspendLayout(); textBox.Width = ClientRectangle.Width - 26; textBox.Height = ClientRectangle.Height; ResumeLayout(); Invalidate(false); } #endregion } #endregion }