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
);
31 enabled_parent
= true;
40 Control::FindElementsInHostCoordinates (cairo_t
*cr
, Point p
, List
*uielement_list
)
43 FrameworkElement::FindElementsInHostCoordinates (cr
, p
, uielement_list
);
47 Control::HitTest (cairo_t
*cr
, Point p
, List
*uielement_list
)
50 FrameworkElement::HitTest (cr
, p
, uielement_list
);
54 Control::InsideObject (cairo_t
*cr
, double x
, double y
)
57 * Controls don't get hit themselves the rendered elements
58 * do and it bubbles up
66 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
67 UIElement
*e
= GetVisualParent ();
68 while (e
&& !types
->IsSubclassOf (e
->GetObjectType (), Type::CONTROL
))
69 e
= e
->GetVisualParent ();
71 ((Control
*)e
)->UpdateEnabled ();
73 FrameworkElement::OnLoaded ();
77 Control::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
79 if (args
->GetProperty ()->GetOwnerType() != Type::CONTROL
) {
80 FrameworkElement::OnPropertyChanged (args
, error
);
84 if (args
->GetId () == Control::TemplateProperty
) {
85 if (GetSubtreeObject ())
86 ElementRemoved ((UIElement
*) GetSubtreeObject ());
88 else if (args
->GetId () == Control::PaddingProperty
89 || args
->GetId () == Control::BorderThicknessProperty
) {
91 } else if (args
->GetId () == Control::IsEnabledProperty
) {
92 if (!args
->GetNewValue ()->AsBool ()) {
93 Surface
*surface
= Deployment::GetCurrent ()->GetSurface ();
94 if (surface
&& surface
->GetFocusedElement () == this) {
95 // Ensure this element loses focus, then try to focus the next suitable element
96 surface
->FocusElement (NULL
);
97 TabNavigationWalker::Focus (this, true);
99 ReleaseMouseCapture ();
101 args
->ref (); // to counter the unref in Emit
102 Emit (IsEnabledChangedEvent
, args
);
103 } else if (args
->GetId () == Control::HorizontalContentAlignmentProperty
104 || args
->GetId () == Control::VerticalContentAlignmentProperty
) {
105 InvalidateArrange ();
107 NotifyListenersOfPropertyChange (args
, error
);
111 Control::SetVisualParent (UIElement
*visual_parent
)
113 FrameworkElement::SetVisualParent (visual_parent
);
114 if (!UIElement::IsSubtreeLoaded (this))
117 this->enabled_parent
= GetParentEnabledState (this);
118 SetValue (Control::IsEnabledProperty
, Value (enabled_local
));
122 Control::GetParentEnabledState (UIElement
*element
)
125 element
= element
->GetVisualParent ();
126 } while (element
&& !element
->Is (Type::CONTROL
));
128 return element
? ((Control
*) element
)->GetIsEnabled () : true;
132 Control::SetValueWithErrorImpl (DependencyProperty
*property
, Value
*value
, MoonError
*error
)
134 if (property
->GetId () == Control::IsEnabledProperty
) {
135 this->enabled_local
= value
->AsBool ();
136 if ((enabled_local
&& enabled_parent
) == GetIsEnabled ())
139 Value
v (enabled_local
&& (enabled_parent
));
141 // If we don't propagate the changes down the tree here, the EnabledChanged events
142 // from the subtree are raised in the wrong order
143 bool b
= FrameworkElement::SetValueWithErrorImpl (property
, &v
, error
);
148 return FrameworkElement::SetValueWithErrorImpl (property
, value
, error
);
152 Control::DoApplyTemplate ()
154 ControlTemplate
*t
= GetTemplate ();
156 return FrameworkElement::DoApplyTemplate ();
158 // If the template expands to an element which is *not* a UIElement
159 // we don't apply the template.
160 DependencyObject
*root
= t
->GetVisualTree (this);
161 if (root
&& !root
->Is (Type::UIELEMENT
)) {
162 g_warning ("Control::DoApplyTemplate () Template root was not a UIElement");
168 return FrameworkElement::DoApplyTemplate ();
170 // No need to ref template_root here as ElementAdded refs it
171 // and it is cleared when ElementRemoved is called.
172 template_root
= (UIElement
*)root
;
173 ElementAdded (template_root
);
178 ((UIElement
*)root
)->WalkTreeForLoadedHandlers (&post
, true, true);
181 Deployment::GetCurrent()->PostLoaded ();
188 Control::ElementAdded (UIElement
*item
)
191 item
->SetParent (this, &e
);
192 SetSubtreeObject (item
);
193 FrameworkElement::ElementAdded (item
);
197 Control::ElementRemoved (UIElement
*item
)
199 template_root
= NULL
;
201 item
->SetParent (NULL
, &e
);
202 FrameworkElement::ElementRemoved (item
);
206 Control::GetTemplateChild (const char *name
)
209 return template_root
->FindName (name
);
215 Control::Focus (bool recurse
)
217 Surface
*surface
= GetSurface ();
221 /* according to msdn, these three things must be true for an element to be focusable:
223 * 1. the element must be visible
224 * 2. the element must have IsTabStop = true
225 * 3. the element must be part of the plugin's visual tree, and must have had its Loaded event fired.
229 * If the current control is not focusable, we walk the visual tree and stop as soon
230 * as we find the first focusable child. That then becomes focused
232 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
233 DeepTreeWalker
walker (this);
234 while (UIElement
*e
= walker
.Step ()) {
235 if (!types
->IsSubclassOf (e
->GetObjectType (), Type::CONTROL
))
238 Control
*c
= (Control
*)e
;
239 if (!c
->GetIsEnabled ()) {
243 walker
.SkipBranch ();
247 // A control is focusable if it is attached to a visual tree whose root
248 // element has been loaded
250 for (UIElement
*check
= this; !loaded
&& check
!= NULL
; check
= check
->GetVisualParent ())
251 loaded
|= check
->IsLoaded ();
253 if (loaded
&& c
->GetRenderVisible () && c
->GetIsTabStop ())
254 return surface
->FocusElement (c
);
263 Control::UpdateEnabled ()
265 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
266 DeepTreeWalker walker
= DeepTreeWalker (this);
267 while (UIElement
*child
= walker
.Step ()) {
268 if (child
== this || !types
->IsSubclassOf (child
->GetObjectType (), Type::CONTROL
))
271 Control
*control
= (Control
*)child
;
272 control
->enabled_parent
= (enabled_local
&& enabled_parent
);
273 control
->SetValue (Control::IsEnabledProperty
, Value (control
->enabled_local
));
274 walker
.SkipBranch ();