just kick off another build
[moon.git] / src / control.cpp
blobd82f770cf7456a6e16e1c3b8581fba504738d799
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"
25 Control::Control ()
27 SetObjectType (Type::CONTROL);
29 applied_template = NULL;
30 enabled_local = true;
31 enabled_parent = true;
32 template_root = NULL;
35 Control::~Control ()
39 void
40 Control::Dispose ()
42 if (applied_template) {
43 applied_template->unref();
44 applied_template = NULL;
47 if (template_root) {
48 template_root->unref ();
49 template_root = NULL;
52 FrameworkElement::Dispose ();
55 void
56 Control::FindElementsInHostCoordinates (cairo_t *cr, Point p, List *uielement_list)
58 if (GetIsEnabled ())
59 FrameworkElement::FindElementsInHostCoordinates (cr, p, uielement_list);
62 void
63 Control::HitTest (cairo_t *cr, Point p, List *uielement_list)
65 if (GetIsEnabled ())
66 FrameworkElement::HitTest (cr, p, uielement_list);
69 bool
70 Control::InsideObject (cairo_t *cr, double x, double y)
72 /*
73 * Controls don't get hit themselves the rendered elements
74 * do and it bubbles up
76 return false;
79 void
80 Control::OnLoaded ()
82 Types *types = Deployment::GetCurrent ()->GetTypes ();
83 UIElement *e = GetVisualParent ();
84 while (e && !types->IsSubclassOf (e->GetObjectType (), Type::CONTROL))
85 e = e->GetVisualParent ();
86 if (e)
87 ((Control *)e)->UpdateEnabled ();
89 FrameworkElement::OnLoaded ();
92 void
93 Control::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
95 if (args->GetProperty ()->GetOwnerType() != Type::CONTROL) {
96 FrameworkElement::OnPropertyChanged (args, error);
97 return;
100 if (args->GetId () == Control::TemplateProperty) {
101 if (IsLoaded())
102 ApplyTemplate ();
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 Emit (IsEnabledChangedEvent);
119 } else if (args->GetId () == Control::HorizontalContentAlignmentProperty
120 || args->GetId () == Control::VerticalContentAlignmentProperty) {
121 InvalidateArrange ();
123 NotifyListenersOfPropertyChange (args, error);
126 void
127 Control::SetVisualParent (UIElement *visual_parent)
129 FrameworkElement::SetVisualParent (visual_parent);
130 if (!UIElement::IsSubtreeLoaded (this))
131 return;
133 Types *types = Deployment::GetCurrent ()->GetTypes ();
134 if (!visual_parent) {
135 enabled_parent = true;
136 } else {
137 UIElement *parent = GetVisualParent ();
138 while (parent) {
139 if (!types->IsSubclassOf (parent->GetObjectType (), Type::CONTROL)) {
140 parent = parent->GetVisualParent ();
142 else {
143 this->enabled_parent = ((Control *)parent)->GetIsEnabled ();
144 break;
148 SetValue (Control::IsEnabledProperty, Value (enabled_local));
151 bool
152 Control::SetValueWithErrorImpl (DependencyProperty *property, Value *value, MoonError *error)
154 if (property->GetId () == Control::IsEnabledProperty) {
155 this->enabled_local = value->AsBool ();
156 if ((enabled_local && enabled_parent) == GetIsEnabled ())
157 return true;
159 Value v (enabled_local && (enabled_parent));
161 // If we don't propagate the changes down the tree here, the EnabledChanged events
162 // from the subtree are raised in the wrong order
163 bool b = FrameworkElement::SetValueWithErrorImpl (property, &v, error);
164 if (b)
165 UpdateEnabled ();
166 return b;
168 return FrameworkElement::SetValueWithErrorImpl (property, value, error);
171 bool
172 Control::ApplyTemplate ()
174 return ApplyTemplate (GetTemplate ()) == TemplateStatusApplied;
177 TemplateStatus
178 Control::ApplyTemplate (FrameworkTemplate *t)
180 // If the template is null, we won't apply it
181 if (!t)
182 return TemplateStatusNotApplied;
184 if (applied_template == t)
185 return TemplateStatusAlreadyApplied;
187 ClearTemplate ();
189 applied_template = t;
190 applied_template->ref();
192 // If the template expands to an element which is *not* a UIElement
193 // we don't apply the template.
194 DependencyObject *root = applied_template->GetVisualTree (this);
195 if (root && !root->Is (Type::UIELEMENT)) {
196 g_warning ("Control::ApplyTemplate (FrameworkTemplate*) Template root was not a UIElement");
197 root->unref ();
198 return TemplateStatusNotApplied;
200 return ApplyTemplateRoot ((UIElement *) root);
203 TemplateStatus
204 Control::ApplyTemplateRoot (UIElement *root)
206 // If the template root is null, we treat the template as
207 // not being applied
208 if (!root)
209 return TemplateStatusNotApplied;
210 if (root == template_root)
211 return TemplateStatusAlreadyApplied;
213 ElementAdded (root);
215 MoonError e;
216 root->SetParent (this, &e);
217 OnApplyTemplate ();
219 return TemplateStatusApplied;
222 void
223 Control::ClearTemplate ()
225 if (applied_template) {
226 applied_template->unref();
227 applied_template = NULL;
230 ElementRemoved (template_root);
233 void
234 Control::OnApplyTemplate ()
236 Emit (TemplateAppliedEvent);
239 void
240 Control::ElementAdded (UIElement *item)
242 if (item == template_root)
243 return;
245 ElementRemoved (template_root);
247 template_root = item;
249 if (template_root) {
250 template_root->ref ();
251 FrameworkElement::ElementAdded (template_root);
254 SetSubtreeObject (template_root);
257 void
258 Control::ElementRemoved (UIElement *item)
260 if (template_root && item == template_root) {
261 template_root->unref ();
262 template_root = NULL;
263 SetSubtreeObject (NULL);
266 if (item)
267 FrameworkElement::ElementRemoved (item);
270 DependencyObject *
271 Control::GetTemplateChild (const char *name)
273 if (template_root)
274 return template_root->FindName (name);
276 return NULL;
279 bool
280 Control::Focus (bool recurse)
282 Surface *surface = GetSurface ();
283 if (!surface)
284 return false;
286 /* according to msdn, these three things must be true for an element to be focusable:
288 * 1. the element must be visible
289 * 2. the element must have IsTabStop = true
290 * 3. the element must be part of the plugin's visual tree, and must have had its Loaded event fired.
294 * If the current control is not focusable, we walk the visual tree and stop as soon
295 * as we find the first focusable child. That then becomes focused
297 Types *types = Deployment::GetCurrent ()->GetTypes ();
298 DeepTreeWalker walker (this);
299 while (UIElement *e = walker.Step ()) {
300 if (!types->IsSubclassOf (e->GetObjectType (), Type::CONTROL))
301 continue;
303 Control *c = (Control *)e;
304 if (!c->GetIsEnabled ()) {
305 if (!recurse)
306 return false;
308 walker.SkipBranch ();
309 continue;
312 // A control is focusable if it is attached to a visual tree whose root
313 // element has been loaded
314 bool loaded = false;
315 for (UIElement *check = this; !loaded && check != NULL; check = check->GetVisualParent ())
316 loaded |= check->IsLoaded ();
318 if (loaded && c->GetRenderVisible () && c->GetIsTabStop ())
319 return surface->FocusElement (c);
321 if (!recurse)
322 return false;
324 return false;
327 void
328 Control::UpdateEnabled ()
330 Types *types = Deployment::GetCurrent ()->GetTypes ();
331 DeepTreeWalker walker = DeepTreeWalker (this);
332 while (UIElement *child = walker.Step ()) {
333 if (child == this || !types->IsSubclassOf (child->GetObjectType (), Type::CONTROL))
334 continue;
336 Control *control = (Control *)child;
337 control->enabled_parent = (enabled_local && enabled_parent);
338 control->SetValue (Control::IsEnabledProperty, Value (control->enabled_local));
339 walker.SkipBranch ();