fixed the build
[moon.git] / src / control.cpp
blobf5ec6b3e9bc22730daa8c9cac13e2f1517f8dd16
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * control.cpp:
5 * Contact:
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.
14 #include <config.h>
16 #include "rect.h"
17 #include "runtime.h"
18 #include "control.h"
19 #include "canvas.h"
20 #include "namescope.h"
21 #include "application.h"
22 #include "geometry.h"
23 #include "tabnavigationwalker.h"
24 #include "deployment.h"
26 Control::Control ()
28 SetObjectType (Type::CONTROL);
30 applied_template = NULL;
31 enabled_local = true;
32 enabled_parent = true;
33 template_root = NULL;
36 Control::~Control ()
40 void
41 Control::Dispose ()
43 if (applied_template) {
44 applied_template->unref();
45 applied_template = NULL;
48 if (template_root) {
49 template_root->unref ();
50 template_root = NULL;
53 FrameworkElement::Dispose ();
56 void
57 Control::FindElementsInHostCoordinates (cairo_t *cr, Point p, List *uielement_list)
59 if (GetIsEnabled ())
60 FrameworkElement::FindElementsInHostCoordinates (cr, p, uielement_list);
63 void
64 Control::HitTest (cairo_t *cr, Point p, List *uielement_list)
66 if (GetIsEnabled ())
67 FrameworkElement::HitTest (cr, p, uielement_list);
70 bool
71 Control::InsideObject (cairo_t *cr, double x, double y)
73 /*
74 * Controls don't get hit themselves the rendered elements
75 * do and it bubbles up
77 return false;
80 void
81 Control::OnLoaded ()
83 Types *types = Deployment::GetCurrent ()->GetTypes ();
84 UIElement *e = GetVisualParent ();
85 while (e && !types->IsSubclassOf (e->GetObjectType (), Type::CONTROL))
86 e = e->GetVisualParent ();
87 if (e)
88 ((Control *)e)->UpdateEnabled ();
90 FrameworkElement::OnLoaded ();
93 void
94 Control::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
96 if (args->GetProperty ()->GetOwnerType() != Type::CONTROL) {
97 FrameworkElement::OnPropertyChanged (args, error);
98 return;
101 if (args->GetId () == Control::TemplateProperty) {
102 if (!args->GetNewValue() || args->GetNewValue()->GetIsNull())
103 ClearTemplate ();
104 else if (IsLoaded())
105 ApplyTemplate ();
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);
130 void
131 Control::SetVisualParent (UIElement *visual_parent)
133 FrameworkElement::SetVisualParent (visual_parent);
134 if (!UIElement::IsSubtreeLoaded (this))
135 return;
137 Types *types = Deployment::GetCurrent ()->GetTypes ();
138 if (!visual_parent) {
139 enabled_parent = true;
140 } else {
141 UIElement *parent = GetVisualParent ();
142 while (parent) {
143 if (!types->IsSubclassOf (parent->GetObjectType (), Type::CONTROL)) {
144 parent = parent->GetVisualParent ();
146 else {
147 this->enabled_parent = ((Control *)parent)->GetIsEnabled ();
148 break;
152 SetValue (Control::IsEnabledProperty, Value (enabled_local));
155 bool
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 ())
161 return true;
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);
168 if (b)
169 UpdateEnabled ();
170 return b;
172 return FrameworkElement::SetValueWithErrorImpl (property, value, error);
175 bool
176 Control::ApplyTemplate ()
178 return ApplyTemplate (GetTemplate ()) == TemplateStatusApplied;
181 TemplateStatus
182 Control::ApplyTemplate (FrameworkTemplate *t)
184 // If the template is null, we won't apply it
185 if (!t)
186 return TemplateStatusNotApplied;
188 if (applied_template == t)
189 return TemplateStatusAlreadyApplied;
191 ClearTemplate ();
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");
201 root->unref ();
202 return TemplateStatusNotApplied;
204 return ApplyTemplateRoot ((UIElement *) root);
207 TemplateStatus
208 Control::ApplyTemplateRoot (UIElement *root)
210 // If the template root is null, we treat the template as
211 // not being applied
212 if (!root)
213 return TemplateStatusNotApplied;
214 if (root == template_root)
215 return TemplateStatusAlreadyApplied;
217 ElementAdded (root);
219 MoonError e;
220 root->SetParent (this, &e);
221 OnApplyTemplate ();
223 return TemplateStatusApplied;
226 void
227 Control::ClearTemplate ()
229 if (applied_template) {
230 applied_template->unref();
231 applied_template = NULL;
234 ElementRemoved (template_root);
235 template_root = NULL;
238 void
239 Control::OnApplyTemplate ()
241 Emit (TemplateAppliedEvent);
244 void
245 Control::ElementAdded (UIElement *item)
247 if (item == template_root)
248 return;
250 ElementRemoved (template_root);
252 template_root = item;
254 if (template_root) {
255 template_root->ref ();
256 FrameworkElement::ElementAdded (template_root);
259 SetSubtreeObject (template_root);
262 void
263 Control::ElementRemoved (UIElement *item)
265 if (template_root && item == template_root) {
266 template_root->unref ();
267 template_root = NULL;
268 SetSubtreeObject (NULL);
271 if (item)
272 FrameworkElement::ElementRemoved (item);
275 DependencyObject *
276 Control::GetTemplateChild (const char *name)
278 if (template_root)
279 return template_root->FindName (name);
281 return NULL;
284 bool
285 Control::Focus (bool recurse)
287 Surface *surface = GetSurface ();
288 if (!surface)
289 return false;
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))
306 continue;
308 Control *c = (Control *)e;
309 if (!c->GetIsEnabled ()) {
310 if (!recurse)
311 return false;
313 walker.SkipBranch ();
314 continue;
317 // A control is focusable if it is attached to a visual tree whose root
318 // element has been loaded
319 bool loaded = false;
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);
326 if (!recurse)
327 return false;
329 return false;
332 void
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))
339 continue;
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 ();