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"
24 #include "deployment.h"
28 SetObjectType (Type::CONTROL
);
30 applied_template
= NULL
;
32 enabled_parent
= true;
43 if (applied_template
) {
44 applied_template
->unref();
45 applied_template
= NULL
;
49 template_root
->unref ();
53 FrameworkElement::Dispose ();
57 Control::FindElementsInHostCoordinates (cairo_t
*cr
, Point p
, List
*uielement_list
)
60 FrameworkElement::FindElementsInHostCoordinates (cr
, p
, uielement_list
);
64 Control::HitTest (cairo_t
*cr
, Point p
, List
*uielement_list
)
67 FrameworkElement::HitTest (cr
, p
, uielement_list
);
71 Control::InsideObject (cairo_t
*cr
, double x
, double y
)
74 * Controls don't get hit themselves the rendered elements
75 * do and it bubbles up
83 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
84 UIElement
*e
= GetVisualParent ();
85 while (e
&& !types
->IsSubclassOf (e
->GetObjectType (), Type::CONTROL
))
86 e
= e
->GetVisualParent ();
88 ((Control
*)e
)->UpdateEnabled ();
90 FrameworkElement::OnLoaded ();
94 Control::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
96 if (args
->GetProperty ()->GetOwnerType() != Type::CONTROL
) {
97 FrameworkElement::OnPropertyChanged (args
, error
);
101 if (args
->GetId () == Control::TemplateProperty
) {
102 if (!args
->GetNewValue() || args
->GetNewValue()->GetIsNull())
106 InvalidateMeasure ();
108 else if (args
->GetId () == Control::PaddingProperty
109 || args
->GetId () == Control::BorderThicknessProperty
) {
110 InvalidateMeasure ();
111 } else if (args
->GetId () == Control::IsEnabledProperty
) {
112 if (!args
->GetNewValue ()->AsBool ()) {
113 Surface
*surface
= Deployment::GetCurrent ()->GetSurface ();
114 if (surface
&& surface
->GetFocusedElement () == this) {
115 // Ensure this element loses focus, then try to focus the next suitable element
116 surface
->FocusElement (NULL
);
117 TabNavigationWalker::Focus (this, true);
119 ReleaseMouseCapture ();
121 args
->ref (); // to counter the unref in Emit
122 Emit (IsEnabledChangedEvent
, args
);
123 } else if (args
->GetId () == Control::HorizontalContentAlignmentProperty
124 || args
->GetId () == Control::VerticalContentAlignmentProperty
) {
125 InvalidateArrange ();
127 NotifyListenersOfPropertyChange (args
, error
);
131 Control::SetVisualParent (UIElement
*visual_parent
)
133 FrameworkElement::SetVisualParent (visual_parent
);
134 if (!UIElement::IsSubtreeLoaded (this))
137 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
138 if (!visual_parent
) {
139 enabled_parent
= true;
141 UIElement
*parent
= GetVisualParent ();
143 if (!types
->IsSubclassOf (parent
->GetObjectType (), Type::CONTROL
)) {
144 parent
= parent
->GetVisualParent ();
147 this->enabled_parent
= ((Control
*)parent
)->GetIsEnabled ();
152 SetValue (Control::IsEnabledProperty
, Value (enabled_local
));
156 Control::SetValueWithErrorImpl (DependencyProperty
*property
, Value
*value
, MoonError
*error
)
158 if (property
->GetId () == Control::IsEnabledProperty
) {
159 this->enabled_local
= value
->AsBool ();
160 if ((enabled_local
&& enabled_parent
) == GetIsEnabled ())
163 Value
v (enabled_local
&& (enabled_parent
));
165 // If we don't propagate the changes down the tree here, the EnabledChanged events
166 // from the subtree are raised in the wrong order
167 bool b
= FrameworkElement::SetValueWithErrorImpl (property
, &v
, error
);
172 return FrameworkElement::SetValueWithErrorImpl (property
, value
, error
);
176 Control::ApplyTemplate ()
178 return ApplyTemplate (GetTemplate ()) == TemplateStatusApplied
;
182 Control::ApplyTemplate (FrameworkTemplate
*t
)
184 // If the template is null, we won't apply it
186 return TemplateStatusNotApplied
;
188 if (applied_template
== t
)
189 return TemplateStatusAlreadyApplied
;
193 applied_template
= t
;
194 applied_template
->ref();
196 // If the template expands to an element which is *not* a UIElement
197 // we don't apply the template.
198 DependencyObject
*root
= applied_template
->GetVisualTree (this);
199 if (root
&& !root
->Is (Type::UIELEMENT
)) {
200 g_warning ("Control::ApplyTemplate (FrameworkTemplate*) Template root was not a UIElement");
202 return TemplateStatusNotApplied
;
204 return ApplyTemplateRoot ((UIElement
*) root
);
208 Control::ApplyTemplateRoot (UIElement
*root
)
210 // If the template root is null, we treat the template as
213 return TemplateStatusNotApplied
;
214 if (root
== template_root
)
215 return TemplateStatusAlreadyApplied
;
220 root
->SetParent (this, &e
);
223 return TemplateStatusApplied
;
227 Control::ClearTemplate ()
229 if (applied_template
) {
230 applied_template
->unref();
231 applied_template
= NULL
;
234 ElementRemoved (template_root
);
235 template_root
= NULL
;
239 Control::OnApplyTemplate ()
241 Emit (TemplateAppliedEvent
);
245 Control::ElementAdded (UIElement
*item
)
247 if (item
== template_root
)
250 ElementRemoved (template_root
);
252 template_root
= item
;
255 template_root
->ref ();
256 FrameworkElement::ElementAdded (template_root
);
259 SetSubtreeObject (template_root
);
263 Control::ElementRemoved (UIElement
*item
)
265 if (template_root
&& item
== template_root
) {
266 template_root
->unref ();
267 template_root
= NULL
;
268 SetSubtreeObject (NULL
);
272 FrameworkElement::ElementRemoved (item
);
276 Control::GetTemplateChild (const char *name
)
279 return template_root
->FindName (name
);
285 Control::Focus (bool recurse
)
287 Surface
*surface
= GetSurface ();
291 /* according to msdn, these three things must be true for an element to be focusable:
293 * 1. the element must be visible
294 * 2. the element must have IsTabStop = true
295 * 3. the element must be part of the plugin's visual tree, and must have had its Loaded event fired.
299 * If the current control is not focusable, we walk the visual tree and stop as soon
300 * as we find the first focusable child. That then becomes focused
302 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
303 DeepTreeWalker
walker (this);
304 while (UIElement
*e
= walker
.Step ()) {
305 if (!types
->IsSubclassOf (e
->GetObjectType (), Type::CONTROL
))
308 Control
*c
= (Control
*)e
;
309 if (!c
->GetIsEnabled ()) {
313 walker
.SkipBranch ();
317 // A control is focusable if it is attached to a visual tree whose root
318 // element has been loaded
320 for (UIElement
*check
= this; !loaded
&& check
!= NULL
; check
= check
->GetVisualParent ())
321 loaded
|= check
->IsLoaded ();
323 if (loaded
&& c
->GetRenderVisible () && c
->GetIsTabStop ())
324 return surface
->FocusElement (c
);
333 Control::UpdateEnabled ()
335 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
336 DeepTreeWalker walker
= DeepTreeWalker (this);
337 while (UIElement
*child
= walker
.Step ()) {
338 if (child
== this || !types
->IsSubclassOf (child
->GetObjectType (), Type::CONTROL
))
341 Control
*control
= (Control
*)child
;
342 control
->enabled_parent
= (enabled_local
&& enabled_parent
);
343 control
->SetValue (Control::IsEnabledProperty
, Value (control
->enabled_local
));
344 walker
.SkipBranch ();