Merge lp:~mandel/ubuntuone-windows-installer/improve_sso_ui into lp:ubuntuone-windows-installer/beta
- improve_sso_ui
- Merge into beta
Proposed by
Manuel de la Peña
Status: | Merged |
---|---|
Approved by: | Rick McBride |
Approved revision: | 90 |
Merged at revision: | 92 |
Proposed branch: | lp:~mandel/ubuntuone-windows-installer/improve_sso_ui |
Merge into: | lp:ubuntuone-windows-installer/beta |
Prerequisite: | lp:~mandel/ubuntuone-windows-installer/sso_di |
Diff against target: |
777 lines (+682/-17) 6 files modified
src/Canonical.Ubuntu.SSO.Views/Canonical.Ubuntu.SSO.Views.csproj (+12/-0) src/Canonical.Ubuntu.SSO.Views/LoginDialog.xaml (+32/-17) src/Canonical.Ubuntu.SSO.Views/Resources/Resources.Designer.cs (+108/-0) src/Canonical.Ubuntu.SSO.Views/Resources/Resources.resx (+135/-0) src/Canonical.Ubuntu.SSO.Views/WatermarkAdorner.cs (+141/-0) src/Canonical.Ubuntu.SSO.Views/WatermarkService.cs (+254/-0) |
To merge this branch: | bzr merge lp:~mandel/ubuntuone-windows-installer/improve_sso_ui |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Rick McBride (community) | Approve | ||
John Lenton (community) | Approve | ||
Review via email: mp+37587@code.launchpad.net |
Commit message
Description of the change
Improves the login view used in the Ubuntu SSO to match better the one present in linux.
To post a comment you must log in.
Revision history for this message
John Lenton (chipaca) : | # |
review:
Approve
Revision history for this message
Rick McBride (rmcbride) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/Canonical.Ubuntu.SSO.Views/Canonical.Ubuntu.SSO.Views.csproj' |
2 | --- src/Canonical.Ubuntu.SSO.Views/Canonical.Ubuntu.SSO.Views.csproj 2010-10-05 11:24:46 +0000 |
3 | +++ src/Canonical.Ubuntu.SSO.Views/Canonical.Ubuntu.SSO.Views.csproj 2010-10-05 11:24:47 +0000 |
4 | @@ -72,11 +72,23 @@ |
5 | <DependentUpon>Settings.settings</DependentUpon> |
6 | <DesignTimeSharedInput>True</DesignTimeSharedInput> |
7 | </Compile> |
8 | + <Compile Include="Resources\Resources.Designer.cs"> |
9 | + <AutoGen>True</AutoGen> |
10 | + <DesignTime>True</DesignTime> |
11 | + <DependentUpon>Resources.resx</DependentUpon> |
12 | + </Compile> |
13 | + <Compile Include="WatermarkAdorner.cs" /> |
14 | + <Compile Include="WatermarkService.cs" /> |
15 | <EmbeddedResource Include="Properties\Resources.resx"> |
16 | <Generator>ResXFileCodeGenerator</Generator> |
17 | <LastGenOutput>Resources.Designer.cs</LastGenOutput> |
18 | <SubType>Designer</SubType> |
19 | </EmbeddedResource> |
20 | + <EmbeddedResource Include="Resources\Resources.resx"> |
21 | + <Generator>PublicResXFileCodeGenerator</Generator> |
22 | + <LastGenOutput>Resources.Designer.cs</LastGenOutput> |
23 | + <SubType>Designer</SubType> |
24 | + </EmbeddedResource> |
25 | <None Include="Properties\Settings.settings"> |
26 | <Generator>SettingsSingleFileGenerator</Generator> |
27 | <LastGenOutput>Settings.Designer.cs</LastGenOutput> |
28 | |
29 | === modified file 'src/Canonical.Ubuntu.SSO.Views/LoginDialog.xaml' |
30 | --- src/Canonical.Ubuntu.SSO.Views/LoginDialog.xaml 2010-10-05 11:24:46 +0000 |
31 | +++ src/Canonical.Ubuntu.SSO.Views/LoginDialog.xaml 2010-10-05 11:24:47 +0000 |
32 | @@ -1,8 +1,10 @@ |
33 | <Window x:Class="Canonical.Ubuntu.SSO.Views.LoginDialog" |
34 | xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
35 | - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
36 | - Title="Login" Height="300" Width="300"> |
37 | - <Grid> |
38 | + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
39 | + xmlns:controls="clr-namespace:Canonical.Ubuntu.SSO.Views" |
40 | + xmlns:resx="clr-namespace:Canonical.Ubuntu.SSO.Views.Resources" |
41 | + Title="Login" Height="350" Width="550"> |
42 | + <Grid Margin="10"> |
43 | <Grid.RowDefinitions> |
44 | <RowDefinition Height="*" /> |
45 | <RowDefinition Height="28" /> |
46 | @@ -12,35 +14,48 @@ |
47 | <RowDefinition Height="*" /> |
48 | <RowDefinition Height="34" /> |
49 | <RowDefinition Height="34" /> |
50 | + <RowDefinition Height="34" /> |
51 | <RowDefinition Height="*" /> |
52 | </Grid.RowDefinitions> |
53 | <Grid Grid.Row="0"> |
54 | <Grid.RowDefinitions> |
55 | - <RowDefinition Height="32" /> |
56 | + <RowDefinition Height="*" /> |
57 | <RowDefinition Height="*" /> |
58 | </Grid.RowDefinitions> |
59 | - <Label Name="InfoLabel" Grid.Row="0" Margin="3" >Please provide the email you used register in</Label> |
60 | - <Label Grid.Row="1">Ubuntu One and you password.</Label> |
61 | + <TextBlock Name="TitleLabel" Grid.Row="0" Margin="3" FontSize="20" FontFamily="Calibry" Text="{x:Static resx:Resources.LoginViewTitle}"></TextBlock> |
62 | + <TextBlock Name="InfoText" Grid.Row="1" Margin="3" FontFamily="Calibry" Text="{x:Static resx:Resources.LoginViewInfo}"></TextBlock> |
63 | </Grid> |
64 | <Grid Grid.Row="1"> |
65 | <Grid.ColumnDefinitions> |
66 | <ColumnDefinition Width="*"/> |
67 | - <ColumnDefinition Width="120"/> |
68 | - <ColumnDefinition Width="120"/> |
69 | + <ColumnDefinition Width="240"/> |
70 | <ColumnDefinition Width="*"/> |
71 | </Grid.ColumnDefinitions> |
72 | - <Label Name="MessageLabel" Grid.Column="1" Margin="3">Email</Label> |
73 | - <TextBox Name="EmailTextBox" Grid.Column="2" Margin="3"></TextBox> |
74 | + <TextBox Name="EmailTextBox" Grid.Column="1" Margin="3"> |
75 | + <controls:WatermarkService.Watermark> |
76 | + <TextBlock Text="{x:Static resx:Resources.LoginEmailAddressWatermark}"></TextBlock> |
77 | + </controls:WatermarkService.Watermark> |
78 | + </TextBox> |
79 | </Grid> |
80 | <Grid Grid.Row="2"> |
81 | <Grid.ColumnDefinitions> |
82 | <ColumnDefinition Width="*"/> |
83 | - <ColumnDefinition Width="120"/> |
84 | - <ColumnDefinition Width="120"/> |
85 | - <ColumnDefinition Width="*"/> |
86 | - </Grid.ColumnDefinitions> |
87 | - <Label Name="PasswordLabel" Grid.Column="1" Margin="3">Password</Label> |
88 | - <PasswordBox Name="PasswordTextBox" Grid.Column="2" Margin="3" PasswordChar="*"></PasswordBox > |
89 | + <ColumnDefinition Width="240"/> |
90 | + <ColumnDefinition Width="*"/> |
91 | + </Grid.ColumnDefinitions> |
92 | + <PasswordBox Name="PasswordTextBox" Grid.Column="1" Margin="3" PasswordChar="*"> |
93 | + <controls:WatermarkService.Watermark> |
94 | + <TextBlock Text="{x:Static resx:Resources.LoginPasswordWatermark}"></TextBlock> |
95 | + </controls:WatermarkService.Watermark> |
96 | + </PasswordBox > |
97 | + </Grid> |
98 | + <Grid Grid.Row="3"> |
99 | + <Grid.ColumnDefinitions> |
100 | + <ColumnDefinition Width="*"/> |
101 | + <ColumnDefinition Width="240"/> |
102 | + <ColumnDefinition Width="*"/> |
103 | + </Grid.ColumnDefinitions> |
104 | + <TextBlock Name="ForgottenLink" Grid.Column="1" Margin="3" TextAlignment="Center"><Hyperlink >I've forgotten my password.</Hyperlink></TextBlock> |
105 | </Grid> |
106 | </Grid> |
107 | <Grid Grid.Row="1"> |
108 | @@ -49,7 +64,7 @@ |
109 | <ColumnDefinition Width="85"/> |
110 | <ColumnDefinition Width="85"/> |
111 | </Grid.ColumnDefinitions> |
112 | - <Button Name="LoginButton" Grid.Column="1" Margin="3" Click="LoginButton_Click">Login</Button> |
113 | + <Button Name="LoginButton" Grid.Column="1" Margin="3" Click="LoginButton_Click">Connect</Button> |
114 | <Button Name="CancelButton" Grid.Column="2" Margin="3" Click="CancelButton_Click">Cancel</Button> |
115 | </Grid> |
116 | </Grid> |
117 | |
118 | === added directory 'src/Canonical.Ubuntu.SSO.Views/Resources' |
119 | === added file 'src/Canonical.Ubuntu.SSO.Views/Resources/Resources.Designer.cs' |
120 | --- src/Canonical.Ubuntu.SSO.Views/Resources/Resources.Designer.cs 1970-01-01 00:00:00 +0000 |
121 | +++ src/Canonical.Ubuntu.SSO.Views/Resources/Resources.Designer.cs 2010-10-05 11:24:47 +0000 |
122 | @@ -0,0 +1,108 @@ |
123 | +//------------------------------------------------------------------------------ |
124 | +// <auto-generated> |
125 | +// This code was generated by a tool. |
126 | +// Runtime Version:2.0.50727.4952 |
127 | +// |
128 | +// Changes to this file may cause incorrect behavior and will be lost if |
129 | +// the code is regenerated. |
130 | +// </auto-generated> |
131 | +//------------------------------------------------------------------------------ |
132 | + |
133 | +namespace Canonical.Ubuntu.SSO.Views.Resources { |
134 | + using System; |
135 | + |
136 | + |
137 | + /// <summary> |
138 | + /// A strongly-typed resource class, for looking up localized strings, etc. |
139 | + /// </summary> |
140 | + // This class was auto-generated by the StronglyTypedResourceBuilder |
141 | + // class via a tool like ResGen or Visual Studio. |
142 | + // To add or remove a member, edit your .ResX file then rerun ResGen |
143 | + // with the /str option, or rebuild your VS project. |
144 | + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] |
145 | + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
146 | + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] |
147 | + public class Resources { |
148 | + |
149 | + private static global::System.Resources.ResourceManager resourceMan; |
150 | + |
151 | + private static global::System.Globalization.CultureInfo resourceCulture; |
152 | + |
153 | + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] |
154 | + internal Resources() { |
155 | + } |
156 | + |
157 | + /// <summary> |
158 | + /// Returns the cached ResourceManager instance used by this class. |
159 | + /// </summary> |
160 | + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] |
161 | + public static global::System.Resources.ResourceManager ResourceManager { |
162 | + get { |
163 | + if (object.ReferenceEquals(resourceMan, null)) { |
164 | + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Canonical.Ubuntu.SSO.Views.Resources.Resources", typeof(Resources).Assembly); |
165 | + resourceMan = temp; |
166 | + } |
167 | + return resourceMan; |
168 | + } |
169 | + } |
170 | + |
171 | + /// <summary> |
172 | + /// Overrides the current thread's CurrentUICulture property for all |
173 | + /// resource lookups using this strongly typed resource class. |
174 | + /// </summary> |
175 | + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] |
176 | + public static global::System.Globalization.CultureInfo Culture { |
177 | + get { |
178 | + return resourceCulture; |
179 | + } |
180 | + set { |
181 | + resourceCulture = value; |
182 | + } |
183 | + } |
184 | + |
185 | + /// <summary> |
186 | + /// Looks up a localized string similar to Email address. |
187 | + /// </summary> |
188 | + public static string LoginEmailAddressWatermark { |
189 | + get { |
190 | + return ResourceManager.GetString("LoginEmailAddressWatermark", resourceCulture); |
191 | + } |
192 | + } |
193 | + |
194 | + /// <summary> |
195 | + /// Looks up a localized string similar to I've forgotten my password.. |
196 | + /// </summary> |
197 | + public static string LoginForgottenLink { |
198 | + get { |
199 | + return ResourceManager.GetString("LoginForgottenLink", resourceCulture); |
200 | + } |
201 | + } |
202 | + |
203 | + /// <summary> |
204 | + /// Looks up a localized string similar to Password. |
205 | + /// </summary> |
206 | + public static string LoginPasswordWatermark { |
207 | + get { |
208 | + return ResourceManager.GetString("LoginPasswordWatermark", resourceCulture); |
209 | + } |
210 | + } |
211 | + |
212 | + /// <summary> |
213 | + /// Looks up a localized string similar to To connect this computer to Ubuntu One enter your details below.. |
214 | + /// </summary> |
215 | + public static string LoginViewInfo { |
216 | + get { |
217 | + return ResourceManager.GetString("LoginViewInfo", resourceCulture); |
218 | + } |
219 | + } |
220 | + |
221 | + /// <summary> |
222 | + /// Looks up a localized string similar to Connect to Ubuntu One. |
223 | + /// </summary> |
224 | + public static string LoginViewTitle { |
225 | + get { |
226 | + return ResourceManager.GetString("LoginViewTitle", resourceCulture); |
227 | + } |
228 | + } |
229 | + } |
230 | +} |
231 | |
232 | === added file 'src/Canonical.Ubuntu.SSO.Views/Resources/Resources.resx' |
233 | --- src/Canonical.Ubuntu.SSO.Views/Resources/Resources.resx 1970-01-01 00:00:00 +0000 |
234 | +++ src/Canonical.Ubuntu.SSO.Views/Resources/Resources.resx 2010-10-05 11:24:47 +0000 |
235 | @@ -0,0 +1,135 @@ |
236 | +<?xml version="1.0" encoding="utf-8"?> |
237 | +<root> |
238 | + <!-- |
239 | + Microsoft ResX Schema |
240 | + |
241 | + Version 2.0 |
242 | + |
243 | + The primary goals of this format is to allow a simple XML format |
244 | + that is mostly human readable. The generation and parsing of the |
245 | + various data types are done through the TypeConverter classes |
246 | + associated with the data types. |
247 | + |
248 | + Example: |
249 | + |
250 | + ... ado.net/XML headers & schema ... |
251 | + <resheader name="resmimetype">text/microsoft-resx</resheader> |
252 | + <resheader name="version">2.0</resheader> |
253 | + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> |
254 | + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> |
255 | + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> |
256 | + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> |
257 | + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> |
258 | + <value>[base64 mime encoded serialized .NET Framework object]</value> |
259 | + </data> |
260 | + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> |
261 | + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> |
262 | + <comment>This is a comment</comment> |
263 | + </data> |
264 | + |
265 | + There are any number of "resheader" rows that contain simple |
266 | + name/value pairs. |
267 | + |
268 | + Each data row contains a name, and value. The row also contains a |
269 | + type or mimetype. Type corresponds to a .NET class that support |
270 | + text/value conversion through the TypeConverter architecture. |
271 | + Classes that don't support this are serialized and stored with the |
272 | + mimetype set. |
273 | + |
274 | + The mimetype is used for serialized objects, and tells the |
275 | + ResXResourceReader how to depersist the object. This is currently not |
276 | + extensible. For a given mimetype the value must be set accordingly: |
277 | + |
278 | + Note - application/x-microsoft.net.object.binary.base64 is the format |
279 | + that the ResXResourceWriter will generate, however the reader can |
280 | + read any of the formats listed below. |
281 | + |
282 | + mimetype: application/x-microsoft.net.object.binary.base64 |
283 | + value : The object must be serialized with |
284 | + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter |
285 | + : and then encoded with base64 encoding. |
286 | + |
287 | + mimetype: application/x-microsoft.net.object.soap.base64 |
288 | + value : The object must be serialized with |
289 | + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter |
290 | + : and then encoded with base64 encoding. |
291 | + |
292 | + mimetype: application/x-microsoft.net.object.bytearray.base64 |
293 | + value : The object must be serialized into a byte array |
294 | + : using a System.ComponentModel.TypeConverter |
295 | + : and then encoded with base64 encoding. |
296 | + --> |
297 | + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> |
298 | + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> |
299 | + <xsd:element name="root" msdata:IsDataSet="true"> |
300 | + <xsd:complexType> |
301 | + <xsd:choice maxOccurs="unbounded"> |
302 | + <xsd:element name="metadata"> |
303 | + <xsd:complexType> |
304 | + <xsd:sequence> |
305 | + <xsd:element name="value" type="xsd:string" minOccurs="0" /> |
306 | + </xsd:sequence> |
307 | + <xsd:attribute name="name" use="required" type="xsd:string" /> |
308 | + <xsd:attribute name="type" type="xsd:string" /> |
309 | + <xsd:attribute name="mimetype" type="xsd:string" /> |
310 | + <xsd:attribute ref="xml:space" /> |
311 | + </xsd:complexType> |
312 | + </xsd:element> |
313 | + <xsd:element name="assembly"> |
314 | + <xsd:complexType> |
315 | + <xsd:attribute name="alias" type="xsd:string" /> |
316 | + <xsd:attribute name="name" type="xsd:string" /> |
317 | + </xsd:complexType> |
318 | + </xsd:element> |
319 | + <xsd:element name="data"> |
320 | + <xsd:complexType> |
321 | + <xsd:sequence> |
322 | + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> |
323 | + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> |
324 | + </xsd:sequence> |
325 | + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> |
326 | + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> |
327 | + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> |
328 | + <xsd:attribute ref="xml:space" /> |
329 | + </xsd:complexType> |
330 | + </xsd:element> |
331 | + <xsd:element name="resheader"> |
332 | + <xsd:complexType> |
333 | + <xsd:sequence> |
334 | + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> |
335 | + </xsd:sequence> |
336 | + <xsd:attribute name="name" type="xsd:string" use="required" /> |
337 | + </xsd:complexType> |
338 | + </xsd:element> |
339 | + </xsd:choice> |
340 | + </xsd:complexType> |
341 | + </xsd:element> |
342 | + </xsd:schema> |
343 | + <resheader name="resmimetype"> |
344 | + <value>text/microsoft-resx</value> |
345 | + </resheader> |
346 | + <resheader name="version"> |
347 | + <value>2.0</value> |
348 | + </resheader> |
349 | + <resheader name="reader"> |
350 | + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
351 | + </resheader> |
352 | + <resheader name="writer"> |
353 | + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
354 | + </resheader> |
355 | + <data name="LoginEmailAddressWatermark" xml:space="preserve"> |
356 | + <value>Email address</value> |
357 | + </data> |
358 | + <data name="LoginForgottenLink" xml:space="preserve"> |
359 | + <value>I've forgotten my password.</value> |
360 | + </data> |
361 | + <data name="LoginPasswordWatermark" xml:space="preserve"> |
362 | + <value>Password</value> |
363 | + </data> |
364 | + <data name="LoginViewInfo" xml:space="preserve"> |
365 | + <value>To connect this computer to Ubuntu One enter your details below.</value> |
366 | + </data> |
367 | + <data name="LoginViewTitle" xml:space="preserve"> |
368 | + <value>Connect to Ubuntu One</value> |
369 | + </data> |
370 | +</root> |
371 | \ No newline at end of file |
372 | |
373 | === added file 'src/Canonical.Ubuntu.SSO.Views/WatermarkAdorner.cs' |
374 | --- src/Canonical.Ubuntu.SSO.Views/WatermarkAdorner.cs 1970-01-01 00:00:00 +0000 |
375 | +++ src/Canonical.Ubuntu.SSO.Views/WatermarkAdorner.cs 2010-10-05 11:24:47 +0000 |
376 | @@ -0,0 +1,141 @@ |
377 | +/* |
378 | + * Copyright 2010 Canonical Ltd. |
379 | + * |
380 | + * This file is part of UbuntuOne on Windows. |
381 | + * |
382 | + * UbuntuOne on Windows is free software: you can redistribute it and/or modify |
383 | + * it under the terms of the GNU Lesser General Public License version |
384 | + * as published by the Free Software Foundation. |
385 | + * |
386 | + * Ubuntu One on Windows is distributed in the hope that it will be useful, |
387 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
388 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
389 | + * GNU Lesser General Public License for more details. |
390 | + * |
391 | + * You should have received a copy of the GNU Lesser General Public License |
392 | + * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>. |
393 | + * |
394 | + * Authors: Manuel de la Peña <manuel.delapena@canonical.com> |
395 | + */ |
396 | +using System.Windows; |
397 | +using System.Windows.Controls; |
398 | +using System.Windows.Data; |
399 | +using System.Windows.Documents; |
400 | +using System.Windows.Media; |
401 | + |
402 | +namespace Canonical.Ubuntu.SSO.Views |
403 | +{ |
404 | + /// <summary> |
405 | + /// Adorner for the watermark |
406 | + /// </summary> |
407 | + internal class WatermarkAdorner : Adorner |
408 | + { |
409 | + #region Private Fields |
410 | + |
411 | + /// <summary> |
412 | + /// <see cref="ContentPresenter"/> that holds the watermark |
413 | + /// </summary> |
414 | + private readonly ContentPresenter _contentPresenter; |
415 | + |
416 | + #endregion |
417 | + |
418 | + #region Constructor |
419 | + |
420 | + /// <summary> |
421 | + /// Initializes a new instance of the <see cref="WatermarkAdorner"/> class |
422 | + /// </summary> |
423 | + /// <param name="adornedElement"><see cref="UIElement"/> to be adorned</param> |
424 | + /// <param name="watermark">The watermark</param> |
425 | + public WatermarkAdorner(UIElement adornedElement, object watermark) : |
426 | + base(adornedElement) |
427 | + { |
428 | + IsHitTestVisible = false; |
429 | + |
430 | + _contentPresenter = new ContentPresenter |
431 | + { |
432 | + Content = watermark, |
433 | + Opacity = 0.5, |
434 | + Margin = |
435 | + new Thickness(Control.Margin.Left + Control.Padding.Left, |
436 | + Control.Margin.Top + Control.Padding.Top, 0, 0) |
437 | + }; |
438 | + |
439 | + if (Control is ItemsControl && !(Control is ComboBox)) |
440 | + { |
441 | + _contentPresenter.VerticalAlignment = VerticalAlignment.Center; |
442 | + _contentPresenter.HorizontalAlignment = HorizontalAlignment.Center; |
443 | + } |
444 | + |
445 | + // Hide the control adorner when the adorned element is hidden |
446 | + var binding = new Binding("IsVisible") |
447 | + { |
448 | + Source = adornedElement, |
449 | + Converter = new BooleanToVisibilityConverter() |
450 | + }; |
451 | + SetBinding(VisibilityProperty, binding); |
452 | + } |
453 | + |
454 | + #endregion |
455 | + |
456 | + #region Protected Properties |
457 | + |
458 | + /// <summary> |
459 | + /// Gets the number of children for the <see cref="ContainerVisual"/>. |
460 | + /// </summary> |
461 | + protected override int VisualChildrenCount |
462 | + { |
463 | + get { return 1; } |
464 | + } |
465 | + |
466 | + #endregion |
467 | + |
468 | + #region Private Properties |
469 | + |
470 | + /// <summary> |
471 | + /// Gets the control that is being adorned |
472 | + /// </summary> |
473 | + private Control Control |
474 | + { |
475 | + get { return (Control)AdornedElement; } |
476 | + } |
477 | + |
478 | + #endregion |
479 | + |
480 | + #region Protected Overrides |
481 | + |
482 | + /// <summary> |
483 | + /// Returns a specified child <see cref="Visual"/> for the parent <see cref="ContainerVisual"/>. |
484 | + /// </summary> |
485 | + /// <param name="index">A 32-bit signed integer that represents the index value of the child <see cref="Visual"/>. The value of index must be between 0 and <see cref="VisualChildrenCount"/> - 1.</param> |
486 | + /// <returns>The child <see cref="Visual"/>.</returns> |
487 | + protected override Visual GetVisualChild(int index) |
488 | + { |
489 | + return _contentPresenter; |
490 | + } |
491 | + |
492 | + /// <summary> |
493 | + /// Implements any custom measuring behavior for the adorner. |
494 | + /// </summary> |
495 | + /// <param name="constraint">A size to constrain the adorner to.</param> |
496 | + /// <returns>A <see cref="Size"/> object representing the amount of layout space needed by the adorner.</returns> |
497 | + protected override Size MeasureOverride(Size constraint) |
498 | + { |
499 | + // Here's the secret to getting the adorner to cover the whole control |
500 | + _contentPresenter.Measure(Control.RenderSize); |
501 | + return Control.RenderSize; |
502 | + } |
503 | + |
504 | + /// <summary> |
505 | + /// When overridden in a derived class, positions child elements and determines a size for a <see cref="FrameworkElement"/> derived class. |
506 | + /// </summary> |
507 | + /// <param name="finalSize">The final area within the parent that this element should use to arrange itself and its children.</param> |
508 | + /// <returns>The actual size used.</returns> |
509 | + protected override Size ArrangeOverride(Size finalSize) |
510 | + { |
511 | + _contentPresenter.Arrange(new Rect(finalSize)); |
512 | + return finalSize; |
513 | + } |
514 | + |
515 | + #endregion |
516 | + } |
517 | +} |
518 | \ No newline at end of file |
519 | |
520 | === added file 'src/Canonical.Ubuntu.SSO.Views/WatermarkService.cs' |
521 | --- src/Canonical.Ubuntu.SSO.Views/WatermarkService.cs 1970-01-01 00:00:00 +0000 |
522 | +++ src/Canonical.Ubuntu.SSO.Views/WatermarkService.cs 2010-10-05 11:24:47 +0000 |
523 | @@ -0,0 +1,254 @@ |
524 | +/* |
525 | + * Copyright 2010 Canonical Ltd. |
526 | + * |
527 | + * This file is part of UbuntuOne on Windows. |
528 | + * |
529 | + * UbuntuOne on Windows is free software: you can redistribute it and/or modify |
530 | + * it under the terms of the GNU Lesser General Public License version |
531 | + * as published by the Free Software Foundation. |
532 | + * |
533 | + * Ubuntu One on Windows is distributed in the hope that it will be useful, |
534 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
535 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
536 | + * GNU Lesser General Public License for more details. |
537 | + * |
538 | + * You should have received a copy of the GNU Lesser General Public License |
539 | + * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>. |
540 | + * |
541 | + * Authors: Manuel de la Peña <manuel.delapena@canonical.com> |
542 | + */ |
543 | +using System; |
544 | +using System.Collections.Generic; |
545 | +using System.ComponentModel; |
546 | +using System.Windows; |
547 | +using System.Windows.Controls; |
548 | +using System.Windows.Controls.Primitives; |
549 | +using System.Windows.Documents; |
550 | + |
551 | +namespace Canonical.Ubuntu.SSO.Views |
552 | +{ |
553 | + /// <summary> |
554 | + /// Class that provides the Watermark attached property |
555 | + /// </summary> |
556 | + public static class WatermarkService |
557 | + { |
558 | + /// <summary> |
559 | + /// Watermark Attached Dependency Property |
560 | + /// </summary> |
561 | + public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached( |
562 | + "Watermark", |
563 | + typeof(object), |
564 | + typeof(WatermarkService), |
565 | + new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnWatermarkChanged))); |
566 | + |
567 | + #region Private Fields |
568 | + |
569 | + /// <summary> |
570 | + /// Dictionary of ItemsControls |
571 | + /// </summary> |
572 | + private static readonly Dictionary<object, ItemsControl> _itemsControls = new Dictionary<object, ItemsControl>(); |
573 | + |
574 | + #endregion |
575 | + |
576 | + /// <summary> |
577 | + /// Gets the Watermark property. This dependency property indicates the watermark for the control. |
578 | + /// </summary> |
579 | + /// <param name="d"><see cref="DependencyObject"/> to get the property from</param> |
580 | + /// <returns>The value of the Watermark property</returns> |
581 | + public static object GetWatermark(DependencyObject d) |
582 | + { |
583 | + return d.GetValue(WatermarkProperty); |
584 | + } |
585 | + |
586 | + /// <summary> |
587 | + /// Sets the Watermark property. This dependency property indicates the watermark for the control. |
588 | + /// </summary> |
589 | + /// <param name="d"><see cref="DependencyObject"/> to set the property on</param> |
590 | + /// <param name="value">value of the property</param> |
591 | + public static void SetWatermark(DependencyObject d, object value) |
592 | + { |
593 | + d.SetValue(WatermarkProperty, value); |
594 | + } |
595 | + |
596 | + /// <summary> |
597 | + /// Handles changes to the Watermark property. |
598 | + /// </summary> |
599 | + /// <param name="d"><see cref="DependencyObject"/> that fired the event</param> |
600 | + /// <param name="e">A <see cref="DependencyPropertyChangedEventArgs"/> that contains the event data.</param> |
601 | + private static void OnWatermarkChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
602 | + { |
603 | + var control = (Control)d; |
604 | + control.Loaded += ControlLoaded; |
605 | + |
606 | + if (d is ComboBox || d is TextBox || d is PasswordBox) |
607 | + { |
608 | + control.GotKeyboardFocus += ControlGotKeyboardFocus; |
609 | + control.LostKeyboardFocus += ControlLoaded; |
610 | + } |
611 | + |
612 | + if (d is ItemsControl && !(d is ComboBox)) |
613 | + { |
614 | + var i = (ItemsControl)d; |
615 | + |
616 | + // for Items property |
617 | + i.ItemContainerGenerator.ItemsChanged += ItemsChanged; |
618 | + _itemsControls.Add(i.ItemContainerGenerator, i); |
619 | + |
620 | + // for ItemsSource property |
621 | + DependencyPropertyDescriptor prop = DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, i.GetType()); |
622 | + prop.AddValueChanged(i, ItemsSourceChanged); |
623 | + } |
624 | + } |
625 | + |
626 | + #region Event Handlers |
627 | + |
628 | + /// <summary> |
629 | + /// Handle the GotFocus event on the control |
630 | + /// </summary> |
631 | + /// <param name="sender">The source of the event.</param> |
632 | + /// <param name="e">A <see cref="RoutedEventArgs"/> that contains the event data.</param> |
633 | + private static void ControlGotKeyboardFocus(object sender, RoutedEventArgs e) |
634 | + { |
635 | + var c = (Control)sender; |
636 | + if (ShouldShowWatermark(c)) |
637 | + { |
638 | + RemoveWatermark(c); |
639 | + } |
640 | + } |
641 | + |
642 | + /// <summary> |
643 | + /// Handle the Loaded and LostFocus event on the control |
644 | + /// </summary> |
645 | + /// <param name="sender">The source of the event.</param> |
646 | + /// <param name="e">A <see cref="RoutedEventArgs"/> that contains the event data.</param> |
647 | + private static void ControlLoaded(object sender, RoutedEventArgs e) |
648 | + { |
649 | + var control = (Control)sender; |
650 | + if (ShouldShowWatermark(control)) |
651 | + { |
652 | + ShowWatermark(control); |
653 | + } |
654 | + } |
655 | + |
656 | + /// <summary> |
657 | + /// Event handler for the items source changed event |
658 | + /// </summary> |
659 | + /// <param name="sender">The source of the event.</param> |
660 | + /// <param name="e">A <see cref="EventArgs"/> that contains the event data.</param> |
661 | + private static void ItemsSourceChanged(object sender, EventArgs e) |
662 | + { |
663 | + var c = (ItemsControl)sender; |
664 | + if (c.ItemsSource != null) |
665 | + { |
666 | + if (ShouldShowWatermark(c)) |
667 | + { |
668 | + ShowWatermark(c); |
669 | + } |
670 | + else |
671 | + { |
672 | + RemoveWatermark(c); |
673 | + } |
674 | + } |
675 | + else |
676 | + { |
677 | + ShowWatermark(c); |
678 | + } |
679 | + } |
680 | + |
681 | + /// <summary> |
682 | + /// Event handler for the items changed event |
683 | + /// </summary> |
684 | + /// <param name="sender">The source of the event.</param> |
685 | + /// <param name="e">A <see cref="ItemsChangedEventArgs"/> that contains the event data.</param> |
686 | + private static void ItemsChanged(object sender, ItemsChangedEventArgs e) |
687 | + { |
688 | + ItemsControl control; |
689 | + if (_itemsControls.TryGetValue(sender, out control)) |
690 | + { |
691 | + if (ShouldShowWatermark(control)) |
692 | + { |
693 | + ShowWatermark(control); |
694 | + } |
695 | + else |
696 | + { |
697 | + RemoveWatermark(control); |
698 | + } |
699 | + } |
700 | + } |
701 | + |
702 | + #endregion |
703 | + |
704 | + #region Helper Methods |
705 | + |
706 | + /// <summary> |
707 | + /// Remove the watermark from the specified element |
708 | + /// </summary> |
709 | + /// <param name="control">Element to remove the watermark from</param> |
710 | + private static void RemoveWatermark(UIElement control) |
711 | + { |
712 | + AdornerLayer layer = AdornerLayer.GetAdornerLayer(control); |
713 | + |
714 | + // layer could be null if control is no longer in the visual tree |
715 | + if (layer != null) |
716 | + { |
717 | + Adorner[] adorners = layer.GetAdorners(control); |
718 | + if (adorners == null) |
719 | + { |
720 | + return; |
721 | + } |
722 | + |
723 | + foreach (Adorner adorner in adorners) |
724 | + { |
725 | + if (adorner is WatermarkAdorner) |
726 | + { |
727 | + adorner.Visibility = Visibility.Hidden; |
728 | + layer.Remove(adorner); |
729 | + } |
730 | + } |
731 | + } |
732 | + } |
733 | + |
734 | + /// <summary> |
735 | + /// Show the watermark on the specified control |
736 | + /// </summary> |
737 | + /// <param name="control">Control to show the watermark on</param> |
738 | + private static void ShowWatermark(Control control) |
739 | + { |
740 | + AdornerLayer layer = AdornerLayer.GetAdornerLayer(control); |
741 | + |
742 | + // layer could be null if control is no longer in the visual tree |
743 | + if (layer != null) |
744 | + { |
745 | + layer.Add(new WatermarkAdorner(control, GetWatermark(control))); |
746 | + } |
747 | + } |
748 | + |
749 | + /// <summary> |
750 | + /// Indicates whether or not the watermark should be shown on the specified control |
751 | + /// </summary> |
752 | + /// <param name="c"><see cref="Control"/> to test</param> |
753 | + /// <returns>true if the watermark should be shown; false otherwise</returns> |
754 | + private static bool ShouldShowWatermark(Control c) |
755 | + { |
756 | + if (c is ComboBox) |
757 | + { |
758 | + return (c as ComboBox).Text == string.Empty; |
759 | + } |
760 | + if (c is TextBoxBase) |
761 | + { |
762 | + return (c as TextBox).Text == string.Empty; |
763 | + } |
764 | + if(c is PasswordBox) |
765 | + { |
766 | + return (c as PasswordBox).Password == string.Empty; |
767 | + } |
768 | + if (c is ItemsControl) |
769 | + { |
770 | + return (c as ItemsControl).Items.Count == 0; |
771 | + } |
772 | + return false; |
773 | + } |
774 | + |
775 | + #endregion |
776 | + } |
777 | +} |