using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Linq;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using HotelPms.Share.Windows.Util;
using HotelPms.Share.Windows.Animations;
using HotelPms.Share.Windows.GraphicsApi;
namespace HotelPms.Share.Windows.Component
{
public class PanelEx : Panel
{
private int imgPadding = 5;
public int ArcWidth { get; set; } = 16;
public int OffsetX { get; set; } = 0;
public int OffsetY { get; set; } = 0;
///
/// 模糊
///
public int Blur { get; set; } = 15;
///
/// 蔓延
///
public int Spread { get; set; } = 15;
public bool UseTitleBookMark { get; set; } = true;
public Color TitleBookMarkColor { get; set; } = Color.Pink;
public string Title { get; set; } = string.Empty;
public Font TitleFont { get; set; } = DefaultFont;
public Font SignFont { get; set; } = DefaultFont;
public int TitleHeight { get; set; } = 0;
public Color TitleForeColor { get; set; } = Color.Black;
public Color TitleBackColor { get; set; } = Color.Gainsboro;
public int MaxHeight { get; set; } = -1;
private bool m_Expan = true;
///
/// 拡張
///
public bool Expan
{
get { return m_Expan; }
set
{
m_Expan = value;
if(!m_Expan && MaxHeight == -1) { MaxHeight = this.Height; }
//this.Height = m_Expan ? MaxHeight : MixHeight;
animationSelf.StartNewAnimation(m_Expan ? AnimationDirection.Out : AnimationDirection.In);
Invalidate();
}
}
private StringFormat m_StringFormat = new StringFormat();
private Rectangle m_TitleRect;
private string activeName = string.Empty;
public string ActiveName { get { return activeName; } set { activeName = value; Invalidate(); } }
private readonly Dictionary animationDict = new Dictionary();
private AnimationManager animationSelf;
public PanelEx()
{
SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor, true);
m_StringFormat.LineAlignment = StringAlignment.Center;
m_StringFormat.Alignment = StringAlignment.Near;
animationSelf = new AnimationManager
{
Increment = 0.03,
AnimationType = AnimationType.Linear,
InterruptAnimation = false,
};
animationSelf.OnAnimationProgress += _animationManager_OnAnimationProgress;
}
private void _animationManager_OnAnimationProgress(object sender)
{
Invalidate();
}
protected override void OnControlAdded(ControlEventArgs e)
{
if (e.Control is TextBox || e.Control is ComboBox)
{
e.Control.Enter += Control_Enter;
e.Control.Leave += Control_Leave;
IPanelEx child = e.Control as IPanelEx;
if (child != null)
{
System.Diagnostics.Debug.WriteLine($"{e.Control.Handle}:{e.Control.Name}:{child.PanelExEnabled}"); //←未設定
AnimationManager animationManager = new AnimationManager
{
Increment = 0.06,
AnimationType = AnimationType.EaseInOut,
InterruptAnimation = false,
};
animationManager.OnAnimationProgress += _animationManager_OnAnimationProgress;
animationDict.Add(e.Control, animationManager);
}
}
base.OnControlAdded(e);
}
private void Control_Leave(object sender, EventArgs e)
{
ActiveName = string.Empty;
IPanelEx child = sender as IPanelEx;
if (child != null && child.PanelExEnabled && (child.TitleStyle == CTextBox.ETitleStyle.Material || child.TitleStyle == CTextBox.ETitleStyle.Icon))
{
if (child.TitleStyle == CTextBox.ETitleStyle.Icon && (sender as Control).Text.Length > 0) { return; }
animationDict[child as Control].StartNewAnimation(AnimationDirection.Out);
}
}
private void Control_Enter(object sender, EventArgs e)
{
ActiveName = (sender as Control).Name;
IPanelEx child = sender as IPanelEx;
if (child != null && child.PanelExEnabled && (child.TitleStyle == CTextBox.ETitleStyle.Material || child.TitleStyle == CTextBox.ETitleStyle.Icon))
{
if (child.TitleStyle == CTextBox.ETitleStyle.Icon && (sender as Control).Text.Length > 0) { return; }
animationDict[child as Control].StartNewAnimation(AnimationDirection.In);
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
DrawShadow(Controls.OfType().Where(c => ActiveName.Length > 0 && ActiveName == c.Name), e.Graphics);
DrawStyle(Controls.OfType().Where(c => c.BorderStyle == BorderStyle.None), e.Graphics);
DrawTitle(e);
SetHeight(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (TitleHeight == 0) { return; }
Cursor = m_TitleRect.Contains(e.Location) ? Cursors.Hand : Cursors.Default;
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
if(!m_TitleRect.Contains(e.Location)) { return; }
Expan = !Expan;
}
private void DrawTitle(PaintEventArgs e)
{
if(TitleHeight == 0) { return; }
m_TitleRect = new Rectangle(UseTitleBookMark ? 5 : 0, 0, this.Width, TitleHeight);
using (SolidBrush backBrush = new SolidBrush(TitleBackColor))
{
e.Graphics.FillRectangle(backBrush, m_TitleRect);
}
if (UseTitleBookMark)
{
Rectangle markRect = new Rectangle(0, 0, 5, TitleHeight);
using (SolidBrush backBrush = new SolidBrush(TitleBookMarkColor))
{
e.Graphics.FillRectangle(backBrush, markRect);
}
}
//文言
using (SolidBrush foreBrush = new SolidBrush(TitleForeColor))
{
e.Graphics.DrawString(Title, TitleFont, foreBrush, m_TitleRect, m_StringFormat);
}
//矢印
int width = 30;
Rectangle signRect = new Rectangle(this.Width - width, 0, width, TitleHeight);
using (SolidBrush foreBrush = new SolidBrush(TitleForeColor))
{
e.Graphics.DrawString(m_Expan ? "▲" : "▼", SignFont, foreBrush, signRect, m_StringFormat);
}
}
private void SetHeight(PaintEventArgs e)
{
if (TitleHeight == 0 || MaxHeight <= 0) { return; }
if (!animationSelf.IsAnimating())
{
this.Height = m_Expan ? MaxHeight : TitleHeight;
System.Diagnostics.Debug.WriteLine($"animationSelf⇒END");
}
else
{
//Animate
int height = MaxHeight - TitleHeight;
int step = (int)(height * animationSelf.GetProgress());
if (m_Expan)
{
this.Height = TitleHeight + (height - step);
}
else
{
this.Height = MaxHeight - step;
}
System.Diagnostics.Debug.WriteLine($"animationSelf⇒{step}");
}
}
private void DrawShadow(IEnumerable controls, Graphics g)
{
foreach (var control in controls)
{
DrawOutsetShadow(g, control);
}
}
private void DrawStyle(IEnumerable controls, Graphics g)
{
foreach (var control in controls)
{
DrawControlStyle(g, control);
}
}
private Rectangle GetControlRect(Control control)
{
int titleWidth = 0;
if (control is IPanelEx)
{
IPanelEx child = control as IPanelEx;
if(child.PanelExEnabled)
{
if (child.TitleStyle == CTextBox.ETitleStyle.Label) { titleWidth = child.TitleWidth; }
else if (child.TitleStyle == CTextBox.ETitleStyle.Icon) { titleWidth = control.Height + imgPadding; }
}
}
int left = control.Left - ArcWidth / 2 - titleWidth;
int top = control.Top - ArcWidth / 2;
int width = control.Width + ArcWidth + titleWidth;
int height = control.Height + ArcWidth;
Rectangle r = new Rectangle(left, top, width, height);
return r;
}
///
/// 枠線
///
///
///
private void DrawControlStyle(Graphics g, Control control)
{
bool drawBorder = true;
Color borderColor = Color.FromArgb(255, 0, 120, 215); //255,0,120,215 (濃青) #7bc1f7 140, 123, 193, 247 (青) #22AC38 255, 34, 172, 56 (緑)
Rectangle r = GetControlRect(control);
if (control is IPanelEx)
{
IPanelEx child = control as IPanelEx;
if (child.PanelExEnabled)
{
borderColor = control.Focused ? child.BorderFocusColor : child.BorderColor;
if (child.TitleStyle == CTextBox.ETitleStyle.Material) { drawBorder = false; }
}
else
{
drawBorder = false;
}
}
if (drawBorder)
{
using (GraphicsPath path = new GraphicsPath())
{
path.AddArc(r.X, r.Y, ArcWidth, ArcWidth, 180, 90);
path.AddArc(r.X + r.Width - ArcWidth - 1, r.Y, ArcWidth, ArcWidth, -90, 90);
path.AddArc(r.X + r.Width - ArcWidth - 1, r.Y + r.Height - ArcWidth - 1, ArcWidth, ArcWidth, 0, 90);
path.AddArc(r.X, r.Y + r.Height - ArcWidth - 1, ArcWidth, ArcWidth, 90, 90);
path.CloseFigure();
using (Brush brush = new SolidBrush(control.BackColor))
{
g.FillPath(brush, path);
}
using (Pen pen = new Pen(borderColor)) //255,0,120,215 (濃青) #7bc1f7 140, 123, 193, 247 (青) #22AC38 255, 34, 172, 56 (緑)
{
g.DrawPath(pen, path);
}
}
}
//Labelを各
if (control is IPanelEx)
{
IPanelEx child = control as IPanelEx;
if (child.PanelExEnabled)
{
if (child.TitleStyle == CTextBox.ETitleStyle.Label)
{
int labelWidth = child.TitleWidth;
using (GraphicsPath path = new GraphicsPath())
{
path.AddArc(r.X, r.Y, ArcWidth, ArcWidth, 180, 90);
path.AddLine(new Point(r.X + labelWidth, r.Y), new Point(r.X + labelWidth, r.Y + r.Height - 1));
path.AddArc(r.X, r.Y + r.Height - ArcWidth - 1, ArcWidth, ArcWidth, 90, 90);
path.CloseFigure();
using (Brush brush = new SolidBrush(child.TitleBackColor))
{
g.FillPath(brush, path);
}
using (Pen pen = new Pen(borderColor)) //255,0,120,215 (濃青) #7bc1f7 140, 123, 193, 247 (青) #22AC38 255, 34, 172, 56 (緑) 255,122,122,122 gray
{
g.DrawPath(pen, path);
}
}
TextRenderer.DrawText(g, child.TitleText, child.TitleFont, new Rectangle(r.X, r.Y, child.TitleWidth, r.Height), child.TitleForeColor, TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter);
}
else if (child.TitleStyle == CTextBox.ETitleStyle.Icon)
{
if (child.ForeImage != null)
{
Rectangle imgRect = new Rectangle(control.Left - control.Height - imgPadding, control.Top, control.Width, control.Height);
GdiPlus.DrawImage(g, child.ForeImage as Bitmap, imgRect);
}
if (child is CTextBox)
{
CTextBox textBox = (child as CTextBox);
Size sizeText = TextRenderer.MeasureText(textBox.TipText, child.TitleFont);
int endX = r.X + 15; //タイトル文字最終的な位置 X
int endY = r.Y - sizeText.Height * 2 / 3; //タイトル文字最終的な位置 Y
if (animationDict.ContainsKey(control) && animationDict[control].IsAnimating())
{
double per = animationDict[control].GetProgress();
//位置、フォントサイズの変化 animationDict[control].GetProgress() in ⇒ enter ⇒ 増大, out ⇒ leave ⇒ 減少
float fontSize = textBox.Font.Size - (textBox.Font.Size - child.TitleFont.Size) * (float)per;
double curX = textBox.Left - (textBox.Left - endX) * per;
double curY = textBox.Top - (textBox.Top - endY) * per;
using (Font font = new Font(child.TitleFont.FontFamily, fontSize))
{
Rectangle textR = new Rectangle((int)curX, (int)curY, (int)(sizeText.Width * 1.2), sizeText.Height);
using (Brush brush = new SolidBrush(this.BackColor))
{
g.FillRectangle(brush, textR);
}
TextRenderer.DrawText(g, textBox.TipText, font, textR, borderColor, TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter);
}
}
else
{
if ((control.Focused || textBox.Text.Length > 0) && textBox.TipText.Length > 0)
{
Rectangle textR = new Rectangle(endX, endY, (int)(sizeText.Width * 1.2), sizeText.Height);
using (Brush brush = new SolidBrush(this.BackColor))
{
g.FillRectangle(brush, textR);
}
TextRenderer.DrawText(g, textBox.TipText, child.TitleFont, textR, borderColor, TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter);
}
}
}
}
else if (child.TitleStyle == CTextBox.ETitleStyle.Material && animationDict.ContainsKey(control))
{
var lineY = control.Bottom + 3;
if (!animationDict[control].IsAnimating())
{
using (Pen pen = new Pen(control.Focused ? child.ShadowColor : child.BorderColor, control.Focused ? 2F : 1F))
{
g.DrawLine(pen, control.Location.X, lineY, control.Location.X + control.Width, lineY);
}
}
else
{
//Animate
int animationWidth = (int)(control.Width * animationDict[control].GetProgress());
int halfAnimationWidth = animationWidth / 2;
int animationStart = control.Location.X + control.Width / 2;
using (Pen pen = new Pen(child.BorderColor, 1F))
{
g.DrawLine(pen, control.Location.X, lineY, control.Location.X + control.Width, lineY);
}
using (Pen pen = new Pen(child.ShadowColor, 2F))
{
g.DrawLine(pen, animationStart - halfAnimationWidth, lineY, animationStart - halfAnimationWidth + animationWidth, lineY);
}
}
}
}
}
}
// drawing the loop on an image because of speed
private void DrawOutsetShadow(Graphics g, Control control)
{
Color shadowColor = Color.FromArgb(140, 123, 193, 247); //#7bc1f7 140, 123, 193, 247 (青) #22AC38 140, 34, 172, 56 (緑)
if (control is IPanelEx)
{
IPanelEx child = control as IPanelEx;
if (child.PanelExEnabled)
{
shadowColor = child.ShadowColor;
if (child.TitleStyle == CTextBox.ETitleStyle.Material) { return; }
}
}
var rOuter = control.Bounds;
var rInner = control.Bounds;
if (control is CTextBox && (control as CTextBox).BorderStyle == BorderStyle.None)
{
Rectangle r = GetControlRect(control);
rOuter = r;
rInner = r;
}
rInner.Offset(OffsetX, OffsetY);
rInner.Inflate(-Blur, -Blur);
rOuter.Inflate(Spread, Spread);
rOuter.Offset(OffsetX, OffsetY);
var originalOuter = rOuter;
using (var img = new Bitmap(originalOuter.Width, originalOuter.Height, g))
{
using (var g2 = Graphics.FromImage(img))
{
var currentBlur = 0;
do
{
var transparency = (rOuter.Height - rInner.Height) / (double)(Blur * 2 + Spread * 3);
transparency -= 0.02;
var color = Color.FromArgb(((int)(255 * (transparency * transparency))), shadowColor);
var rOutput = rInner;
rOutput.Offset(-originalOuter.Left, -originalOuter.Top);
DrawRoundedRectangle(g2, rOutput, currentBlur, Pens.Transparent, color);
rInner.Inflate(1, 1);
currentBlur = (int)((double)Blur * (1 - (transparency * transparency)));
} while (rOuter.Contains(rInner));
g2.Flush();
}
g.DrawImage(img, originalOuter);
}
}
private void DrawRoundedRectangle(Graphics gfx, Rectangle bounds, int cornerRadius, Pen drawPen, Color fillColor)
{
int strokeOffset = Convert.ToInt32(Math.Ceiling(drawPen.Width));
bounds = Rectangle.Inflate(bounds, -strokeOffset, -strokeOffset);
var gfxPath = new GraphicsPath();
if (cornerRadius > 0)
{
gfxPath.AddArc(bounds.X, bounds.Y, cornerRadius, cornerRadius, 180, 90);
gfxPath.AddArc(bounds.X + bounds.Width - cornerRadius, bounds.Y, cornerRadius, cornerRadius, 270, 90);
gfxPath.AddArc(bounds.X + bounds.Width - cornerRadius, bounds.Y + bounds.Height - cornerRadius, cornerRadius, cornerRadius, 0, 90);
gfxPath.AddArc(bounds.X, bounds.Y + bounds.Height - cornerRadius, cornerRadius, cornerRadius, 90, 90);
}
else
{
gfxPath.AddRectangle(bounds);
}
gfxPath.CloseAllFigures();
gfx.FillPath(new SolidBrush(fillColor), gfxPath);
if (drawPen != Pens.Transparent)
{
var pen = new Pen(drawPen.Color);
pen.EndCap = pen.StartCap = LineCap.Round;
gfx.DrawPath(pen, gfxPath);
}
}
}
}