Statistics
| Branch: | Revision:

root / trunk / Pithos.Client.WPF / SelectiveSynch / VirtualToggleButton.cs @ 255f5f86

History | View | Annotate | Download (11.1 kB)

1
#region
2
/* -----------------------------------------------------------------------
3
 * <copyright file="VirtualToggleButton.cs" company="GRNet">
4
 * 
5
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or
8
 * without modification, are permitted provided that the following
9
 * conditions are met:
10
 *
11
 *   1. Redistributions of source code must retain the above
12
 *      copyright notice, this list of conditions and the following
13
 *      disclaimer.
14
 *
15
 *   2. Redistributions in binary form must reproduce the above
16
 *      copyright notice, this list of conditions and the following
17
 *      disclaimer in the documentation and/or other materials
18
 *      provided with the distribution.
19
 *
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
 * POSSIBILITY OF SUCH DAMAGE.
33
 *
34
 * The views and conclusions contained in the software and
35
 * documentation are those of the authors and should not be
36
 * interpreted as representing official policies, either expressed
37
 * or implied, of GRNET S.A.
38
 * </copyright>
39
 * -----------------------------------------------------------------------
40
 */
41
#endregion
42
using System;
43
using System.Collections.Generic;
44
using System.Linq;
45
using System.Text;
46
using System.Windows;
47
using System.Windows.Controls.Primitives;
48
using System.Windows.Input;
49

    
50
namespace Pithos.Client.WPF.SelectiveSynch
51
{
52
    public static class VirtualToggleButton
53
    {
54
        #region attached properties
55

    
56
        #region IsChecked
57

    
58
        /// <summary>
59
        /// IsChecked Attached Dependency Property
60
        /// </summary>
61
        public static readonly DependencyProperty IsCheckedProperty =
62
            DependencyProperty.RegisterAttached("IsChecked", typeof(Nullable<bool>), typeof(VirtualToggleButton),
63
                new FrameworkPropertyMetadata((Nullable<bool>)false,
64
                    FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
65
                    new PropertyChangedCallback(OnIsCheckedChanged)));
66

    
67
        /// <summary>
68
        /// Gets the IsChecked property.  This dependency property 
69
        /// indicates whether the toggle button is checked.
70
        /// </summary>
71
        public static Nullable<bool> GetIsChecked(DependencyObject d)
72
        {
73
            return (Nullable<bool>)d.GetValue(IsCheckedProperty);
74
        }
75

    
76
        /// <summary>
77
        /// Sets the IsChecked property.  This dependency property 
78
        /// indicates whether the toggle button is checked.
79
        /// </summary>
80
        public static void SetIsChecked(DependencyObject d, Nullable<bool> value)
81
        {
82
            d.SetValue(IsCheckedProperty, value);
83
        }
84

    
85
        /// <summary>
86
        /// Handles changes to the IsChecked property.
87
        /// </summary>
88
        private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
89
        {
90
            UIElement pseudobutton = d as UIElement;
91
            if (pseudobutton != null)
92
            {
93
                Nullable<bool> newValue = (Nullable<bool>)e.NewValue;
94
                if (newValue == true)
95
                {
96
                    RaiseCheckedEvent(pseudobutton);
97
                }
98
                else if (newValue == false)
99
                {
100
                    RaiseUncheckedEvent(pseudobutton);
101
                }
102
                else
103
                {
104
                    RaiseIndeterminateEvent(pseudobutton);
105
                }
106
            }
107
        }
108

    
109
        #endregion
110

    
111
        #region IsThreeState
112

    
113
        /// <summary>
114
        /// IsThreeState Attached Dependency Property
115
        /// </summary>
116
        public static readonly DependencyProperty IsThreeStateProperty =
117
            DependencyProperty.RegisterAttached("IsThreeState", typeof(bool), typeof(VirtualToggleButton),
118
                new FrameworkPropertyMetadata((bool)false));
119

    
120
        /// <summary>
121
        /// Gets the IsThreeState property.  This dependency property 
122
        /// indicates whether the control supports two or three states.  
123
        /// IsChecked can be set to null as a third state when IsThreeState is true.
124
        /// </summary>
125
        public static bool GetIsThreeState(DependencyObject d)
126
        {
127
            return (bool)d.GetValue(IsThreeStateProperty);
128
        }
129

    
130
        /// <summary>
131
        /// Sets the IsThreeState property.  This dependency property 
132
        /// indicates whether the control supports two or three states. 
133
        /// IsChecked can be set to null as a third state when IsThreeState is true.
134
        /// </summary>
135
        public static void SetIsThreeState(DependencyObject d, bool value)
136
        {
137
            d.SetValue(IsThreeStateProperty, value);
138
        }
139

    
140
        #endregion
141

    
142
        #region IsVirtualToggleButton
143

    
144
        /// <summary>
145
        /// IsVirtualToggleButton Attached Dependency Property
146
        /// </summary>
147
        public static readonly DependencyProperty IsVirtualToggleButtonProperty =
148
            DependencyProperty.RegisterAttached("IsVirtualToggleButton", typeof(bool), typeof(VirtualToggleButton),
149
                new FrameworkPropertyMetadata((bool)false,
150
                    new PropertyChangedCallback(OnIsVirtualToggleButtonChanged)));
151

    
152
        /// <summary>
153
        /// Gets the IsVirtualToggleButton property.  This dependency property 
154
        /// indicates whether the object to which the property is attached is treated as a VirtualToggleButton.  
155
        /// If true, the object will respond to keyboard and mouse input the same way a ToggleButton would.
156
        /// </summary>
157
        public static bool GetIsVirtualToggleButton(DependencyObject d)
158
        {
159
            return (bool)d.GetValue(IsVirtualToggleButtonProperty);
160
        }
161

    
162
        /// <summary>
163
        /// Sets the IsVirtualToggleButton property.  This dependency property 
164
        /// indicates whether the object to which the property is attached is treated as a VirtualToggleButton.  
165
        /// If true, the object will respond to keyboard and mouse input the same way a ToggleButton would.
166
        /// </summary>
167
        public static void SetIsVirtualToggleButton(DependencyObject d, bool value)
168
        {
169
            d.SetValue(IsVirtualToggleButtonProperty, value);
170
        }
171

    
172
        /// <summary>
173
        /// Handles changes to the IsVirtualToggleButton property.
174
        /// </summary>
175
        private static void OnIsVirtualToggleButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
176
        {
177
            IInputElement element = d as IInputElement;
178
            if (element != null)
179
            {
180
                if ((bool)e.NewValue)
181
                {
182
                    element.MouseLeftButtonDown += OnMouseLeftButtonDown;
183
                    element.KeyDown += OnKeyDown;
184
                }
185
                else
186
                {
187
                    element.MouseLeftButtonDown -= OnMouseLeftButtonDown;
188
                    element.KeyDown -= OnKeyDown;
189
                }
190
            }
191
        }
192

    
193
        #endregion
194

    
195
        #endregion
196

    
197
        #region routed events
198

    
199
        #region Checked
200

    
201
        /// <summary>
202
        /// A static helper method to raise the Checked event on a target element.
203
        /// </summary>
204
        /// <param name="target">UIElement or ContentElement on which to raise the event</param>
205
        internal static RoutedEventArgs RaiseCheckedEvent(UIElement target)
206
        {
207
            if (target == null) return null;
208

    
209
            RoutedEventArgs args = new RoutedEventArgs();
210
            args.RoutedEvent = ToggleButton.CheckedEvent;
211
            RaiseEvent(target, args);
212
            return args;
213
        }
214

    
215
        #endregion
216

    
217
        #region Unchecked
218

    
219
        /// <summary>
220
        /// A static helper method to raise the Unchecked event on a target element.
221
        /// </summary>
222
        /// <param name="target">UIElement or ContentElement on which to raise the event</param>
223
        internal static RoutedEventArgs RaiseUncheckedEvent(UIElement target)
224
        {
225
            if (target == null) return null;
226

    
227
            RoutedEventArgs args = new RoutedEventArgs();
228
            args.RoutedEvent = ToggleButton.UncheckedEvent;
229
            RaiseEvent(target, args);
230
            return args;
231
        }
232

    
233
        #endregion
234

    
235
        #region Indeterminate
236

    
237
        /// <summary>
238
        /// A static helper method to raise the Indeterminate event on a target element.
239
        /// </summary>
240
        /// <param name="target">UIElement or ContentElement on which to raise the event</param>
241
        internal static RoutedEventArgs RaiseIndeterminateEvent(UIElement target)
242
        {
243
            if (target == null) return null;
244

    
245
            RoutedEventArgs args = new RoutedEventArgs();
246
            args.RoutedEvent = ToggleButton.IndeterminateEvent;
247
            RaiseEvent(target, args);
248
            return args;
249
        }
250

    
251
        #endregion
252

    
253
        #endregion
254

    
255
        #region private methods
256

    
257
        private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
258
        {
259
            e.Handled = true;
260
            UpdateIsChecked(sender as DependencyObject);
261
        }
262

    
263
        private static void OnKeyDown(object sender, KeyEventArgs e)
264
        {
265
            if (e.OriginalSource == sender)
266
            {
267
                if (e.Key == Key.Space)
268
                {
269
                    // ignore alt+space which invokes the system menu
270
                    if ((Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt) return;
271

    
272
                    UpdateIsChecked(sender as DependencyObject);
273
                    e.Handled = true;
274

    
275
                }
276
                else if (e.Key == Key.Enter && (bool)(sender as DependencyObject).GetValue(KeyboardNavigation.AcceptsReturnProperty))
277
                {
278
                    UpdateIsChecked(sender as DependencyObject);
279
                    e.Handled = true;
280
                }
281
            }
282
        }
283

    
284
        private static void UpdateIsChecked(DependencyObject d)
285
        {
286
            Nullable<bool> isChecked = GetIsChecked(d);
287
            if (isChecked == true)
288
            {
289
                SetIsChecked(d, GetIsThreeState(d) ? (Nullable<bool>)null : (Nullable<bool>)false);
290
            }
291
            else
292
            {
293
                SetIsChecked(d, isChecked.HasValue);
294
            }
295
        }
296

    
297
        private static void RaiseEvent(DependencyObject target, RoutedEventArgs args)
298
        {
299
            if (target is UIElement)
300
            {
301
                (target as UIElement).RaiseEvent(args);
302
            }
303
            else if (target is ContentElement)
304
            {
305
                (target as ContentElement).RaiseEvent(args);
306
            }
307
        }
308

    
309
        #endregion
310
    }
311
}