#region Imports
|
|
using DPumpHydr.WinFrmUI.RLT.Extension;
|
using DPumpHydr.WinFrmUI.RLT.Manager;
|
using DPumpHydr.WinFrmUI.RLT.Util;
|
using System;
|
using System.Collections.Generic;
|
using System.ComponentModel;
|
using System.Drawing;
|
using System.Drawing.Imaging;
|
using System.Runtime.InteropServices;
|
using System.Windows.Forms;
|
using static DPumpHydr.WinFrmUI.RLT.Helper.MaterialDrawHelper;
|
using static DPumpHydr.WinFrmUI.RLT.Util.MaterialAnimations;
|
|
#endregion
|
|
namespace DPumpHydr.WinFrmUI.RLT.Controls
|
{
|
#region MaterialTextBox
|
|
[ToolboxItem(false), Description("This control has been replaced by MaterialTextBoxEdit"), Obsolete("Use MaterialTextBoxEdit instead", false)]
|
public class MaterialTextBox : RichTextBox, MaterialControlI
|
{
|
MaterialContextMenuStrip cms = new MaterialTextBoxContextMenuStrip();
|
ContextMenuStrip _lastContextMenuStrip = new();
|
|
//Properties for managing the material design properties
|
[Browsable(false)]
|
public int Depth { get; set; }
|
|
[Browsable(false)]
|
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
|
|
[Browsable(false)]
|
public MaterialMouseState MouseState { get; set; }
|
|
[Category("Material"), DefaultValue(false)]
|
public bool Password { get; set; }
|
|
private bool _UseTallSize;
|
|
[Category("Material"), DefaultValue(true), Description("Using a larger size enables the hint to always be visible")]
|
public bool UseTallSize
|
{
|
get => _UseTallSize;
|
set
|
{
|
_UseTallSize = value;
|
HEIGHT = UseTallSize ? 50 : 36;
|
Size = new Size(Size.Width, HEIGHT);
|
UpdateRects(false);
|
Invalidate();
|
}
|
}
|
|
[Category("Material"), DefaultValue(true)]
|
public bool UseAccent { get; set; }
|
|
private string _hint = string.Empty;
|
|
[Category("Material"), DefaultValue(""), Localizable(true)]
|
public string Hint
|
{
|
get => _hint;
|
set
|
{
|
_hint = value;
|
hasHint = !string.IsNullOrEmpty(Hint);
|
Invalidate();
|
}
|
}
|
|
private Image _leadingIcon;
|
|
[Category("Material"), Browsable(true), Localizable(false)]
|
public Image LeadingIcon
|
{
|
get => _leadingIcon;
|
set
|
{
|
_leadingIcon = value;
|
UpdateRects(false);
|
preProcessIcons();
|
if (AutoSize)
|
{
|
Refresh();
|
}
|
else
|
{
|
Invalidate();
|
}
|
}
|
}
|
|
private Image _trailingIcon;
|
|
[Category("Material"), Browsable(true), Localizable(false)]
|
public Image TrailingIcon
|
{
|
get => _trailingIcon;
|
set
|
{
|
_trailingIcon = value;
|
UpdateRects(false);
|
preProcessIcons();
|
if (AutoSize)
|
{
|
Refresh();
|
}
|
else
|
{
|
Invalidate();
|
}
|
}
|
}
|
|
public override ContextMenuStrip ContextMenuStrip
|
{
|
get => base.ContextMenuStrip;
|
set
|
{
|
if (value != null)
|
{
|
base.ContextMenuStrip = value;
|
}
|
else
|
{
|
base.ContextMenuStrip = cms;
|
}
|
_lastContextMenuStrip = base.ContextMenuStrip;
|
}
|
}
|
|
public override bool ShortcutsEnabled
|
{
|
get => base.ShortcutsEnabled;
|
set
|
{
|
base.ShortcutsEnabled = value;
|
if (value == false)
|
{
|
base.ContextMenuStrip = null;
|
}
|
else
|
{
|
base.ContextMenuStrip = _lastContextMenuStrip;
|
}
|
}
|
}
|
|
private const int ICON_SIZE = 24;
|
private const int HINT_TEXT_SMALL_SIZE = 18;
|
private const int HINT_TEXT_SMALL_Y = 4;
|
private const int BOTTOM_PADDING = 3;
|
private int HEIGHT = 50;
|
private int LINE_Y;
|
|
private bool hasHint;
|
private bool _errorState = false;
|
private int _left_padding;
|
private int _right_padding;
|
private Rectangle _leadingIconBounds;
|
private Rectangle _trailingIconBounds;
|
private Rectangle _textfieldBounds;
|
|
private readonly AnimationManager _animationManager;
|
private Dictionary<string, TextureBrush> iconsBrushes;
|
private Dictionary<string, TextureBrush> iconsErrorBrushes;
|
|
private bool _animateReadOnly;
|
|
[Category("Material")]
|
[Browsable(true)]
|
public bool AnimateReadOnly
|
{
|
get => _animateReadOnly;
|
set
|
{
|
_animateReadOnly = value;
|
Invalidate();
|
}
|
}
|
|
private bool _leaveOnEnterKey;
|
|
[Category("Material"), DefaultValue(false), Description("Select next control which have TabStop property set to True when enter key is pressed.")]
|
public bool LeaveOnEnterKey
|
{
|
get => _leaveOnEnterKey;
|
set
|
{
|
_leaveOnEnterKey = value;
|
if (value)
|
{
|
KeyDown += new KeyEventHandler(LeaveOnEnterKey_KeyDown);
|
}
|
else
|
{
|
KeyDown -= LeaveOnEnterKey_KeyDown;
|
}
|
Invalidate();
|
}
|
}
|
|
#region "Events"
|
|
[Category("Action")]
|
[Description("Fires when Leading Icon is clicked")]
|
public event EventHandler LeadingIconClick;
|
|
[Category("Action")]
|
[Description("Fires when Trailing Icon is clicked")]
|
public event EventHandler TrailingIconClick;
|
|
#endregion
|
|
public MaterialTextBox()
|
{
|
// Material Properties
|
Hint = "";
|
Password = false;
|
UseAccent = true;
|
UseTallSize = true;
|
|
// Properties
|
TabStop = true;
|
Multiline = false;
|
BorderStyle = BorderStyle.None;
|
|
// Animations
|
_animationManager = new AnimationManager
|
{
|
Increment = 0.08,
|
AnimationType = AnimationType.EaseInOut
|
};
|
_animationManager.OnAnimationProgress += sender => Invalidate();
|
|
SkinManager.ColorSchemeChanged += sender =>
|
{
|
preProcessIcons();
|
};
|
|
SkinManager.ThemeChanged += sender =>
|
{
|
preProcessIcons();
|
};
|
|
cms.Opening += ContextMenuStripOnOpening;
|
cms.OnItemClickStart += ContextMenuStripOnItemClickStart;
|
ContextMenuStrip = cms;
|
|
MaxLength = 50;
|
}
|
|
private const int EM_SETPASSWORDCHAR = 0x00cc;
|
|
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
|
|
protected override void OnCreateControl()
|
{
|
base.OnCreateControl();
|
base.Font = SkinManager.GetFontByType(MaterialSkinManager.FontType.Subtitle1);
|
base.AutoSize = false;
|
|
SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
|
|
if (Password)
|
{
|
SendMessage(Handle, EM_SETPASSWORDCHAR, 'T', 0);
|
}
|
|
// Size and padding
|
HEIGHT = UseTallSize ? 50 : 36;
|
Size = new Size(Size.Width, HEIGHT);
|
LINE_Y = HEIGHT - BOTTOM_PADDING;
|
UpdateRects();
|
|
// events
|
MouseState = MaterialMouseState.OUT;
|
LostFocus += (sender, args) => _animationManager.StartNewAnimation(AnimationDirection.Out);
|
GotFocus += (sender, args) =>
|
{
|
_animationManager.StartNewAnimation(AnimationDirection.In);
|
};
|
MouseEnter += (sender, args) =>
|
{
|
MouseState = MaterialMouseState.HOVER;
|
Invalidate();
|
};
|
MouseLeave += (sender, args) =>
|
{
|
MouseState = MaterialMouseState.OUT;
|
Invalidate();
|
};
|
HScroll += (sender, args) =>
|
{
|
SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref scrollPos);
|
Invalidate();
|
};
|
KeyDown += (sender, args) =>
|
{
|
SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref scrollPos);
|
};
|
}
|
|
private Point scrollPos = Point.Empty;
|
private const int EM_GETSCROLLPOS = WM_USER + 221;
|
private const int WM_USER = 0x400;
|
|
[DllImport("user32.dll")]
|
private static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, int wParam, ref Point lParam);
|
|
public override Size GetPreferredSize(Size proposedSize)
|
{
|
return new Size(proposedSize.Width, HEIGHT);
|
}
|
|
private static Size ResizeIcon(Image Icon)
|
{
|
int newWidth, newHeight;
|
//Resize icon if greater than ICON_SIZE
|
if (Icon.Width > ICON_SIZE || Icon.Height > ICON_SIZE)
|
{
|
//calculate aspect ratio
|
float aspect = Icon.Width / (float)Icon.Height;
|
|
//calculate new dimensions based on aspect ratio
|
newWidth = (int)(ICON_SIZE * aspect);
|
newHeight = (int)(newWidth / aspect);
|
|
//if one of the two dimensions exceed the box dimensions
|
if (newWidth > ICON_SIZE || newHeight > ICON_SIZE)
|
{
|
//depending on which of the two exceeds the box dimensions set it as the box dimension and calculate the other one based on the aspect ratio
|
if (newWidth > newHeight)
|
{
|
newWidth = ICON_SIZE;
|
newHeight = (int)(newWidth / aspect);
|
}
|
else
|
{
|
newHeight = ICON_SIZE;
|
newWidth = (int)(newHeight * aspect);
|
}
|
}
|
}
|
else
|
{
|
newWidth = Icon.Width;
|
newHeight = Icon.Height;
|
}
|
|
return new Size()
|
{
|
Height = newHeight,
|
Width = newWidth
|
};
|
}
|
|
private void preProcessIcons()
|
{
|
if (_trailingIcon == null && _leadingIcon == null)
|
{
|
return;
|
}
|
|
// Calculate lightness and color
|
float l = (SkinManager.Theme == MaterialSkinManager.Themes.LIGHT) ? 0f : 1f;
|
|
// Create matrices
|
float[][] matrixGray = {
|
new float[] { 0, 0, 0, 0, 0}, // Red scale factor
|
new float[] { 0, 0, 0, 0, 0}, // Green scale factor
|
new float[] { 0, 0, 0, 0, 0}, // Blue scale factor
|
new float[] { 0, 0, 0, Enabled ? .7f : .3f, 0}, // alpha scale factor
|
new float[] { l, l, l, 0, 1}};// offset
|
|
float[][] matrixRed = {
|
new float[] { 0, 0, 0, 0, 0}, // Red scale factor
|
new float[] { 0, 0, 0, 0, 0}, // Green scale factor
|
new float[] { 0, 0, 0, 0, 0}, // Blue scale factor
|
new float[] { 0, 0, 0, 1, 0}, // alpha scale factor
|
new float[] { 1, 0, 0, 0, 1}};// offset
|
|
ColorMatrix colorMatrixGray = new(matrixGray);
|
ColorMatrix colorMatrixRed = new(matrixRed);
|
|
ImageAttributes grayImageAttributes = new();
|
ImageAttributes redImageAttributes = new();
|
|
// Set color matrices
|
grayImageAttributes.SetColorMatrix(colorMatrixGray, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
|
redImageAttributes.SetColorMatrix(colorMatrixRed, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
|
|
// Create brushes
|
iconsBrushes = new Dictionary<string, TextureBrush>(2);
|
iconsErrorBrushes = new Dictionary<string, TextureBrush>(2);
|
|
// Image Rect
|
Rectangle destRect = new(0, 0, ICON_SIZE, ICON_SIZE);
|
|
if (_leadingIcon != null)
|
{
|
// ********************
|
// *** _leadingIcon ***
|
// ********************
|
|
//Resize icon if greater than ICON_SIZE
|
Size newSize_leadingIcon = ResizeIcon(_leadingIcon);
|
Bitmap _leadingIconIconResized = new(_leadingIcon, newSize_leadingIcon.Width, newSize_leadingIcon.Height);
|
|
// Create a pre-processed copy of the image (GRAY)
|
Bitmap bgray = new(destRect.Width, destRect.Height);
|
using (Graphics gGray = Graphics.FromImage(bgray))
|
{
|
gGray.DrawImage(_leadingIconIconResized,
|
new Point[] {
|
new(0, 0),
|
new(destRect.Width, 0),
|
new(0, destRect.Height),
|
},
|
destRect, GraphicsUnit.Pixel, grayImageAttributes);
|
}
|
|
// added processed image to brush for drawing
|
TextureBrush textureBrushGray = new(bgray);
|
|
textureBrushGray.WrapMode = System.Drawing.Drawing2D.WrapMode.Clamp;
|
|
Rectangle iconRect = _leadingIconBounds;
|
|
textureBrushGray.TranslateTransform(iconRect.X + (iconRect.Width / 2) - (_leadingIconIconResized.Width / 2),
|
iconRect.Y + (iconRect.Height / 2) - (_leadingIconIconResized.Height / 2));
|
|
// add to dictionary
|
iconsBrushes.Add("_leadingIcon", textureBrushGray);
|
}
|
|
if (_trailingIcon != null)
|
{
|
// *********************
|
// *** _trailingIcon ***
|
// *********************
|
|
//Resize icon if greater than ICON_SIZE
|
Size newSize_trailingIcon = ResizeIcon(_trailingIcon);
|
Bitmap _trailingIconResized = new(_trailingIcon, newSize_trailingIcon.Width, newSize_trailingIcon.Height);
|
|
// Create a pre-processed copy of the image (GRAY)
|
Bitmap bgray = new(destRect.Width, destRect.Height);
|
using (Graphics gGray = Graphics.FromImage(bgray))
|
{
|
gGray.DrawImage(_trailingIconResized,
|
new Point[] {
|
new(0, 0),
|
new(destRect.Width, 0),
|
new(0, destRect.Height),
|
},
|
destRect, GraphicsUnit.Pixel, grayImageAttributes);
|
}
|
|
//Create a pre - processed copy of the image(RED)
|
Bitmap bred = new(destRect.Width, destRect.Height);
|
using (Graphics gred = Graphics.FromImage(bred))
|
{
|
gred.DrawImage(_trailingIconResized,
|
new Point[] {
|
new(0, 0),
|
new(destRect.Width, 0),
|
new(0, destRect.Height),
|
},
|
destRect, GraphicsUnit.Pixel, redImageAttributes);
|
}
|
|
|
// added processed image to brush for drawing
|
TextureBrush textureBrushGray = new(bgray);
|
TextureBrush textureBrushRed = new(bred);
|
|
textureBrushGray.WrapMode = System.Drawing.Drawing2D.WrapMode.Clamp;
|
textureBrushRed.WrapMode = System.Drawing.Drawing2D.WrapMode.Clamp;
|
|
Rectangle iconRect = _trailingIconBounds;
|
|
textureBrushGray.TranslateTransform(iconRect.X + (iconRect.Width / 2) - (_trailingIconResized.Width / 2),
|
iconRect.Y + (iconRect.Height / 2) - (_trailingIconResized.Height / 2));
|
textureBrushRed.TranslateTransform(iconRect.X + (iconRect.Width / 2) - (_trailingIconResized.Width / 2),
|
iconRect.Y + (iconRect.Height / 2) - (_trailingIconResized.Height / 2));
|
|
// add to dictionary
|
iconsBrushes.Add("_trailingIcon", textureBrushGray);
|
//iconsSelectedBrushes.Add(0, textureBrushColor);
|
iconsErrorBrushes.Add("_trailingIcon", textureBrushRed);
|
}
|
}
|
|
private void UpdateRects(bool RedefineTextField = true)
|
{
|
if (LeadingIcon != null)
|
{
|
_left_padding = SkinManager.FORM_PADDING + ICON_SIZE;
|
}
|
else
|
{
|
_left_padding = SkinManager.FORM_PADDING;
|
}
|
|
if (_trailingIcon != null)
|
{
|
_right_padding = SkinManager.FORM_PADDING + ICON_SIZE;
|
}
|
else
|
{
|
_right_padding = SkinManager.FORM_PADDING;
|
}
|
|
_leadingIconBounds = new Rectangle(8, (HEIGHT / 2) - (ICON_SIZE / 2), ICON_SIZE, ICON_SIZE);
|
_trailingIconBounds = new Rectangle(Width - (ICON_SIZE + 8), (HEIGHT / 2) - (ICON_SIZE / 2), ICON_SIZE, ICON_SIZE);
|
_textfieldBounds = new Rectangle(_left_padding, ClientRectangle.Y, Width - _left_padding - _right_padding, LINE_Y);
|
|
if (RedefineTextField)
|
{
|
Rectangle rect = new(_left_padding, UseTallSize ? hasHint ?
|
(HINT_TEXT_SMALL_Y + HINT_TEXT_SMALL_SIZE) : // Has hint and it's tall
|
(int)(LINE_Y / 3.5) : // No hint and tall
|
Height / 5, // not tall
|
ClientSize.Width - _left_padding - _right_padding, LINE_Y);
|
RECT rc = new(rect);
|
SendMessageRefRect(Handle, EM_SETRECT, 0, ref rc);
|
}
|
|
}
|
|
public void SetErrorState(bool ErrorState)
|
{
|
_errorState = ErrorState;
|
Invalidate();
|
}
|
|
public bool GetErrorState()
|
{
|
return _errorState;
|
}
|
|
protected override void OnPaint(PaintEventArgs pevent)
|
{
|
base.OnPaint(pevent);
|
|
Graphics g = pevent.Graphics;
|
|
g.Clear(Parent.BackColor == Color.Transparent ? ((Parent.Parent == null || (Parent.Parent != null && Parent.Parent.BackColor == Color.Transparent)) ? SkinManager.BackgroundColor : Parent.Parent.BackColor) : Parent.BackColor);
|
|
SolidBrush backBrush = new(BlendColor(Parent.BackColor, SkinManager.BackgroundAlternativeColor, SkinManager.BackgroundAlternativeColor.A));
|
|
g.FillRectangle(
|
!Enabled ? SkinManager.BackgroundDisabledBrush : // Disabled
|
Focused ? SkinManager.BackgroundFocusBrush : // Focused
|
MouseState == MaterialMouseState.HOVER && (!ReadOnly || (ReadOnly && !AnimateReadOnly)) ? SkinManager.BackgroundHoverBrush : // Hover
|
backBrush, // Normal
|
ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, LINE_Y);
|
|
//Leading Icon
|
if (LeadingIcon != null)
|
{
|
g.FillRectangle(iconsBrushes["_leadingIcon"], _leadingIconBounds);
|
}
|
|
//Trailing Icon
|
if (TrailingIcon != null)
|
{
|
if (_errorState)
|
{
|
g.FillRectangle(iconsErrorBrushes["_trailingIcon"], _trailingIconBounds);
|
}
|
else
|
{
|
g.FillRectangle(iconsBrushes["_trailingIcon"], _trailingIconBounds);
|
}
|
}
|
|
// HintText
|
bool userTextPresent = !string.IsNullOrEmpty(Text);
|
Color textColor = Enabled ? Focused ?
|
UseAccent ? SkinManager.ColorScheme.AccentColor : SkinManager.ColorScheme.PrimaryColor : // Focused
|
SkinManager.TextHighEmphasisColor : // Inactive
|
SkinManager.TextDisabledOrHintColor; // Disabled
|
Rectangle hintRect = new(_left_padding, ClientRectangle.Y, Width - _left_padding - _right_padding, LINE_Y);
|
int hintTextSize = 16;
|
|
// bottom line base
|
g.FillRectangle(SkinManager.DividersAlternativeBrush, 0, LINE_Y, Width, 1);
|
|
if (ReadOnly == false || (ReadOnly && AnimateReadOnly))
|
{
|
if (!_animationManager.IsAnimating())
|
{
|
// No animation
|
if (hasHint && UseTallSize && (Focused || userTextPresent))
|
{
|
// hint text
|
hintRect = new Rectangle(_left_padding, HINT_TEXT_SMALL_Y, Width - _left_padding - _right_padding, HINT_TEXT_SMALL_SIZE);
|
hintTextSize = 12;
|
}
|
|
// bottom line
|
if (Focused)
|
{
|
g.FillRectangle(_errorState ? SkinManager.BackgroundHoverRedBrush : UseAccent ? SkinManager.ColorScheme.AccentBrush : SkinManager.ColorScheme.PrimaryBrush, 0, LINE_Y, Width, 2);
|
}
|
}
|
else
|
{
|
// Animate - Focus got/lost
|
double animationProgress = _animationManager.GetProgress();
|
|
// hint Animation
|
if (hasHint && UseTallSize)
|
{
|
hintRect = new Rectangle(
|
_left_padding,
|
userTextPresent ? HINT_TEXT_SMALL_Y : ClientRectangle.Y + (int)((HINT_TEXT_SMALL_Y - ClientRectangle.Y) * animationProgress),
|
Width - _left_padding - _right_padding,
|
userTextPresent ? HINT_TEXT_SMALL_SIZE : (int)(LINE_Y + ((HINT_TEXT_SMALL_SIZE - LINE_Y) * animationProgress)));
|
hintTextSize = userTextPresent ? 12 : (int)(16 + ((12 - 16) * animationProgress));
|
}
|
|
// Line Animation
|
int LineAnimationWidth = (int)(Width * animationProgress);
|
int LineAnimationX = (Width / 2) - (LineAnimationWidth / 2);
|
g.FillRectangle(UseAccent ? SkinManager.ColorScheme.AccentBrush : SkinManager.ColorScheme.PrimaryBrush, LineAnimationX, LINE_Y, LineAnimationWidth, 2);
|
}
|
}
|
|
// Text stuff:
|
string textToDisplay = Password ? Text.ToSecureString() : Text;
|
string textSelected;
|
Rectangle textSelectRect;
|
|
// Calc text Rect
|
Rectangle textRect = new(
|
hintRect.X,
|
hasHint && UseTallSize ? hintRect.Y + hintRect.Height - 2 : ClientRectangle.Y,
|
ClientRectangle.Width - _left_padding - _right_padding + scrollPos.X,
|
hasHint && UseTallSize ? LINE_Y - (hintRect.Y + hintRect.Height) : LINE_Y);
|
|
g.Clip = new Region(textRect);
|
textRect.X -= scrollPos.X;
|
|
using (MaterialNativeTextRenderer NativeText = new(g))
|
{
|
// Selection rects calc
|
string textBeforeSelection = textToDisplay.Substring(0, SelectionStart);
|
textSelected = textToDisplay.Substring(SelectionStart, SelectionLength);
|
|
int selectX = NativeText.MeasureLogString(textBeforeSelection, SkinManager.GetLogFontByType(MaterialSkinManager.FontType.Subtitle1)).Width;
|
int selectWidth = NativeText.MeasureLogString(textSelected, SkinManager.GetLogFontByType(MaterialSkinManager.FontType.Subtitle1)).Width;
|
|
textSelectRect = new Rectangle(
|
textRect.X + selectX, UseTallSize ? hasHint ?
|
textRect.Y + BOTTOM_PADDING : // tall and hint
|
(LINE_Y / 3) - BOTTOM_PADDING : // tall and no hint
|
BOTTOM_PADDING, // not tall
|
selectWidth,
|
UseTallSize ? hasHint ?
|
textRect.Height - (BOTTOM_PADDING * 2) : // tall and hint
|
(int)(LINE_Y / 2) : // tall and no hint
|
LINE_Y - (BOTTOM_PADDING * 2)); // not tall
|
|
// Draw user text
|
NativeText.DrawTransparentText(
|
textToDisplay,
|
SkinManager.GetLogFontByType(MaterialSkinManager.FontType.Subtitle1),
|
Enabled ? SkinManager.TextHighEmphasisColor : SkinManager.TextDisabledOrHintColor,
|
textRect.Location,
|
textRect.Size,
|
MaterialNativeTextRenderer.TextAlignFlags.Left | MaterialNativeTextRenderer.TextAlignFlags.Middle);
|
}
|
|
if (Focused)
|
{
|
// Draw Selection Rectangle
|
g.FillRectangle(UseAccent ? SkinManager.ColorScheme.AccentBrush : SkinManager.ColorScheme.DarkPrimaryBrush, textSelectRect);
|
|
// Draw Selected Text
|
using MaterialNativeTextRenderer NativeText = new(g);
|
NativeText.DrawTransparentText(
|
textSelected,
|
SkinManager.GetLogFontByType(MaterialSkinManager.FontType.Subtitle1),
|
SkinManager.ColorScheme.TextColor,
|
textSelectRect.Location,
|
textSelectRect.Size,
|
MaterialNativeTextRenderer.TextAlignFlags.Left | MaterialNativeTextRenderer.TextAlignFlags.Middle);
|
}
|
|
g.Clip = new Region(ClientRectangle);
|
|
// Draw hint text
|
if (hasHint && (UseTallSize || string.IsNullOrEmpty(Text)))
|
{
|
using MaterialNativeTextRenderer NativeText = new(g);
|
NativeText.DrawTransparentText(
|
Hint,
|
SkinManager.GetTextBoxFontBySize(hintTextSize),
|
Enabled ? !_errorState || (!userTextPresent && !Focused) ? Focused ? UseAccent ?
|
SkinManager.ColorScheme.AccentColor : // Focus Accent
|
SkinManager.ColorScheme.PrimaryColor : // Focus Primary
|
SkinManager.TextMediumEmphasisColor : // not focused
|
SkinManager.BackgroundHoverRedColor : // error state
|
SkinManager.TextDisabledOrHintColor, // Disabled
|
hintRect.Location,
|
hintRect.Size,
|
MaterialNativeTextRenderer.TextAlignFlags.Left | MaterialNativeTextRenderer.TextAlignFlags.Middle);
|
}
|
}
|
|
protected override void OnTextChanged(EventArgs e)
|
{
|
base.OnTextChanged(e);
|
Invalidate();
|
}
|
|
protected override void OnMouseMove(MouseEventArgs e)
|
{
|
base.OnMouseMove(e);
|
|
if (DesignMode)
|
{
|
return;
|
}
|
|
if (_textfieldBounds.Contains(e.Location))
|
{
|
Cursor = Cursors.IBeam;
|
}
|
else if (LeadingIcon != null && _leadingIconBounds.Contains(e.Location) && LeadingIconClick != null)
|
{
|
Cursor = Cursors.Hand;
|
}
|
else if (TrailingIcon != null && _trailingIconBounds.Contains(e.Location) && TrailingIconClick != null)
|
{
|
Cursor = Cursors.Hand;
|
}
|
else
|
{
|
Cursor = Cursors.Default;
|
}
|
|
}
|
|
protected override void OnMouseDown(MouseEventArgs e)
|
{
|
if (LeadingIcon != null && _leadingIconBounds.Contains(e.Location))
|
{
|
LeadingIconClick?.Invoke(this, new EventArgs());
|
}
|
else if (TrailingIcon != null && _trailingIconBounds.Contains(e.Location))
|
{
|
TrailingIconClick?.Invoke(this, new EventArgs());
|
}
|
else
|
{
|
if (DesignMode)
|
{
|
return;
|
}
|
}
|
base.OnMouseDown(e);
|
}
|
|
protected override void OnSelectionChanged(EventArgs e)
|
{
|
base.OnSelectionChanged(e);
|
Invalidate();
|
}
|
|
protected override void OnResize(EventArgs e)
|
{
|
base.OnResize(e);
|
Size = new Size(Width, HEIGHT);
|
LINE_Y = HEIGHT - BOTTOM_PADDING;
|
UpdateRects(false);
|
preProcessIcons();
|
|
if (DesignMode)
|
{
|
//Below code helps to redraw images in design mode only
|
Image _tmpimage;
|
_tmpimage = LeadingIcon;
|
LeadingIcon = null;
|
LeadingIcon = _tmpimage;
|
_tmpimage = TrailingIcon;
|
TrailingIcon = null;
|
TrailingIcon = _tmpimage;
|
}
|
}
|
|
private void ContextMenuStripOnItemClickStart(object sender, ToolStripItemClickedEventArgs toolStripItemClickedEventArgs)
|
{
|
switch (toolStripItemClickedEventArgs.ClickedItem.Text)
|
{
|
case "Cut":
|
Cut();
|
break;
|
|
case "Copy":
|
Copy();
|
break;
|
|
case "Paste":
|
Paste();
|
break;
|
|
case "Delete":
|
SelectedText = string.Empty;
|
break;
|
|
case "Select All":
|
SelectAll();
|
break;
|
}
|
}
|
|
private void ContextMenuStripOnOpening(object sender, CancelEventArgs cancelEventArgs)
|
{
|
if (sender is MaterialTextBoxContextMenuStrip strip)
|
{
|
strip.Cut.Enabled = !string.IsNullOrEmpty(SelectedText) && !ReadOnly;
|
strip.Copy.Enabled = !string.IsNullOrEmpty(SelectedText);
|
strip.Paste.Enabled = Clipboard.ContainsText() && !ReadOnly;
|
strip.Delete.Enabled = !string.IsNullOrEmpty(SelectedText) && !ReadOnly;
|
strip.SelectAll.Enabled = !string.IsNullOrEmpty(Text);
|
}
|
}
|
|
private void LeaveOnEnterKey_KeyDown(object sender, KeyEventArgs e)
|
{
|
if (e.KeyCode == Keys.Enter)
|
{
|
e.Handled = true;
|
e.SuppressKeyPress = true;
|
SendKeys.Send("{TAB}");
|
}
|
}
|
|
// Cursor flickering fix
|
private const int WM_SETCURSOR = 0x0020;
|
|
protected override void WndProc(ref Message m)
|
{
|
if (m.Msg == WM_SETCURSOR)
|
{
|
Cursor.Current = this.Cursor;
|
}
|
else
|
{
|
base.WndProc(ref m);
|
}
|
}
|
|
// Padding
|
private const int EM_SETRECT = 0xB3;
|
|
[DllImport(@"User32.dll", EntryPoint = @"SendMessage", CharSet = CharSet.Auto)]
|
private static extern int SendMessageRefRect(IntPtr hWnd, uint msg, int wParam, ref RECT rect);
|
|
[StructLayout(LayoutKind.Sequential)]
|
private struct RECT
|
{
|
public readonly int Left;
|
public readonly int Top;
|
public readonly int Right;
|
public readonly int Bottom;
|
|
private RECT(int left, int top, int right, int bottom)
|
{
|
Left = left;
|
Top = top;
|
Right = right;
|
Bottom = bottom;
|
}
|
|
public RECT(Rectangle r) : this(r.Left, r.Top, r.Right, r.Bottom)
|
{
|
}
|
}
|
}
|
|
#region MaterialTextBoxContextMenuStrip
|
|
[ToolboxItem(false)]
|
public class MaterialTextBoxContextMenuStrip : MaterialContextMenuStrip
|
{
|
public readonly ToolStripItem SelectAll = new MaterialToolStripMenuItem { Text = "Select All" };
|
public readonly ToolStripItem Separator2 = new ToolStripSeparator();
|
public readonly ToolStripItem Paste = new MaterialToolStripMenuItem { Text = "Paste" };
|
public readonly ToolStripItem Copy = new MaterialToolStripMenuItem { Text = "Copy" };
|
public readonly ToolStripItem Cut = new MaterialToolStripMenuItem { Text = "Cut" };
|
public readonly ToolStripItem Delete = new MaterialToolStripMenuItem { Text = "Delete" };
|
|
public MaterialTextBoxContextMenuStrip()
|
{
|
Items.AddRange(new[]
|
{
|
Cut,
|
Copy,
|
Paste,
|
Delete,
|
Separator2,
|
SelectAll
|
}
|
);
|
}
|
}
|
|
#endregion
|
|
#endregion
|
}
|