1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
20 #include "namescope.h"
21 #include "application.h"
23 #include "tabnavigationwalker.h"
27 SetObjectType (Type::CONTROL
);
29 applied_template
= NULL
;
31 enabled_parent
= true;
42 if (applied_template
) {
43 applied_template
->unref();
44 applied_template
= NULL
;
48 template_root
->unref ();
52 FrameworkElement::Dispose ();
56 Control::FindElementsInHostCoordinates (cairo_t
*cr
, Point p
, List
*uielement_list
)
59 FrameworkElement::FindElementsInHostCoordinates (cr
, p
, uielement_list
);
63 Control::HitTest (cairo_t
*cr
, Point p
, List
*uielement_list
)
66 FrameworkElement::HitTest (cr
, p
, uielement_list
);
70 Control::InsideObject (cairo_t
*cr
, double x
, double y
)
73 * Controls don't get hit themselves the rendered elements
74 * do and it bubbles up
82 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
83 UIElement
*e
= GetVisualParent ();
84 while (e
&& !types
->IsSubclassOf (e
->GetObjectType (), Type::CONTROL
))
85 e
= e
->GetVisualParent ();
87 ((Control
*)e
)->UpdateEnabled ();
89 FrameworkElement::OnLoaded ();
93 Control::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
95 if (args
->GetProperty ()->GetOwnerType() != Type::CONTROL
) {
96 FrameworkElement::OnPropertyChanged (args
, error
);
100 if (args
->GetId () == Control::TemplateProperty
) {
103 InvalidateMeasure ();
105 else if (args
->GetId () == Control::PaddingProperty
106 || args
->GetId () == Control::BorderThicknessProperty
) {
107 InvalidateMeasure ();
108 } else if (args
->GetId () == Control::IsEnabledProperty
) {
109 if (!args
->GetNewValue ()->AsBool ()) {
110 Surface
*surface
= Deployment::GetCurrent ()->GetSurface ();
111 if (surface
&& surface
->GetFocusedElement () == this) {
112 // Ensure this element loses focus, then try to focus the next suitable element
113 surface
->FocusElement (NULL
);
114 TabNavigationWalker::Focus (this, true);
116 ReleaseMouseCapture ();
118 Emit (IsEnabledChangedEvent
);
119 } else if (args
->GetId () == Control::HorizontalContentAlignmentProperty
120 || args
->GetId () == Control::VerticalContentAlignmentProperty
) {
121 InvalidateArrange ();
123 NotifyListenersOfPropertyChange (args
, error
);
127 Control::SetVisualParent (UIElement
*visual_parent
)
129 FrameworkElement::SetVisualParent (visual_parent
);
130 if (!UIElement::IsSubtreeLoaded (this))
133 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
134 if (!visual_parent
) {
135 enabled_parent
= true;
137 UIElement
*parent
= GetVisualParent ();
139 if (!types
->IsSubclassOf (parent
->GetObjectType (), Type::CONTROL
)) {
140 parent
= parent
->GetVisualParent ();
143 this->enabled_parent
= ((Control
*)parent
)->GetIsEnabled ();
148 SetValue (Control::IsEnabledProperty
, Value (enabled_local
));
152 Control::SetValueWithErrorImpl (DependencyProperty
*property
, Value
*value
, MoonError
*error
)
154 if (property
->GetId () == Control::IsEnabledProperty
) {
155 this->enabled_local
= value
->AsBool ();
156 if ((enabled_local
&& enabled_parent
) == GetIsEnabled ())
159 Value
v (enabled_local
&& (enabled_parent
));
161 // If we don't propagate the changes down the tree here, the EnabledChanged events
162 // from the subtree are raised in the wrong order
163 bool b
= FrameworkElement::SetValueWithErrorImpl (property
, &v
, error
);
168 return FrameworkElement::SetValueWithErrorImpl (property
, value
, error
);
172 Control::ApplyTemplate ()
174 return ApplyTemplate (GetTemplate ()) == TemplateStatusApplied
;
178 Control::ApplyTemplate (FrameworkTemplate
*t
)
180 // If the template is null, we won't apply it
182 return TemplateStatusNotApplied
;
184 if (applied_template
== t
)
185 return TemplateStatusAlreadyApplied
;
189 applied_template
= t
;
190 applied_template
->ref();
192 // If the template expands to an element which is *not* a UIElement
193 // we don't apply the template.
194 DependencyObject
*root
= applied_template
->GetVisualTree (this);
195 if (root
&& !root
->Is (Type::UIELEMENT
)) {
196 g_warning ("Control::ApplyTemplate (FrameworkTemplate*) Template root was not a UIElement");
198 return TemplateStatusNotApplied
;
200 return ApplyTemplateRoot ((UIElement
*) root
);
204 Control::ApplyTemplateRoot (UIElement
*root
)
206 // If the template root is null, we treat the template as
209 return TemplateStatusNotApplied
;
210 if (root
== template_root
)
211 return TemplateStatusAlreadyApplied
;
216 root
->SetParent (this, &e
);
219 return TemplateStatusApplied
;
223 Control::ClearTemplate ()
225 if (applied_template
) {
226 applied_template
->unref();
227 applied_template
= NULL
;
230 ElementRemoved (template_root
);
234 Control::OnApplyTemplate ()
236 Emit (TemplateAppliedEvent
);
240 Control::ElementAdded (UIElement
*item
)
242 if (item
== template_root
)
245 ElementRemoved (template_root
);
247 template_root
= item
;
250 template_root
->ref ();
251 FrameworkElement::ElementAdded (template_root
);
254 SetSubtreeObject (template_root
);
258 Control::ElementRemoved (UIElement
*item
)
260 if (template_root
&& item
== template_root
) {
261 template_root
->unref ();
262 template_root
= NULL
;
263 SetSubtreeObject (NULL
);
267 FrameworkElement::ElementRemoved (item
);
271 Control::GetTemplateChild (const char *name
)
274 return template_root
->FindName (name
);
280 Control::Focus (bool recurse
)
282 Surface
*surface
= GetSurface ();
286 /* according to msdn, these three things must be true for an element to be focusable:
288 * 1. the element must be visible
289 * 2. the element must have IsTabStop = true
290 * 3. the element must be part of the plugin's visual tree, and must have had its Loaded event fired.
294 * If the current control is not focusable, we walk the visual tree and stop as soon
295 * as we find the first focusable child. That then becomes focused
297 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
298 DeepTreeWalker
walker (this);
299 while (UIElement
*e
= walker
.Step ()) {
300 if (!types
->IsSubclassOf (e
->GetObjectType (), Type::CONTROL
))
303 Control
*c
= (Control
*)e
;
304 if (!c
->GetIsEnabled ()) {
308 walker
.SkipBranch ();
312 // A control is focusable if it is attached to a visual tree whose root
313 // element has been loaded
315 for (UIElement
*check
= this; !loaded
&& check
!= NULL
; check
= check
->GetVisualParent ())
316 loaded
|= check
->IsLoaded ();
318 if (loaded
&& c
->GetRenderVisible () && c
->GetIsTabStop ())
319 return surface
->FocusElement (c
);
328 Control::UpdateEnabled ()
330 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
331 DeepTreeWalker walker
= DeepTreeWalker (this);
332 while (UIElement
*child
= walker
.Step ()) {
333 if (child
== this || !types
->IsSubclassOf (child
->GetObjectType (), Type::CONTROL
))
336 Control
*control
= (Control
*)child
;
337 control
->enabled_parent
= (enabled_local
&& enabled_parent
);
338 control
->SetValue (Control::IsEnabledProperty
, Value (control
->enabled_local
));
339 walker
.SkipBranch ();