@@ -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]";. | |||
/// </summary> | |||
internal static string cn { | |||
get { | |||
@@ -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; | |||
} | |||
@@ -1,72 +0,0 @@ | |||
namespace Shadowsocks.View | |||
{ | |||
partial class QRCodeSplashForm | |||
{ | |||
/// <summary> | |||
/// Required designer variable. | |||
/// </summary> | |||
private System.ComponentModel.IContainer components = null; | |||
/// <summary> | |||
/// Clean up any resources being used. | |||
/// </summary> | |||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> | |||
protected override void Dispose(bool disposing) | |||
{ | |||
if (disposing && (components != null)) | |||
{ | |||
components.Dispose(); | |||
} | |||
base.Dispose(disposing); | |||
} | |||
#region Windows Form Designer generated code | |||
/// <summary> | |||
/// Required method for Designer support - do not modify | |||
/// the contents of this method with the code editor. | |||
/// </summary> | |||
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; | |||
} | |||
} |
@@ -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); | |||
} | |||
/// <para>Changes the current bitmap with a custom opacity level. Here is where all happens!</para> | |||
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++; | |||
} | |||
} | |||
} |
@@ -1,120 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<root> | |||
<!-- | |||
Microsoft ResX Schema | |||
Version 2.0 | |||
The primary goals of this format is to allow a simple XML format | |||
that is mostly human readable. The generation and parsing of the | |||
various data types are done through the TypeConverter classes | |||
associated with the data types. | |||
Example: | |||
... ado.net/XML headers & schema ... | |||
<resheader name="resmimetype">text/microsoft-resx</resheader> | |||
<resheader name="version">2.0</resheader> | |||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | |||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | |||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | |||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | |||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | |||
<value>[base64 mime encoded serialized .NET Framework object]</value> | |||
</data> | |||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | |||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | |||
<comment>This is a comment</comment> | |||
</data> | |||
There are any number of "resheader" rows that contain simple | |||
name/value pairs. | |||
Each data row contains a name, and value. The row also contains a | |||
type or mimetype. Type corresponds to a .NET class that support | |||
text/value conversion through the TypeConverter architecture. | |||
Classes that don't support this are serialized and stored with the | |||
mimetype set. | |||
The mimetype is used for serialized objects, and tells the | |||
ResXResourceReader how to depersist the object. This is currently not | |||
extensible. For a given mimetype the value must be set accordingly: | |||
Note - application/x-microsoft.net.object.binary.base64 is the format | |||
that the ResXResourceWriter will generate, however the reader can | |||
read any of the formats listed below. | |||
mimetype: application/x-microsoft.net.object.binary.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.soap.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.bytearray.base64 | |||
value : The object must be serialized into a byte array | |||
: using a System.ComponentModel.TypeConverter | |||
: and then encoded with base64 encoding. | |||
--> | |||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | |||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> | |||
<xsd:element name="root" msdata:IsDataSet="true"> | |||
<xsd:complexType> | |||
<xsd:choice maxOccurs="unbounded"> | |||
<xsd:element name="metadata"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" use="required" type="xsd:string" /> | |||
<xsd:attribute name="type" type="xsd:string" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="assembly"> | |||
<xsd:complexType> | |||
<xsd:attribute name="alias" type="xsd:string" /> | |||
<xsd:attribute name="name" type="xsd:string" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="data"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> | |||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="resheader"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:choice> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:schema> | |||
<resheader name="resmimetype"> | |||
<value>text/microsoft-resx</value> | |||
</resheader> | |||
<resheader name="version"> | |||
<value>2.0</value> | |||
</resheader> | |||
<resheader name="reader"> | |||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<resheader name="writer"> | |||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
</root> |
@@ -169,9 +169,6 @@ | |||
<Compile Include="View\QRCodeSplashForm.cs"> | |||
<SubType>Form</SubType> | |||
</Compile> | |||
<Compile Include="View\QRCodeSplashForm.Designer.cs"> | |||
<DependentUpon>QRCodeSplashForm.cs</DependentUpon> | |||
</Compile> | |||
<EmbeddedResource Include="View\ConfigForm.resx"> | |||
<DependentUpon>ConfigForm.cs</DependentUpon> | |||
<SubType>Designer</SubType> | |||
@@ -184,9 +181,6 @@ | |||
<EmbeddedResource Include="View\QRCodeForm.resx"> | |||
<DependentUpon>QRCodeForm.cs</DependentUpon> | |||
</EmbeddedResource> | |||
<EmbeddedResource Include="View\QRCodeSplashForm.resx"> | |||
<DependentUpon>QRCodeSplashForm.cs</DependentUpon> | |||
</EmbeddedResource> | |||
<None Include="app.config" /> | |||
<None Include="app.manifest"> | |||
<SubType>Designer</SubType> | |||