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;
|
|
/// <summary>
|
/// 模糊
|
/// </summary>
|
public int Blur { get; set; } = 15;
|
|
/// <summary>
|
/// 蔓延
|
/// </summary>
|
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;
|
|
/// <summary>
|
/// 拡張
|
/// </summary>
|
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<Control, AnimationManager> animationDict = new Dictionary<Control, AnimationManager>();
|
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<Control>().Where(c => ActiveName.Length > 0 && ActiveName == c.Name), e.Graphics);
|
DrawStyle(Controls.OfType<CTextBox>().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<Control> controls, Graphics g)
|
{
|
foreach (var control in controls)
|
{
|
DrawOutsetShadow(g, control);
|
}
|
}
|
|
private void DrawStyle(IEnumerable<Control> 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;
|
}
|
|
/// <summary>
|
/// 枠線
|
/// </summary>
|
/// <param name="g"></param>
|
/// <param name="control"></param>
|
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);
|
}
|
}
|
}
|
}
|