From 794c8bb080d42cde39dac5c871755abe28c94c76 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Tue, 13 Jan 2015 22:13:52 +0800 Subject: [PATCH] refine qrcode --- .../Properties/Resources.Designer.cs | 7 +- shadowsocks-csharp/View/MenuViewController.cs | 6 +- .../View/QRCodeSplashForm.Designer.cs | 72 ---- shadowsocks-csharp/View/QRCodeSplashForm.cs | 309 ++++++++++++++++-- shadowsocks-csharp/View/QRCodeSplashForm.resx | 120 ------- shadowsocks-csharp/shadowsocks-csharp.csproj | 6 - 6 files changed, 291 insertions(+), 229 deletions(-) delete mode 100755 shadowsocks-csharp/View/QRCodeSplashForm.Designer.cs delete mode 100755 shadowsocks-csharp/View/QRCodeSplashForm.resx diff --git a/shadowsocks-csharp/Properties/Resources.Designer.cs b/shadowsocks-csharp/Properties/Resources.Designer.cs index 5139429f..f6db05ad 100755 --- a/shadowsocks-csharp/Properties/Resources.Designer.cs +++ b/shadowsocks-csharp/Properties/Resources.Designer.cs @@ -76,12 +76,13 @@ namespace Shadowsocks.Properties { ///Mode=代理模式 ///PAC=PAC 模式 ///Global=全局模式 - ///Servers=服务器选择 + ///Servers=服务器 ///Edit Servers...=编辑服务器... ///Start on Boot=开机启动 ///Share over LAN=在局域网共享代理 ///Edit PAC File...=编辑 PAC 文件... ///Show QRCode...=显示二维码... + ///Scan QRCode from Screen...=扫描屏幕上的二维码... ///Show Logs...=显示日志... ///About...=关于... ///Quit=退出 @@ -99,9 +100,7 @@ namespace Shadowsocks.Properties { ///Cancel=取消 ///New server=未配置的服务器 ///QRCode=二维码 - ///Shadowsocks Error: {0}=Shadowsocks 错误: {0} - ///Port already in use=端口已被占用 - ///Il [rest of string was truncated]";. + ///Shadowsocks Error: {0}=Shadowsocks [rest of string was truncated]";. /// internal static string cn { get { diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index f8b33e92..1794e7e2 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -425,10 +425,10 @@ namespace Shadowsocks.View maxX += margin + marginLeft; minY += -margin + marginTop; maxY += margin + marginTop; - splash.Location = new Point((int)minX, (int)minY); + splash.Location = new Point(0, 0); // we need a panel because a window has a minimal size - splash.Panel.Size = new Size((int)maxX - (int)minX, (int)maxY - (int)minY); - splash.Size = splash.Panel.Size; + splash.TargetRect = new Rectangle((int)minX, (int)minY, (int)maxX - (int)minX, (int)maxY - (int)minY); + splash.Size = new Size(fullImage.Width, fullImage.Height); splash.Show(); return; } diff --git a/shadowsocks-csharp/View/QRCodeSplashForm.Designer.cs b/shadowsocks-csharp/View/QRCodeSplashForm.Designer.cs deleted file mode 100755 index 0c7e1601..00000000 --- a/shadowsocks-csharp/View/QRCodeSplashForm.Designer.cs +++ /dev/null @@ -1,72 +0,0 @@ -namespace Shadowsocks.View -{ - partial class QRCodeSplashForm - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.Panel = new System.Windows.Forms.Panel(); - this.SuspendLayout(); - // - // Panel - // - this.Panel.BackColor = System.Drawing.Color.Crimson; - this.Panel.Location = new System.Drawing.Point(0, 0); - this.Panel.Margin = new System.Windows.Forms.Padding(0); - this.Panel.Name = "Panel"; - this.Panel.Size = new System.Drawing.Size(168, 158); - this.Panel.TabIndex = 0; - // - // QRCodeSplashForm - // - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; - this.BackColor = System.Drawing.Color.White; - this.ClientSize = new System.Drawing.Size(284, 262); - this.ControlBox = false; - this.Controls.Add(this.Panel); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "QRCodeSplashForm"; - this.Opacity = 0.3D; - this.ShowIcon = false; - this.ShowInTaskbar = false; - this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; - this.Text = "QRCodeSplashForm"; - this.TopMost = true; - this.TransparencyKey = System.Drawing.Color.White; - this.Load += new System.EventHandler(this.QRCodeSplashForm_Load); - this.ResumeLayout(false); - - } - - #endregion - - public System.Windows.Forms.Panel Panel; - - } -} \ No newline at end of file diff --git a/shadowsocks-csharp/View/QRCodeSplashForm.cs b/shadowsocks-csharp/View/QRCodeSplashForm.cs index 3d14785e..f18377b9 100755 --- a/shadowsocks-csharp/View/QRCodeSplashForm.cs +++ b/shadowsocks-csharp/View/QRCodeSplashForm.cs @@ -5,60 +5,321 @@ using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; + namespace Shadowsocks.View { - public partial class QRCodeSplashForm : Form + public class QRCodeSplashForm : PerPixelAlphaForm { + public class QRRectView : Control + { + private Pen pen; + private Brush brush; + + public QRRectView() + { + pen = new Pen(Color.Red, 3); + brush = new SolidBrush(Color.FromArgb(100, Color.Red)); + SetStyle(ControlStyles.ResizeRedraw, true); + SetStyle(ControlStyles.SupportsTransparentBackColor, true); + this.BackColor = Color.Transparent; + this.DoubleBuffered = true; + } + + protected override void OnPaint(PaintEventArgs e) + { + Graphics g = e.Graphics; + g.FillRectangle(brush, 0, 0, Width, Height); + g.DrawRectangle(pen, 0, 0, Width, Height); + } + } + public Rectangle TargetRect; + public QRCodeSplashForm() { - InitializeComponent(); + this.Load += QRCodeSplashForm_Load; + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.BackColor = System.Drawing.Color.White; + this.ClientSize = new System.Drawing.Size(284, 262); + this.ControlBox = false; + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "QRCodeSplashForm"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.TopMost = true; + } private Timer timer; - private int step; + private int animationStep; + private int flashStep; + private static int ANIMATION_STEPS = 30; + private static double ANIMATION_TIME = 0.3; + private QRRectView codeRectView; + int x; + int y; + int w; + int h; + Bitmap bitmap; + Graphics g; + Pen pen; + SolidBrush brush; private void QRCodeSplashForm_Load(object sender, EventArgs e) { - step = 0; + SetStyle(ControlStyles.SupportsTransparentBackColor, true); + this.BackColor = Color.Transparent; + animationStep = 0; + flashStep = 0; + //codeRectView = new QRRectView(); + x = 0; + y = 0; + w = Width; + h = Height; + //this.Controls.Add(codeRectView); timer = new Timer(); - timer.Interval = 300; + timer.Interval = (int)(ANIMATION_TIME * 1000 / ANIMATION_STEPS); timer.Tick += timer_Tick; timer.Start(); + bitmap = new Bitmap(Width, Height, PixelFormat.Format32bppArgb); + g = Graphics.FromImage(bitmap); + pen = new Pen(Color.Red, 3); + brush = new SolidBrush(Color.FromArgb(30, Color.Red)); } - void timer_Tick(object sender, EventArgs e) + protected override CreateParams CreateParams { - timer.Interval = 40; - if (step == 0) + get { - this.Opacity = 0; + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x00080000; // This form has to have the WS_EX_LAYERED extended style + return cp; } - else if (step == 1) - { - this.Opacity = 0.3; - } - else if (step == 1) + } + + void timer_Tick(object sender, EventArgs e) + { + if (animationStep < ANIMATION_STEPS) { - this.Opacity = 0.0; + animationStep++; + double percent = (double)animationStep / (double)ANIMATION_STEPS; + // ease out + percent = 1 - Math.Pow((1 - percent), 4); + x = (int)(TargetRect.X * percent); + y = (int)(TargetRect.Y * percent); + w = (int)(TargetRect.Width * percent + this.Size.Width * (1 - percent)); + h = (int)(TargetRect.Height * percent + this.Size.Height * (1 - percent)); + //codeRectView.Location = new Point(x, y); + //codeRectView.Size = new Size(w, h); + pen.Color = Color.FromArgb((int)(255 * percent), Color.Red); + brush.Color = Color.FromArgb((int)(30 * percent), Color.Red); + g.Clear(Color.Transparent); + g.FillRectangle(brush, x, y, w, h); + g.DrawRectangle(pen, x, y, w, h); + SetBitmap(bitmap); } - else if (step == 2) + else { - this.Opacity = 0.3; + timer.Interval = 50; + if (flashStep == 0) + { + g.Clear(Color.Transparent); + SetBitmap(bitmap); + } + else if (flashStep == 1) + { + g.FillRectangle(brush, x, y, w, h); + g.DrawRectangle(pen, x, y, w, h); + SetBitmap(bitmap); + } + else if (flashStep == 1) + { + g.Clear(Color.Transparent); + SetBitmap(bitmap); + } + else if (flashStep == 2) + { + g.FillRectangle(brush, x, y, w, h); + g.DrawRectangle(pen, x, y, w, h); + SetBitmap(bitmap); + } + else if (flashStep == 3) + { + g.Clear(Color.Transparent); + SetBitmap(bitmap); + } + else if (flashStep == 4) + { + g.FillRectangle(brush, x, y, w, h); + g.DrawRectangle(pen, x, y, w, h); + SetBitmap(bitmap); + } + else + { + timer.Stop(); + pen.Dispose(); + brush.Dispose(); + bitmap.Dispose(); + this.Close(); + } + flashStep++; } - else if (step == 3) + } + } + + + // class that exposes needed win32 gdi functions. + class Win32 + { + + [StructLayout(LayoutKind.Sequential)] + public struct Point + { + public Int32 x; + public Int32 y; + + public Point(Int32 x, Int32 y) { this.x = x; this.y = y; } + } + + + [StructLayout(LayoutKind.Sequential)] + public struct Size + { + public Int32 cx; + public Int32 cy; + + public Size(Int32 cx, Int32 cy) { this.cx = cx; this.cy = cy; } + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ARGB + { + public byte Blue; + public byte Green; + public byte Red; + public byte Alpha; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct BLENDFUNCTION + { + public byte BlendOp; + public byte BlendFlags; + public byte SourceConstantAlpha; + public byte AlphaFormat; + } + + + public const Int32 ULW_COLORKEY = 0x00000001; + public const Int32 ULW_ALPHA = 0x00000002; + public const Int32 ULW_OPAQUE = 0x00000004; + + public const byte AC_SRC_OVER = 0x00; + public const byte AC_SRC_ALPHA = 0x01; + + + [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] + public static extern int UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags); + + [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] + public static extern IntPtr GetDC(IntPtr hWnd); + + [DllImport("user32.dll", ExactSpelling = true)] + public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); + + [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] + public static extern IntPtr CreateCompatibleDC(IntPtr hDC); + + [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] + public static extern int DeleteDC(IntPtr hdc); + + [DllImport("gdi32.dll", ExactSpelling = true)] + public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); + + [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] + public static extern int DeleteObject(IntPtr hObject); + } + + + public class PerPixelAlphaForm : Form + { + // http://www.codeproject.com/Articles/1822/Per-Pixel-Alpha-Blend-in-C + // Rui Lopes + + public PerPixelAlphaForm() + { + // This form should not have a border or else Windows will clip it. + FormBorderStyle = FormBorderStyle.None; + } + + public void SetBitmap(Bitmap bitmap) + { + SetBitmap(bitmap, 255); + } + + + /// Changes the current bitmap with a custom opacity level. Here is where all happens! + public void SetBitmap(Bitmap bitmap, byte opacity) + { + if (bitmap.PixelFormat != PixelFormat.Format32bppArgb) + throw new ApplicationException("The bitmap must be 32ppp with alpha-channel."); + + // The ideia of this is very simple, + // 1. Create a compatible DC with screen; + // 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC; + // 3. Call the UpdateLayeredWindow. + + IntPtr screenDc = Win32.GetDC(IntPtr.Zero); + IntPtr memDc = Win32.CreateCompatibleDC(screenDc); + IntPtr hBitmap = IntPtr.Zero; + IntPtr oldBitmap = IntPtr.Zero; + + try { - this.Opacity = 0.0; + hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap + oldBitmap = Win32.SelectObject(memDc, hBitmap); + + Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height); + Win32.Point pointSource = new Win32.Point(0, 0); + Win32.Point topPos = new Win32.Point(Left, Top); + Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION(); + blend.BlendOp = Win32.AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = opacity; + blend.AlphaFormat = Win32.AC_SRC_ALPHA; + + Win32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA); } - else if (step == 4) + finally { - this.Opacity = 0.3; + Win32.ReleaseDC(IntPtr.Zero, screenDc); + if (hBitmap != IntPtr.Zero) + { + Win32.SelectObject(memDc, oldBitmap); + //Windows.DeleteObject(hBitmap); // The documentation says that we have to use the Windows.DeleteObject... but since there is no such method I use the normal DeleteObject from Win32 GDI and it's working fine without any resource leak. + Win32.DeleteObject(hBitmap); + } + Win32.DeleteDC(memDc); } - else + } + + + protected override CreateParams CreateParams + { + get { - this.Close(); + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x00080000; // This form has to have the WS_EX_LAYERED extended style + return cp; } - step++; } } } diff --git a/shadowsocks-csharp/View/QRCodeSplashForm.resx b/shadowsocks-csharp/View/QRCodeSplashForm.resx deleted file mode 100755 index 5ea0895e..00000000 --- a/shadowsocks-csharp/View/QRCodeSplashForm.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index e5da1098..61820eaa 100755 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -169,9 +169,6 @@ Form - - QRCodeSplashForm.cs - ConfigForm.cs Designer @@ -184,9 +181,6 @@ QRCodeForm.cs - - QRCodeSplashForm.cs - Designer