in plugin/:
[moon.git] / src / control.cpp
blobaade1eb46082ba40655ea332ea5d2b7256b7ea63
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 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);
127 void
128 Control::SetVisualParent (UIElement *visual_parent)
130 FrameworkElement::SetVisualParent (visual_parent);
131 if (!UIElement::IsSubtreeLoaded (this))
132 return;
134 Types *types = Deployment::GetCurrent ()->GetTypes ();
135 if (!visual_parent) {
136 enabled_parent = true;
137 } else {
138 UIElement *parent = GetVisualParent ();
139 while (parent) {
140 if (!types->IsSubclassOf (parent->GetObjectType (), Type::CONTROL)) {
141 parent = parent->GetVisualParent ();
143 else {
144 this->enabled_parent = ((Control *)parent)->GetIsEnabled ();
145 break;
149 SetValue (Control::IsEnabledProperty, Value (enabled_local));
152 bool
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 ())
158 return true;
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);
165 if (b)
166 UpdateEnabled ();
167 return b;
169 return FrameworkElement::SetValueWithErrorImpl (property, value, error);
172 bool
173 Control::ApplyTemplate ()
175 return ApplyTemplate (GetTemplate ()) == TemplateStatusApplied;
178 TemplateStatus
179 Control::ApplyTemplate (FrameworkTemplate *t)
181 // If the template is null, we won't apply it
182 if (!t)
183 return TemplateStatusNotApplied;
185 if (applied_template == t)
186 return TemplateStatusAlreadyApplied;
188 ClearTemplate ();
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");
198 root->unref ();
199 return TemplateStatusNotApplied;
201 return ApplyTemplateRoot ((UIElement *) root);
204 TemplateStatus
205 Control::ApplyTemplateRoot (UIElement *root)
207 // If the template root is null, we treat the template as
208 // not being applied
209 if (!root)
210 return TemplateStatusNotApplied;
211 if (root == template_root)
212 return TemplateStatusAlreadyApplied;
214 ElementAdded (root);
216 MoonError e;
217 root->SetParent (this, &e);
218 OnApplyTemplate ();
220 return TemplateStatusApplied;
223 void
224 Control::ClearTemplate ()
226 if (applied_template) {
227 applied_template->unref();
228 applied_template = NULL;
231 ElementRemoved (template_root);
234 void
235 Control::OnApplyTemplate ()
237 Emit (TemplateAppliedEvent);
240 void
241 Control::ElementAdded (UIElement *item)
243 if (item == template_root)
244 return;
246 ElementRemoved (template_root);
248 template_root = item;
250 if (template_root) {
251 template_root->ref ();
252 FrameworkElement::ElementAdded (template_root);
255 SetSubtreeObject (template_root);
258 void
259 Control::ElementRemoved (UIElement *item)
261 if (template_root && item == template_root) {
262 template_root->unref ();
263 template_root = NULL;
264 SetSubtreeObject (NULL);
267 if (item)
268 FrameworkElement::ElementRemoved (item);
271 DependencyObject *
272 Control::GetTemplateChild (const char *name)
274 if (template_root)
275 return template_root->FindName (name);
277 return NULL;
280 bool
281 Control::Focus (bool recurse)
283 Surface *surface = GetSurface ();
284 if (!surface)
285 return false;
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))
302 continue;
304 Control *c = (Control *)e;
305 if (!c->GetIsEnabled ()) {
306 if (!recurse)
307 return false;
309 walker.SkipBranch ();
310 continue;
313 // A control is focusable if it is attached to a visual tree whose root
314 // element has been loaded
315 bool loaded = false;
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);
322 if (!recurse)
323 return false;
325 return false;
328 void
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))
335 continue;
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 ();