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
) {
101 if (!args
->GetNewValue() || args
->GetNewValue()->GetIsNull())
105 InvalidateMeasure ();
107 else if (args
->GetId () == Control::PaddingProperty
108 || args
->GetId () == Control::BorderThicknessProperty
) {
109 InvalidateMeasure ();
110 } else if (args
->GetId () == Control::IsEnabledProperty
) {
111 if (!args
->GetNewValue ()->AsBool ()) {
112 Surface
*surface
= Deployment::GetCurrent ()->GetSurface ();
113 if (surface
&& surface
->GetFocusedElement () == this) {
114 // Ensure this element loses focus, then try to focus the next suitable element
115 surface
->FocusElement (NULL
);
116 TabNavigationWalker::Focus (this, true);
118 ReleaseMouseCapture ();
120 args
->ref (); // to counter the unref in Emit
121 Emit (IsEnabledChangedEvent
, args
);
122 } else if (args
->GetId () == Control::HorizontalContentAlignmentProperty
123 || args
->GetId () == Control::VerticalContentAlignmentProperty
) {
124 InvalidateArrange ();
126 NotifyListenersOfPropertyChange (args
, error
);
130 Control::SetVisualParent (UIElement
*visual_parent
)
132 FrameworkElement::SetVisualParent (visual_parent
);
133 if (!UIElement::IsSubtreeLoaded (this))
136 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
137 if (!visual_parent
) {
138 enabled_parent
= true;
140 UIElement
*parent
= GetVisualParent ();
142 if (!types
->IsSubclassOf (parent
->GetObjectType (), Type::CONTROL
)) {
143 parent
= parent
->GetVisualParent ();
146 this->enabled_parent
= ((Control
*)parent
)->GetIsEnabled ();
151 SetValue (Control::IsEnabledProperty
, Value (enabled_local
));
155 Control::SetValueWithErrorImpl (DependencyProperty
*property
, Value
*value
, MoonError
*error
)
157 if (property
->GetId () == Control::IsEnabledProperty
) {
158 this->enabled_local
= value
->AsBool ();
159 if ((enabled_local
&& enabled_parent
) == GetIsEnabled ())
162 Value
v (enabled_local
&& (enabled_parent
));
164 // If we don't propagate the changes down the tree here, the EnabledChanged events
165 // from the subtree are raised in the wrong order
166 bool b
= FrameworkElement::SetValueWithErrorImpl (property
, &v
, error
);
171 return FrameworkElement::SetValueWithErrorImpl (property
, value
, error
);
175 Control::ApplyTemplate ()
177 return ApplyTemplate (GetTemplate ()) == TemplateStatusApplied
;
181 Control::ApplyTemplate (FrameworkTemplate
*t
)
183 // If the template is null, we won't apply it
185 return TemplateStatusNotApplied
;
187 if (applied_template
== t
)
188 return TemplateStatusAlreadyApplied
;
192 applied_template
= t
;
193 applied_template
->ref();
195 // If the template expands to an element which is *not* a UIElement
196 // we don't apply the template.
197 DependencyObject
*root
= applied_template
->GetVisualTree (this);
198 if (root
&& !root
->Is (Type::UIELEMENT
)) {
199 g_warning ("Control::ApplyTemplate (FrameworkTemplate*) Template root was not a UIElement");
201 return TemplateStatusNotApplied
;
203 return ApplyTemplateRoot ((UIElement
*) root
);
207 Control::ApplyTemplateRoot (UIElement
*root
)
209 // If the template root is null, we treat the template as
212 return TemplateStatusNotApplied
;
213 if (root
== template_root
)
214 return TemplateStatusAlreadyApplied
;
219 root
->SetParent (this, &e
);
222 return TemplateStatusApplied
;
226 Control::ClearTemplate ()
228 if (applied_template
) {
229 applied_template
->unref();
230 applied_template
= NULL
;
233 ElementRemoved (template_root
);
234 template_root
= NULL
;
238 Control::OnApplyTemplate ()
240 Emit (TemplateAppliedEvent
);
244 Control::ElementAdded (UIElement
*item
)
246 if (item
== template_root
)
249 ElementRemoved (template_root
);
251 template_root
= item
;
254 template_root
->ref ();
255 FrameworkElement::ElementAdded (template_root
);
258 SetSubtreeObject (template_root
);
262 Control::ElementRemoved (UIElement
*item
)
264 if (template_root
&& item
== template_root
) {
265 template_root
->unref ();
266 template_root
= NULL
;
267 SetSubtreeObject (NULL
);
271 FrameworkElement::ElementRemoved (item
);
275 Control::GetTemplateChild (const char *name
)
278 return template_root
->FindName (name
);
284 Control::Focus (bool recurse
)
286 Surface
*surface
= GetSurface ();
290 /* according to msdn, these three things must be true for an element to be focusable:
292 * 1. the element must be visible
293 * 2. the element must have IsTabStop = true
294 * 3. the element must be part of the plugin's visual tree, and must have had its Loaded event fired.
298 * If the current control is not focusable, we walk the visual tree and stop as soon
299 * as we find the first focusable child. That then becomes focused
301 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
302 DeepTreeWalker
walker (this);
303 while (UIElement
*e
= walker
.Step ()) {
304 if (!types
->IsSubclassOf (e
->GetObjectType (), Type::CONTROL
))
307 Control
*c
= (Control
*)e
;
308 if (!c
->GetIsEnabled ()) {
312 walker
.SkipBranch ();
316 // A control is focusable if it is attached to a visual tree whose root
317 // element has been loaded
319 for (UIElement
*check
= this; !loaded
&& check
!= NULL
; check
= check
->GetVisualParent ())
320 loaded
|= check
->IsLoaded ();
322 if (loaded
&& c
->GetRenderVisible () && c
->GetIsTabStop ())
323 return surface
->FocusElement (c
);
332 Control::UpdateEnabled ()
334 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
335 DeepTreeWalker walker
= DeepTreeWalker (this);
336 while (UIElement
*child
= walker
.Step ()) {
337 if (child
== this || !types
->IsSubclassOf (child
->GetObjectType (), Type::CONTROL
))
340 Control
*control
= (Control
*)child
;
341 control
->enabled_parent
= (enabled_local
&& enabled_parent
);
342 control
->SetValue (Control::IsEnabledProperty
, Value (control
->enabled_local
));
343 walker
.SkipBranch ();