- Use ElementHost in QRCodeForm - Cleanup: Server.Equalstags/4.2.1.0
@@ -58,11 +58,7 @@ namespace Shadowsocks.Model | |||||
return server.GetHashCode() ^ server_port; | return server.GetHashCode() ^ server_port; | ||||
} | } | ||||
public override bool Equals(object obj) | |||||
{ | |||||
Server o2 = (Server)obj; | |||||
return server == o2.server && server_port == o2.server_port; | |||||
} | |||||
public override bool Equals(object obj) => obj is Server o2 && server == o2.server && server_port == o2.server_port; | |||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
@@ -28,73 +28,39 @@ | |||||
/// </summary> | /// </summary> | ||||
private void InitializeComponent() | private void InitializeComponent() | ||||
{ | { | ||||
this.pictureBox1 = new System.Windows.Forms.PictureBox(); | |||||
this.listBox1 = new System.Windows.Forms.ListBox(); | |||||
this.textBoxURL = new System.Windows.Forms.TextBox(); | |||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); | |||||
this.elementHost1 = new System.Windows.Forms.Integration.ElementHost(); | |||||
this.serverSharingView1 = new Shadowsocks.Views.ServerSharingView(); | |||||
this.SuspendLayout(); | this.SuspendLayout(); | ||||
// | // | ||||
// pictureBox1 | |||||
// elementHost1 | |||||
// | // | ||||
this.pictureBox1.Location = new System.Drawing.Point(10, 10); | |||||
this.pictureBox1.Margin = new System.Windows.Forms.Padding(0); | |||||
this.pictureBox1.Name = "pictureBox1"; | |||||
this.pictureBox1.Size = new System.Drawing.Size(210, 210); | |||||
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; | |||||
this.pictureBox1.TabIndex = 1; | |||||
this.pictureBox1.TabStop = false; | |||||
// | |||||
// listBox1 | |||||
// | |||||
this.listBox1.DisplayMember = "Value"; | |||||
this.listBox1.FormattingEnabled = true; | |||||
this.listBox1.ItemHeight = 12; | |||||
this.listBox1.Location = new System.Drawing.Point(224, 10); | |||||
this.listBox1.Name = "listBox1"; | |||||
this.listBox1.ScrollAlwaysVisible = true; | |||||
this.listBox1.Size = new System.Drawing.Size(227, 208); | |||||
this.listBox1.TabIndex = 2; | |||||
this.listBox1.ValueMember = "Key"; | |||||
this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged); | |||||
// | |||||
// textBoxURL | |||||
// | |||||
this.textBoxURL.Location = new System.Drawing.Point(10, 227); | |||||
this.textBoxURL.Name = "textBoxURL"; | |||||
this.textBoxURL.ReadOnly = true; | |||||
this.textBoxURL.Size = new System.Drawing.Size(441, 21); | |||||
this.textBoxURL.TabIndex = 3; | |||||
this.textBoxURL.Click += new System.EventHandler(this.textBoxURL_Click); | |||||
this.elementHost1.Dock = System.Windows.Forms.DockStyle.Fill; | |||||
this.elementHost1.Location = new System.Drawing.Point(0, 0); | |||||
this.elementHost1.Margin = new System.Windows.Forms.Padding(0); | |||||
this.elementHost1.Name = "elementHost1"; | |||||
this.elementHost1.Size = new System.Drawing.Size(600, 340); | |||||
this.elementHost1.TabIndex = 0; | |||||
this.elementHost1.Text = "elementHost1"; | |||||
this.elementHost1.Child = this.serverSharingView1; | |||||
// | // | ||||
// QRCodeForm | // QRCodeForm | ||||
// | // | ||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); | this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); | ||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; | ||||
this.AutoSize = true; | |||||
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; | |||||
this.BackColor = System.Drawing.Color.White; | this.BackColor = System.Drawing.Color.White; | ||||
this.ClientSize = new System.Drawing.Size(457, 257); | |||||
this.Controls.Add(this.textBoxURL); | |||||
this.Controls.Add(this.listBox1); | |||||
this.Controls.Add(this.pictureBox1); | |||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; | |||||
this.MaximizeBox = false; | |||||
this.MinimizeBox = false; | |||||
this.ClientSize = new System.Drawing.Size(600, 340); | |||||
this.Controls.Add(this.elementHost1); | |||||
this.Margin = new System.Windows.Forms.Padding(8); | |||||
this.Name = "QRCodeForm"; | this.Name = "QRCodeForm"; | ||||
this.Padding = new System.Windows.Forms.Padding(10); | |||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; | ||||
this.Text = "QRCode and URL"; | this.Text = "QRCode and URL"; | ||||
this.Load += new System.EventHandler(this.QRCodeForm_Load); | this.Load += new System.EventHandler(this.QRCodeForm_Load); | ||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); | |||||
this.ResumeLayout(false); | this.ResumeLayout(false); | ||||
this.PerformLayout(); | |||||
} | } | ||||
#endregion | #endregion | ||||
private System.Windows.Forms.PictureBox pictureBox1; | |||||
private System.Windows.Forms.ListBox listBox1; | |||||
private System.Windows.Forms.TextBox textBoxURL; | |||||
private System.Windows.Forms.Integration.ElementHost elementHost1; | |||||
private Views.ServerSharingView serverSharingView1; | |||||
} | } | ||||
} | } |
@@ -27,64 +27,9 @@ namespace Shadowsocks.View | |||||
this.Text = I18N.GetString("QRCode and URL"); | this.Text = I18N.GetString("QRCode and URL"); | ||||
} | } | ||||
private void GenQR(string ssconfig) | |||||
{ | |||||
string qrText = ssconfig; | |||||
QRCode code = ZXing.QrCode.Internal.Encoder.encode(qrText, ErrorCorrectionLevel.M); | |||||
ByteMatrix m = code.Matrix; | |||||
int blockSize = Math.Max(pictureBox1.Height/m.Height, 1); | |||||
var qrWidth = m.Width*blockSize; | |||||
var qrHeight = m.Height*blockSize; | |||||
var dWidth = pictureBox1.Width - qrWidth; | |||||
var dHeight = pictureBox1.Height - qrHeight; | |||||
var maxD = Math.Max(dWidth, dHeight); | |||||
pictureBox1.SizeMode = maxD >= 7*blockSize ? PictureBoxSizeMode.Zoom : PictureBoxSizeMode.CenterImage; | |||||
Bitmap drawArea = new Bitmap((m.Width*blockSize), (m.Height*blockSize)); | |||||
using (Graphics g = Graphics.FromImage(drawArea)) | |||||
{ | |||||
g.Clear(Color.White); | |||||
using (Brush b = new SolidBrush(Color.Black)) | |||||
{ | |||||
for (int row = 0; row < m.Width; row++) | |||||
{ | |||||
for (int col = 0; col < m.Height; col++) | |||||
{ | |||||
if (m[row, col] != 0) | |||||
{ | |||||
g.FillRectangle(b, blockSize*row, blockSize*col, blockSize, blockSize); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
pictureBox1.Image = drawArea; | |||||
} | |||||
private void QRCodeForm_Load(object sender, EventArgs e) | private void QRCodeForm_Load(object sender, EventArgs e) | ||||
{ | { | ||||
Configuration config = Configuration.Load(); | |||||
List<KeyValuePair<string, string>> serverDatas = config.configs.Select( | |||||
server => | |||||
new KeyValuePair<string, string>(server.GetURL(config.generateLegacyUrl), server.ToString()) | |||||
).ToList(); | |||||
listBox1.DataSource = serverDatas; | |||||
int selectIndex = serverDatas.FindIndex(serverData => serverData.Key.StartsWith(code)); | |||||
if (selectIndex >= 0) listBox1.SetSelected(selectIndex, true); | |||||
} | |||||
private void listBox1_SelectedIndexChanged(object sender, EventArgs e) | |||||
{ | |||||
var url = (sender as ListBox)?.SelectedValue.ToString(); | |||||
GenQR(url); | |||||
textBoxURL.Text = url; | |||||
} | |||||
private void textBoxURL_Click(object sender, EventArgs e) | |||||
{ | |||||
textBoxURL.SelectAll(); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -0,0 +1,109 @@ | |||||
using ReactiveUI; | |||||
using Shadowsocks.Model; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Drawing; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Windows.Media.Imaging; | |||||
namespace Shadowsocks.ViewModels | |||||
{ | |||||
public class ServerSharingViewModel : ReactiveObject | |||||
{ | |||||
/// <summary> | |||||
/// The view model class for the server sharing user control. | |||||
/// </summary> | |||||
public ServerSharingViewModel() | |||||
{ | |||||
_config = Configuration.Load(); | |||||
_servers = _config.configs; | |||||
_selectedServer = _servers.First(); | |||||
//_selectedServerUrlImage = new BitmapImage(); | |||||
UpdateUrlAndImage(); | |||||
} | |||||
private readonly Configuration _config; | |||||
private List<Server> _servers; | |||||
private Server _selectedServer; | |||||
private string _selectedServerUrl; | |||||
private BitmapImage _selectedServerUrlImage; | |||||
/// <summary> | |||||
/// Called when SelectedServer changed | |||||
/// to update SelectedServerUrl and SelectedServerUrlImage | |||||
/// </summary> | |||||
private void UpdateUrlAndImage() | |||||
{ | |||||
// update SelectedServerUrl | |||||
SelectedServerUrl = _selectedServer.GetURL(_config.generateLegacyUrl); | |||||
// generate QR code | |||||
var qrCode = ZXing.QrCode.Internal.Encoder.encode(_selectedServerUrl, ZXing.QrCode.Internal.ErrorCorrectionLevel.L); | |||||
var byteMatrix = qrCode.Matrix; | |||||
// paint bitmap | |||||
int blockSize = Math.Max(1024 / byteMatrix.Height, 1); | |||||
Bitmap drawArea = new Bitmap((byteMatrix.Width * blockSize), (byteMatrix.Height * blockSize)); | |||||
using (var graphics = Graphics.FromImage(drawArea)) | |||||
{ | |||||
graphics.Clear(Color.White); | |||||
using (var solidBrush = new SolidBrush(Color.Black)) | |||||
{ | |||||
for (int row = 0; row < byteMatrix.Width; row++) | |||||
{ | |||||
for (int column = 0; column < byteMatrix.Height; column++) | |||||
{ | |||||
if (byteMatrix[row, column] != 0) | |||||
{ | |||||
graphics.FillRectangle(solidBrush, blockSize * row, blockSize * column, blockSize, blockSize); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
// transform to BitmapImage for binding | |||||
BitmapImage bitmapImage = new BitmapImage(); | |||||
using (MemoryStream memoryStream = new MemoryStream()) | |||||
{ | |||||
drawArea.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Bmp); | |||||
memoryStream.Position = 0; | |||||
bitmapImage.BeginInit(); | |||||
bitmapImage.StreamSource = memoryStream; | |||||
bitmapImage.CacheOption = BitmapCacheOption.OnLoad; | |||||
bitmapImage.EndInit(); | |||||
} | |||||
SelectedServerUrlImage = bitmapImage; | |||||
} | |||||
public List<Server> Servers | |||||
{ | |||||
get => _servers; | |||||
set => this.RaiseAndSetIfChanged(ref _servers, value); | |||||
} | |||||
public Server SelectedServer | |||||
{ | |||||
get => _selectedServer; | |||||
set | |||||
{ | |||||
this.RaiseAndSetIfChanged(ref _selectedServer, value); | |||||
UpdateUrlAndImage(); | |||||
} | |||||
} | |||||
public string SelectedServerUrl | |||||
{ | |||||
get => _selectedServerUrl; | |||||
set => this.RaiseAndSetIfChanged(ref _selectedServerUrl, value); | |||||
} | |||||
public BitmapImage SelectedServerUrlImage | |||||
{ | |||||
get => _selectedServerUrlImage; | |||||
set => this.RaiseAndSetIfChanged(ref _selectedServerUrlImage, value); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,36 @@ | |||||
<UserControl x:Class="Shadowsocks.Views.ServerSharingView" | |||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |||||
xmlns:local="clr-namespace:Shadowsocks.Views" | |||||
mc:Ignorable="d" | |||||
d:DesignHeight="320" d:DesignWidth="600"> | |||||
<Grid Margin="8"> | |||||
<Grid.RowDefinitions> | |||||
<RowDefinition Height="*" /> | |||||
<RowDefinition Height="Auto" /> | |||||
</Grid.RowDefinitions> | |||||
<Grid.ColumnDefinitions> | |||||
<ColumnDefinition Width="*" /> | |||||
<ColumnDefinition Width="*" /> | |||||
</Grid.ColumnDefinitions> | |||||
<Image Grid.Row="0" | |||||
Grid.Column="0" | |||||
Margin="8" | |||||
Source="{Binding SelectedServerUrlImage}"/> | |||||
<ListBox Grid.Row="0" | |||||
Grid.Column="1" | |||||
Margin="8" | |||||
ItemsSource="{Binding Servers}" | |||||
SelectedItem="{Binding SelectedServer}"/> | |||||
<TextBox x:Name="urlTextBox" | |||||
Grid.Row="1" | |||||
Grid.Column="0" | |||||
Grid.ColumnSpan="2" | |||||
Margin="8" | |||||
IsReadOnly="True" | |||||
Text="{Binding SelectedServerUrl}" | |||||
PreviewMouseDoubleClick="urlTextBox_PreviewMouseDoubleClick"/> | |||||
</Grid> | |||||
</UserControl> |
@@ -0,0 +1,24 @@ | |||||
using Shadowsocks.ViewModels; | |||||
using System.Windows.Controls; | |||||
using System.Windows.Input; | |||||
namespace Shadowsocks.Views | |||||
{ | |||||
/// <summary> | |||||
/// Interaction logic for ServerSharingView.xaml | |||||
/// </summary> | |||||
public partial class ServerSharingView : UserControl | |||||
{ | |||||
public ServerSharingView() | |||||
{ | |||||
InitializeComponent(); | |||||
DataContext = new ServerSharingViewModel(); | |||||
} | |||||
private void urlTextBox_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e) | |||||
{ | |||||
urlTextBox.SelectAll(); | |||||
} | |||||
} | |||||
} |
@@ -268,6 +268,7 @@ | |||||
<Compile Include="Util\SystemProxy\Sysproxy.cs" /> | <Compile Include="Util\SystemProxy\Sysproxy.cs" /> | ||||
<Compile Include="Util\Util.cs" /> | <Compile Include="Util\Util.cs" /> | ||||
<Compile Include="Util\ViewUtils.cs" /> | <Compile Include="Util\ViewUtils.cs" /> | ||||
<Compile Include="ViewModels\ServerSharingViewModel.cs" /> | |||||
<Compile Include="View\ConfigForm.cs"> | <Compile Include="View\ConfigForm.cs"> | ||||
<SubType>Form</SubType> | <SubType>Form</SubType> | ||||
</Compile> | </Compile> | ||||
@@ -320,6 +321,9 @@ | |||||
<Compile Include="View\QRCodeSplashForm.cs"> | <Compile Include="View\QRCodeSplashForm.cs"> | ||||
<SubType>Form</SubType> | <SubType>Form</SubType> | ||||
</Compile> | </Compile> | ||||
<Compile Include="Views\ServerSharingView.xaml.cs"> | |||||
<DependentUpon>ServerSharingView.xaml</DependentUpon> | |||||
</Compile> | |||||
<Compile Include="View\StatisticsStrategyConfigurationForm.cs"> | <Compile Include="View\StatisticsStrategyConfigurationForm.cs"> | ||||
<SubType>Form</SubType> | <SubType>Form</SubType> | ||||
</Compile> | </Compile> | ||||
@@ -416,6 +420,12 @@ | |||||
<Install>true</Install> | <Install>true</Install> | ||||
</BootstrapperPackage> | </BootstrapperPackage> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | |||||
<Page Include="Views\ServerSharingView.xaml"> | |||||
<SubType>Designer</SubType> | |||||
<Generator>MSBuild:Compile</Generator> | |||||
</Page> | |||||
</ItemGroup> | |||||
<ItemGroup /> | <ItemGroup /> | ||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||||
<Import Project="..\packages\Fody.4.2.1\build\Fody.targets" Condition="Exists('..\packages\Fody.4.2.1\build\Fody.targets')" /> | <Import Project="..\packages\Fody.4.2.1\build\Fody.targets" Condition="Exists('..\packages\Fody.4.2.1\build\Fody.targets')" /> | ||||