Skip to content

Commit 2c752dd

Browse files
authored
Merge pull request #2454 from cwensley/curtis/windows-searchbox
Add styling for SearchBox on WinForms and WPF
2 parents c89cf07 + c7c0e96 commit 2c752dd

19 files changed

+720
-144
lines changed

src/Eto.WinForms/Eto.WinForms.csproj

+16
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<DefineConstants>$(DefineConstants);WINFORMS</DefineConstants>
1717
<NoWarn>MSB4011;$(NoWarn)</NoWarn>
1818
<UseWindowsForms Condition="$(HaveWindowsDesktopSdk) == 'True'">true</UseWindowsForms>
19+
<GenerateResourceUsePreserializedResources>True</GenerateResourceUsePreserializedResources>
1920
</PropertyGroup>
2021

2122
<PropertyGroup>
@@ -118,9 +119,24 @@ You do not need to use any of the classes of this assembly (unless customizing t
118119
<ItemGroup>
119120
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.4" />
120121
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1020.30" PrivateAssets="all" />
122+
<PackageReference Include="System.Resources.Extensions" Version="7.0.0" />
121123
</ItemGroup>
122124

123125
<Import Condition="'$(HaveWindowsDesktopSdk)' != 'true'" Sdk="Microsoft.NET.Sdk" Project="Sdk.targets" />
124126
<Import Condition="'$(HaveWindowsDesktopSdk)' == 'true'" Sdk="Microsoft.NET.Sdk.WindowsDesktop" Project="Sdk.targets" />
127+
<ItemGroup>
128+
<Compile Update="Resources.Designer.cs">
129+
<DesignTime>True</DesignTime>
130+
<AutoGen>True</AutoGen>
131+
<DependentUpon>Resources.resx</DependentUpon>
132+
</Compile>
133+
</ItemGroup>
134+
135+
<ItemGroup>
136+
<EmbeddedResource Update="Resources.resx">
137+
<Generator>ResXFileCodeGenerator</Generator>
138+
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
139+
</EmbeddedResource>
140+
</ItemGroup>
125141

126142
</Project>

src/Eto.WinForms/Forms/Controls/SearchBoxHandler.cs

100644100755
+103-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,110 @@
1-
using SD = System.Drawing;
2-
using SWF = System.Windows.Forms;
1+
using sd = System.Drawing;
2+
using swf = System.Windows.Forms;
33
using Eto.Forms;
4+
using Eto.WinForms.CustomControls;
5+
using System;
46

57
namespace Eto.WinForms.Forms.Controls
68
{
7-
public class SearchBoxHandler : TextBoxHandler, SearchBox.IHandler
9+
public class EtoSearchTextBox : EtoTextBox
810
{
11+
private readonly swf.PictureBox searchImage;
12+
13+
private readonly swf.Button clearSearchButton;
14+
15+
public EtoSearchTextBox()
16+
{
17+
clearSearchButton = new swf.Button
18+
{
19+
Dock = swf.DockStyle.Right,
20+
Size = new sd.Size(16, 16),
21+
TabStop = false,
22+
FlatStyle = swf.FlatStyle.Flat,
23+
Cursor = swf.Cursors.Arrow,
24+
ImageAlign = sd.ContentAlignment.MiddleCenter,
25+
Image = Resources.Clear
26+
};
27+
clearSearchButton.FlatAppearance.BorderSize = 0;
28+
clearSearchButton.Click += Clear_Click;
29+
30+
searchImage = new swf.PictureBox
31+
{
32+
Dock = swf.DockStyle.Left,
33+
Size = new sd.Size(16, 16),
34+
TabIndex = 0,
35+
SizeMode = swf.PictureBoxSizeMode.CenterImage,
36+
Image = Resources.Search
37+
};
38+
39+
40+
Controls.Add(clearSearchButton);
41+
Controls.Add(searchImage);
42+
43+
UpdateClearButton();
44+
}
45+
46+
47+
protected override void OnResize(EventArgs e)
48+
{
49+
base.OnResize(e);
50+
SetRounded();
51+
}
52+
53+
protected override void OnCreateControl()
54+
{
55+
base.OnCreateControl();
56+
SetRounded();
57+
}
58+
59+
private void SetRounded()
60+
{
61+
Region = sd.Region.FromHrgn(Win32.CreateRoundRectRgn(1, 1, Width, Height, Height * 2 / 3, Height * 2 / 3));
62+
Win32.SendMessage(Handle, Win32.WM.EM_SETMARGINS, (IntPtr)3, (IntPtr)((16 << 16) + 16));
63+
}
64+
65+
private void Clear_Click(object sender, EventArgs e)
66+
{
67+
Text = string.Empty;
68+
Focus();
69+
}
70+
71+
protected override void OnTextChanged(EventArgs e)
72+
{
73+
base.OnTextChanged(e);
74+
UpdateClearButton();
75+
}
76+
77+
private void UpdateClearButton()
78+
{
79+
var showClearButton = !string.IsNullOrEmpty(Text);
80+
if (clearSearchButton.Visible != showClearButton)
81+
{
82+
clearSearchButton.Visible = showClearButton;
83+
}
84+
}
85+
86+
public sd.Image SearchImage
87+
{
88+
set => searchImage.Image = value;
89+
get => searchImage.Image;
90+
}
91+
92+
public sd.Image CancelSearchImage
93+
{
94+
set => clearSearchButton.Image = value;
95+
get => clearSearchButton.Image;
96+
}
97+
}
98+
99+
public class SearchBoxHandler : TextBoxHandler<EtoSearchTextBox, TextBox, TextBox.ICallback>, SearchBox.IHandler
100+
{
101+
public override swf.TextBox SwfTextBox => Control;
102+
103+
public override EtoTextBox EtoTextBox => Control;
104+
105+
public SearchBoxHandler()
106+
{
107+
Control = new EtoSearchTextBox();
108+
}
9109
}
10110
}

src/Eto.WinForms/Resources.Designer.cs

+83
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Eto.WinForms/Resources.resx

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<root>
3+
<!--
4+
Microsoft ResX Schema
5+
6+
Version 2.0
7+
8+
The primary goals of this format is to allow a simple XML format
9+
that is mostly human readable. The generation and parsing of the
10+
various data types are done through the TypeConverter classes
11+
associated with the data types.
12+
13+
Example:
14+
15+
... ado.net/XML headers & schema ...
16+
<resheader name="resmimetype">text/microsoft-resx</resheader>
17+
<resheader name="version">2.0</resheader>
18+
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
19+
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
20+
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
21+
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
22+
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
23+
<value>[base64 mime encoded serialized .NET Framework object]</value>
24+
</data>
25+
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
26+
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
27+
<comment>This is a comment</comment>
28+
</data>
29+
30+
There are any number of "resheader" rows that contain simple
31+
name/value pairs.
32+
33+
Each data row contains a name, and value. The row also contains a
34+
type or mimetype. Type corresponds to a .NET class that support
35+
text/value conversion through the TypeConverter architecture.
36+
Classes that don't support this are serialized and stored with the
37+
mimetype set.
38+
39+
The mimetype is used for serialized objects, and tells the
40+
ResXResourceReader how to depersist the object. This is currently not
41+
extensible. For a given mimetype the value must be set accordingly:
42+
43+
Note - application/x-microsoft.net.object.binary.base64 is the format
44+
that the ResXResourceWriter will generate, however the reader can
45+
read any of the formats listed below.
46+
47+
mimetype: application/x-microsoft.net.object.binary.base64
48+
value : The object must be serialized with
49+
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
50+
: and then encoded with base64 encoding.
51+
52+
mimetype: application/x-microsoft.net.object.soap.base64
53+
value : The object must be serialized with
54+
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
55+
: and then encoded with base64 encoding.
56+
57+
mimetype: application/x-microsoft.net.object.bytearray.base64
58+
value : The object must be serialized into a byte array
59+
: using a System.ComponentModel.TypeConverter
60+
: and then encoded with base64 encoding.
61+
-->
62+
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
63+
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
64+
<xsd:element name="root" msdata:IsDataSet="true">
65+
<xsd:complexType>
66+
<xsd:choice maxOccurs="unbounded">
67+
<xsd:element name="metadata">
68+
<xsd:complexType>
69+
<xsd:sequence>
70+
<xsd:element name="value" type="xsd:string" minOccurs="0" />
71+
</xsd:sequence>
72+
<xsd:attribute name="name" use="required" type="xsd:string" />
73+
<xsd:attribute name="type" type="xsd:string" />
74+
<xsd:attribute name="mimetype" type="xsd:string" />
75+
<xsd:attribute ref="xml:space" />
76+
</xsd:complexType>
77+
</xsd:element>
78+
<xsd:element name="assembly">
79+
<xsd:complexType>
80+
<xsd:attribute name="alias" type="xsd:string" />
81+
<xsd:attribute name="name" type="xsd:string" />
82+
</xsd:complexType>
83+
</xsd:element>
84+
<xsd:element name="data">
85+
<xsd:complexType>
86+
<xsd:sequence>
87+
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
88+
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
89+
</xsd:sequence>
90+
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
91+
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
92+
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
93+
<xsd:attribute ref="xml:space" />
94+
</xsd:complexType>
95+
</xsd:element>
96+
<xsd:element name="resheader">
97+
<xsd:complexType>
98+
<xsd:sequence>
99+
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
100+
</xsd:sequence>
101+
<xsd:attribute name="name" type="xsd:string" use="required" />
102+
</xsd:complexType>
103+
</xsd:element>
104+
</xsd:choice>
105+
</xsd:complexType>
106+
</xsd:element>
107+
</xsd:schema>
108+
<resheader name="resmimetype">
109+
<value>text/microsoft-resx</value>
110+
</resheader>
111+
<resheader name="version">
112+
<value>2.0</value>
113+
</resheader>
114+
<resheader name="reader">
115+
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
116+
</resheader>
117+
<resheader name="writer">
118+
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119+
</resheader>
120+
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
121+
<data name="Clear" type="System.Resources.ResXFileRef, System.Windows.Forms">
122+
<value>Resources\Clear.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
123+
</data>
124+
<data name="Search" type="System.Resources.ResXFileRef, System.Windows.Forms">
125+
<value>Resources\Search.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
126+
</data>
127+
</root>

src/Eto.WinForms/Resources/Clear.png

4.14 KB
Loading

src/Eto.WinForms/Resources/Search.png

4.27 KB
Loading

src/Eto.WinForms/Win32.cs

100644100755
+5
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ public enum WM
182182

183183
ECM_FIRST = 0x1500,
184184
EM_SETCUEBANNER = ECM_FIRST + 1,
185+
EM_SETMARGINS = 0xd3,
185186

186187
DPICHANGED = 0x02E0,
187188
NCCREATE = 0x0081,
@@ -500,6 +501,10 @@ public static IntPtr GetThreadFocusWindow(uint? threadId = null)
500501
[DllImport("gdi32.dll")]
501502
public static extern bool OffsetWindowOrgEx(IntPtr hdc, int nXOffset, int nYOffset, ref POINT lpPoint);
502503

504+
[DllImport("gdi32.dll")]
505+
public static extern IntPtr CreateRoundRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nheightRect, int nweightRect);
506+
507+
503508
[DllImport("user32.dll")]
504509
public static extern IntPtr WindowFromPoint(POINT lpPoint);
505510

0 commit comments

Comments
 (0)