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 args
->ref (); // to counter the unref in Emit
119 Emit (IsEnabledChangedEvent
, args
);
120 } else if (args
->GetId () == Control::HorizontalContentAlignmentProperty
121 || args
->GetId () == Control::VerticalContentAlignmentProperty
) {
122 InvalidateArrange ();
124 NotifyListenersOfPropertyChange (args
, error
);
128 Control::SetVisualParent (UIElement
*visual_parent
)
130 FrameworkElement::SetVisualParent (visual_parent
);
131 if (!UIElement::IsSubtreeLoaded (this))
134 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
135 if (!visual_parent
) {
136 enabled_parent
= true;
138 UIElement
*parent
= GetVisualParent ();
140 if (!types
->IsSubclassOf (parent
->GetObjectType (), Type::CONTROL
)) {
141 parent
= parent
->GetVisualParent ();
144 this->enabled_parent
= ((Control
*)parent
)->GetIsEnabled ();
149 SetValue (Control::IsEnabledProperty
, Value (enabled_local
));
153 Control::SetValueWithErrorImpl (DependencyProperty
*property
, Value
*value
, MoonError
*error
)
155 if (property
->GetId () == Control::IsEnabledProperty
) {
156 this->enabled_local
= value
->AsBool ();
157 if ((enabled_local
&& enabled_parent
) == GetIsEnabled ())
160 Value
v (enabled_local
&& (enabled_parent
));
162 // If we don't propagate the changes down the tree here, the EnabledChanged events
163 // from the subtree are raised in the wrong order
164 bool b
= FrameworkElement::SetValueWithErrorImpl (property
, &v
, error
);
169 return FrameworkElement::SetValueWithErrorImpl (property
, value
, error
);
173 Control::ApplyTemplate ()
175 return ApplyTemplate (GetTemplate ()) == TemplateStatusApplied
;
179 Control::ApplyTemplate (FrameworkTemplate
*t
)
181 // If the template is null, we won't apply it
183 return TemplateStatusNotApplied
;
185 if (applied_template
== t
)
186 return TemplateStatusAlreadyApplied
;
190 applied_template
= t
;
191 applied_template
->ref();
193 // If the template expands to an element which is *not* a UIElement
194 // we don't apply the template.
195 DependencyObject
*root
= applied_template
->GetVisualTree (this);
196 if (root
&& !root
->Is (Type::UIELEMENT
)) {
197 g_warning ("Control::ApplyTemplate (FrameworkTemplate*) Template root was not a UIElement");
199 return TemplateStatusNotApplied
;
201 return ApplyTemplateRoot ((UIElement
*) root
);
205 Control::ApplyTemplateRoot (UIElement
*root
)
207 // If the template root is null, we treat the template as
210 return TemplateStatusNotApplied
;
211 if (root
== template_root
)
212 return TemplateStatusAlreadyApplied
;
217 root
->SetParent (this, &e
);
220 return TemplateStatusApplied
;
224 Control::ClearTemplate ()
226 if (applied_template
) {
227 applied_template
->unref();
228 applied_template
= NULL
;
231 ElementRemoved (template_root
);
235 Control::OnApplyTemplate ()
237 Emit (TemplateAppliedEvent
);
241 Control::ElementAdded (UIElement
*item
)
243 if (item
== template_root
)
246 ElementRemoved (template_root
);
248 template_root
= item
;
251 template_root
->ref ();
252 FrameworkElement::ElementAdded (template_root
);
255 SetSubtreeObject (template_root
);
259 Control::ElementRemoved (UIElement
*item
)
261 if (template_root
&& item
== template_root
) {
262 template_root
->unref ();
263 template_root
= NULL
;
264 SetSubtreeObject (NULL
);
268 FrameworkElement::ElementRemoved (item
);
272 Control::GetTemplateChild (const char *name
)
275 return template_root
->FindName (name
);
281 Control::Focus (bool recurse
)
283 Surface
*surface
= GetSurface ();
287 /* according to msdn, these three things must be true for an element to be focusable:
289 * 1. the element must be visible
290 * 2. the element must have IsTabStop = true
291 * 3. the element must be part of the plugin's visual tree, and must have had its Loaded event fired.
295 * If the current control is not focusable, we walk the visual tree and stop as soon
296 * as we find the first focusable child. That then becomes focused
298 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
299 DeepTreeWalker
walker (this);
300 while (UIElement
*e
= walker
.Step ()) {
301 if (!types
->IsSubclassOf (e
->GetObjectType (), Type::CONTROL
))
304 Control
*c
= (Control
*)e
;
305 if (!c
->GetIsEnabled ()) {
309 walker
.SkipBranch ();
313 // A control is focusable if it is attached to a visual tree whose root
314 // element has been loaded
316 for (UIElement
*check
= this; !loaded
&& check
!= NULL
; check
= check
->GetVisualParent ())
317 loaded
|= check
->IsLoaded ();
319 if (loaded
&& c
->GetRenderVisible () && c
->GetIsTabStop ())
320 return surface
->FocusElement (c
);
329 Control::UpdateEnabled ()
331 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
332 DeepTreeWalker walker
= DeepTreeWalker (this);
333 while (UIElement
*child
= walker
.Step ()) {
334 if (child
== this || !types
->IsSubclassOf (child
->GetObjectType (), Type::CONTROL
))
337 Control
*control
= (Control
*)child
;
338 control
->enabled_parent
= (enabled_local
&& enabled_parent
);
339 control
->SetValue (Control::IsEnabledProperty
, Value (control
->enabled_local
));
340 walker
.SkipBranch ();