// COPYRIGHT (C) Tom. ALL RIGHTS RESERVED. // THE AntdUI PROJECT IS AN WINFORM LIBRARY LICENSED UNDER THE Apache-2.0 License. // LICENSED UNDER THE Apache License, VERSION 2.0 (THE "License") // YOU MAY NOT USE THIS FILE EXCEPT IN COMPLIANCE WITH THE License. // YOU MAY OBTAIN A COPY OF THE LICENSE AT // // http://www.apache.org/licenses/LICENSE-2.0 // // UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, SOFTWARE // DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING PERMISSIONS AND // LIMITATIONS UNDER THE License. // GITEE: https://gitee.com/antdui/AntdUI // GITHUB: https://github.com/AntdUI/AntdUI // CSDN: https://blog.csdn.net/v_132 // QQ: 17379620 using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; using System.Threading; using System.Windows.Forms; namespace AntdUI { [ToolboxItem(true)] public class Image3D : IControl, ShadowConfig { #region 属性 Color back = Color.Transparent; /// /// 背景颜色 /// [Description("背景颜色"), Category("外观"), DefaultValue(typeof(Color), "Transparent")] public Color Back { get => back; set { if (back == value) return; back = value; Invalidate(); } } int radius = 0; /// /// 圆角 /// [Description("圆角"), Category("外观"), DefaultValue(0)] public int Radius { get => radius; set { if (radius == value) return; radius = value; Invalidate(); } } bool round = false; /// /// 圆角样式 /// [Description("圆角样式"), Category("外观"), DefaultValue(false)] public bool Round { get => round; set { if (round == value) return; round = value; Invalidate(); } } Image? image = null; /// /// 图片 /// [Description("图片"), Category("外观"), DefaultValue(null)] public Image? Image { get => image; set { if (image == value) return; if (image != null && value != null) { var t = Animation.TotalFrames(Speed, Duration); float _radius = radius * Config.Dpi; ITask.Run(() => { var _rect = ClientRectangle; var rect = _rect.PaddingRect(Padding); using (var bmpo = new Bitmap(_rect.Width, _rect.Height)) using (var bmpo2 = new Bitmap(_rect.Width, _rect.Height)) { using (var g = Graphics.FromImage(bmpo).High()) { if (shadow > 0 && shadowOpacity > 0) g.PaintShadow(this, _rect, rect, _radius, round); g.PaintImg(rect, image, imageFit, _radius, round); } using (var g = Graphics.FromImage(bmpo2).High()) { if (shadow > 0 && shadowOpacity > 0) g.PaintShadow(this, _rect, rect, _radius, round); g.PaintImg(rect, value, imageFit, _radius, round); } var images = new List(t); if (Vertical) { for (int i = 0; i < t; i++) { var prog = Animation.Animate(i + 1, t, 180, AnimationType.Ease); var cube = new Cube(bmpo.Width, bmpo.Height, 1); if (prog > 90) { prog = prog - 180; cube.RotateX = prog; cube.calcCube(_rect.Location); var bmp = cube.ToBitmap(bmpo2); bmp.Tag = cube.CentreX(); images.Add(bmp); } else { cube.RotateX = prog; cube.calcCube(_rect.Location); var bmp = cube.ToBitmap(bmpo); bmp.Tag = cube.CentreX(); images.Add(bmp); } } } else { for (int i = 0; i < t; i++) { var prog = Animation.Animate(i + 1, t, 180, AnimationType.Ease); var cube = new Cube(bmpo.Width, bmpo.Height, 1); if (prog > 90) { prog = prog - 180; cube.RotateY = prog; cube.calcCube(_rect.Location); var bmp = cube.ToBitmap(bmpo2); bmp.Tag = cube.CentreY(); images.Add(bmp); } else { cube.RotateY = prog; cube.calcCube(_rect.Location); var bmp = cube.ToBitmap(bmpo); bmp.Tag = cube.CentreY(); images.Add(bmp); } } } for (int i = 0; i < images.Count; i++) { run = images[i]; Invalidate(); Thread.Sleep(Speed); } } run?.Dispose(); run = null; image = value; Invalidate(); }); } else { image = value; Invalidate(); } } } TFit imageFit = TFit.Cover; /// /// 图片布局 /// [Description("图片布局"), Category("外观"), DefaultValue(TFit.Cover)] public TFit ImageFit { get => imageFit; set { if (imageFit == value) return; imageFit = value; Invalidate(); } } /// /// 是否竖向 /// [Description("是否竖向"), Category("动画"), DefaultValue(false)] public bool Vertical { get; set; } = false; /// /// 速度 /// [Description("速度"), Category("动画"), DefaultValue(10)] public int Speed { get; set; } = 10; /// /// 速度 /// [Description("速度"), Category("动画"), DefaultValue(400)] public int Duration { get; set; } = 400; #region 阴影 int shadow = 0; /// /// 阴影大小 /// [Description("阴影"), Category("外观"), DefaultValue(0)] public int Shadow { get => shadow; set { if (shadow == value) return; shadow = value; Invalidate(); } } /// /// 阴影颜色 /// [Description("阴影颜色"), Category("阴影"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public Color? ShadowColor { get; set; } float shadowOpacity = 0.3F; /// /// 阴影透明度 /// [Description("阴影透明度"), Category("阴影"), DefaultValue(0.3F)] public float ShadowOpacity { get => shadowOpacity; set { if (shadowOpacity == value) return; if (value < 0) value = 0; else if (value > 1) value = 1; shadowOpacity = value; Invalidate(); } } int shadowOffsetX = 0; /// /// 阴影偏移X /// [Description("阴影偏移X"), Category("阴影"), DefaultValue(0)] public int ShadowOffsetX { get => shadowOffsetX; set { if (shadowOffsetX == value) return; shadowOffsetX = value; Invalidate(); } } int shadowOffsetY = 0; /// /// 阴影偏移Y /// [Description("阴影偏移Y"), Category("阴影"), DefaultValue(0)] public int ShadowOffsetY { get => shadowOffsetY; set { if (shadowOffsetY == value) return; shadowOffsetY = value; Invalidate(); } } #endregion #endregion #region 渲染 Bitmap? run = null; protected override void OnPaint(PaintEventArgs e) { var _rect = ClientRectangle; if (image == null || _rect.Width == 0 || _rect.Height == 0) return; var g = e.Graphics.High(); var rect = _rect.PaddingRect(Padding); float _radius = radius * Config.Dpi; FillRect(g, rect, back, _radius, round); if (run != null && run.Tag is PointF point) g.DrawImage(run, point.X, point.Y, run.Width, run.Height); else { if (shadow > 0 && shadowOpacity > 0) g.PaintShadow(this, _rect, rect, _radius, round); g.PaintImg(rect, image, imageFit, _radius, round); } this.PaintBadge(g); base.OnPaint(e); } #region 渲染帮助 void FillRect(Graphics g, RectangleF rect, Color color, float radius, bool round) { using (var brush = new SolidBrush(color)) { if (round) { g.FillEllipse(brush, rect); } else if (radius > 0) { using (var path = rect.RoundPath(radius)) { g.FillPath(brush, path); } } else { g.FillRectangle(brush, rect); } } } #endregion #endregion } }