Merge branch 'loaded-branch'
[moon.git] / src / frameworkelement.cpp
blob0a213da9207ff5cc3943484d2eab02ab08aa499a
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * frameworkelement.cpp:
5 * Copyright 2007 Novell, Inc. (http://www.novell.com)
7 * See the LICENSE file included with the distribution for details.
8 *
9 */
11 #include <config.h>
13 #include <math.h>
15 #include "debug.h"
16 #include "geometry.h"
17 #include "application.h"
18 #include "deployment.h"
19 #include "runtime.h"
20 #include "namescope.h"
21 #include "frameworkelement.h"
22 #include "trigger.h"
23 #include "thickness.h"
24 #include "collection.h"
25 #include "style.h"
26 #include "validators.h"
28 #define MAX_LAYOUT_PASSES 250
30 FrameworkElementProvider::FrameworkElementProvider (DependencyObject *obj, PropertyPrecedence precedence) : PropertyValueProvider (obj, precedence)
32 actual_height_value = NULL;
33 actual_width_value = NULL;
34 last = Size (-INFINITY, -INFINITY);
37 FrameworkElementProvider::~FrameworkElementProvider ()
39 delete actual_height_value;
40 delete actual_width_value;
43 Value *
44 FrameworkElementProvider::GetPropertyValue (DependencyProperty *property)
46 if (property->GetId () != FrameworkElement::ActualHeightProperty &&
47 property->GetId () != FrameworkElement::ActualWidthProperty)
48 return NULL;
50 FrameworkElement *element = (FrameworkElement *) obj;
52 Size actual = last.IsEmpty () ? Size () : last;
53 Surface *surface = obj->GetSurface ();
55 if (!LayoutInformation::GetPreviousConstraint (obj) || (surface && surface->IsTopLevel (element) && obj->Is (Type::PANEL)))
56 actual = element->ComputeActualSize ();
58 if (last != actual) {
59 last = actual;
61 if (actual_height_value)
62 delete actual_height_value;
64 if (actual_width_value)
65 delete actual_width_value;
67 actual_height_value = new Value (actual.height);
68 actual_width_value = new Value (actual.width);
71 if (property->GetId () == FrameworkElement::ActualHeightProperty) {
72 return actual_height_value;
73 } else {
74 return actual_width_value;
78 FrameworkElement::FrameworkElement ()
80 SetObjectType (Type::FRAMEWORKELEMENT);
82 default_style_applied = false;
83 get_default_template_cb = NULL;
84 measure_cb = NULL;
85 arrange_cb = NULL;
86 loaded_cb = NULL;
87 bounds_with_children = Rect ();
88 logical_parent = NULL;
90 providers[PropertyPrecedence_LocalStyle] = new StylePropertyValueProvider (this, PropertyPrecedence_LocalStyle);
91 providers[PropertyPrecedence_DefaultStyle] = new StylePropertyValueProvider (this, PropertyPrecedence_DefaultStyle);
92 providers[PropertyPrecedence_DynamicValue] = new FrameworkElementProvider (this, PropertyPrecedence_DynamicValue);
95 FrameworkElement::~FrameworkElement ()
99 void
100 FrameworkElement::RenderLayoutClip (cairo_t *cr)
102 Geometry *geom = LayoutInformation::GetClip (this);
104 if (!geom)
105 return;
107 geom->Draw (cr);
108 cairo_clip (cr);
110 geom->unref ();
113 Point
114 FrameworkElement::GetTransformOrigin ()
116 Point *user_xform_origin = GetRenderTransformOrigin ();
118 double width = GetActualWidth ();
119 double height = GetActualHeight ();
121 return Point (width * user_xform_origin->x,
122 height * user_xform_origin->y);
125 void
126 FrameworkElement::SetLogicalParent (DependencyObject *logical_parent, MoonError *error)
128 if (logical_parent && this->logical_parent && this->logical_parent != logical_parent) {
129 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Element is a child of another element");
130 return;
133 this->logical_parent = logical_parent;
136 void
137 FrameworkElement::ElementAdded (UIElement *item)
139 UIElement::ElementAdded (item);
141 //item->UpdateLayout ();
143 if (IsLayoutContainer () && item->Is (Type::FRAMEWORKELEMENT)) {
144 FrameworkElement *fe = (FrameworkElement *)item;
145 fe->SetActualWidth (0.0);
146 fe->SetActualHeight (0.0);
151 void
152 FrameworkElement::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
154 if (args->GetProperty ()->GetOwnerType() != Type::FRAMEWORKELEMENT) {
155 UIElement::OnPropertyChanged (args, error);
156 return;
159 if (args->GetId () == FrameworkElement::WidthProperty ||
160 args->GetId () == FrameworkElement::MaxWidthProperty ||
161 args->GetId () == FrameworkElement::MinWidthProperty ||
162 args->GetId () == FrameworkElement::MaxHeightProperty ||
163 args->GetId () == FrameworkElement::MinHeightProperty ||
164 args->GetId () == FrameworkElement::HeightProperty ||
165 args->GetId () == FrameworkElement::MarginProperty) {
167 Point *p = GetRenderTransformOrigin ();
169 /* normally we'd only update the bounds of this
170 element on a width/height change, but if the render
171 transform is someplace other than (0,0), the
172 transform needs to be updated as well. */
173 FullInvalidate (p->x != 0.0 || p->y != 0.0);
175 FrameworkElement *visual_parent = (FrameworkElement *)GetVisualParent ();
176 if (visual_parent) {
177 if (visual_parent->Is (Type::CANVAS)) {
178 if (!IsLayoutContainer ()) {
179 ClearValue (FrameworkElement::ActualHeightProperty);
180 ClearValue (FrameworkElement::ActualWidthProperty);
182 InvalidateMeasure ();
183 InvalidateArrange ();
184 } else {
185 visual_parent->InvalidateMeasure ();
186 InvalidateMeasure ();
187 InvalidateArrange ();
189 } else {
190 InvalidateMeasure ();
191 InvalidateArrange ();
193 UpdateBounds ();
195 else if (args->GetId () == FrameworkElement::StyleProperty) {
196 if (args->GetNewValue()) {
197 Style *s = args->GetNewValue()->AsStyle ();
198 if (s) {
199 // this has a side effect of calling
200 // ProviderValueChanged on all values
201 // in the style, so we might end up
202 // with lots of property notifications
203 // here (reentrancy ok?)
205 Application::GetCurrent()->ApplyStyle (this, s);
207 ((StylePropertyValueProvider*)providers[PropertyPrecedence_LocalStyle])->SealStyle (s);
211 else if (args->GetId () == FrameworkElement::HorizontalAlignmentProperty ||
212 args->GetId () == FrameworkElement::VerticalAlignmentProperty) {
213 InvalidateArrange ();
214 FullInvalidate (true);
217 NotifyListenersOfPropertyChange (args, error);
220 Size
221 FrameworkElement::ApplySizeConstraints (const Size &size)
223 Size specified (GetWidth (), GetHeight ());
224 Size constrained (GetMinWidth (), GetMinHeight ());
226 constrained = constrained.Max (size);
228 if (!isnan (specified.width))
229 constrained.width = specified.width;
231 if (!isnan (specified.height))
232 constrained.height = specified.height;
234 constrained = constrained.Min (GetMaxWidth (), GetMaxHeight ());
235 constrained = constrained.Max (GetMinWidth (), GetMinHeight ());
237 return constrained;
240 void
241 FrameworkElement::ComputeBounds ()
243 Size size (GetActualWidth (), GetActualHeight ());
244 size = ApplySizeConstraints (size);
246 extents = Rect (0, 0, size.width, size.height);
248 bounds = IntersectBoundsWithClipPath (extents, false).Transform (&absolute_xform);
249 bounds_with_children = bounds;
251 VisualTreeWalker walker = VisualTreeWalker (this);
252 while (UIElement *item = walker.Step ()) {
253 if (!item->GetRenderVisible ())
254 continue;
256 bounds_with_children = bounds_with_children.Union (item->GetSubtreeBounds ());
260 Rect
261 FrameworkElement::GetSubtreeBounds ()
263 VisualTreeWalker walker = VisualTreeWalker (this);
264 if (GetSubtreeObject () != NULL)
265 return bounds_with_children;
267 return bounds;
270 Size
271 FrameworkElement::ComputeActualSize ()
273 UIElement *parent = GetVisualParent ();
275 if ((parent && !parent->Is (Type::CANVAS)) || (!Is (Type::CANVAS) && IsLayoutContainer ()))
276 return GetDesiredSize ();
278 Size actual (0, 0);
280 actual = ApplySizeConstraints (actual);
282 return actual;
285 bool
286 FrameworkElement::InsideObject (cairo_t *cr, double x, double y)
288 double width = GetActualWidth ();
289 double height = GetActualHeight ();
290 double nx = x, ny = y;
292 TransformPoint (&nx, &ny);
293 if (nx < 0 || ny < 0 || nx > width || ny > height)
294 return false;
296 Geometry *layout_clip = LayoutInformation::GetLayoutClip (this);
297 if (layout_clip && !layout_clip->GetBounds ().PointInside (nx, ny))
298 return false;
300 return UIElement::InsideObject (cr, x, y);
303 void
304 FrameworkElement::HitTest (cairo_t *cr, Point p, List *uielement_list)
306 if (!GetRenderVisible ())
307 return;
309 if (!GetHitTestVisible ())
310 return;
312 // first a quick bounds check
313 if (!GetSubtreeBounds().PointInside (p.x, p.y))
314 return;
316 if (!InsideClip (cr, p.x, p.y))
317 return;
319 /* create our node and stick it on front */
320 List::Node *us = uielement_list->Prepend (new UIElementNode (this));
321 bool hit = false;
323 VisualTreeWalker walker = VisualTreeWalker (this, ZReverse);
324 while (UIElement *child = walker.Step ()) {
325 child->HitTest (cr, p, uielement_list);
327 if (us != uielement_list->First ()) {
328 hit = true;
329 break;
333 if (!hit && !InsideObject (cr, p.x, p.y))
334 uielement_list->Remove (us);
337 void
338 FrameworkElement::FindElementsInHostCoordinates (cairo_t *cr, Point host, List *uielement_list)
340 if (!GetRenderVisible ())
341 return;
343 if (!GetHitTestVisible ())
344 return;
346 if (bounds_with_children.height <= 0)
347 return;
349 cairo_save (cr);
350 cairo_new_path (cr);
352 if (GetClip ()) {
353 RenderClipPath (cr, true);
354 cairo_save (cr);
355 cairo_identity_matrix (cr);
356 bool res = cairo_in_fill (cr, host.x, host.y);
357 cairo_restore (cr);
358 if (!res) {
359 cairo_restore (cr);
360 return;
364 /* create our node and stick it on front */
365 List::Node *us = uielement_list->Prepend (new UIElementNode (this));
367 VisualTreeWalker walker = VisualTreeWalker (this, ZForward);
368 while (UIElement *child = walker.Step ())
369 child->FindElementsInHostCoordinates (cr, host, uielement_list);
371 if (us == uielement_list->First ()) {
372 cairo_new_path (cr);
373 Region all(extents);
374 cairo_set_matrix (cr, &absolute_xform);
375 Render (cr, &all, true);
376 cairo_identity_matrix (cr);
378 if (!CanFindElement () ||
379 !(cairo_in_fill (cr, host.x, host.y) || cairo_in_stroke (cr, host.x, host.y)))
380 uielement_list->Remove (us);
382 cairo_restore (cr);
385 // FIXME: This is not the fastest way of implementing this, decomposing the rectangle into
386 // a series of points is probably going to be quite slow. It's a good first effort.
387 void
388 FrameworkElement::FindElementsInHostCoordinates (cairo_t *cr, Rect r, List *uielement_list)
390 bool res = false;
391 if (!GetRenderVisible ())
392 return;
394 if (!GetHitTestVisible ())
395 return;
397 if (bounds_with_children.height <= 0)
398 return;
400 if (!bounds_with_children.IntersectsWith (r))
401 return;
403 cairo_save (cr);
404 cairo_new_path (cr);
406 if (GetClip ()) {
407 RenderClipPath (cr, true);
408 cairo_save (cr);
409 cairo_identity_matrix (cr);
411 for (int i=r.x; i < r.x + r.width && !res; i++)
412 for (int j=r.y; j < r.y + r.height && !res; j++)
413 res = cairo_in_fill (cr, i, j);
415 cairo_restore (cr);
416 if (!res) {
417 cairo_restore (cr);
418 return;
422 /* create our node and stick it on front */
423 List::Node *us = uielement_list->Prepend (new UIElementNode (this));
425 VisualTreeWalker walker = VisualTreeWalker (this, ZForward);
426 while (UIElement *child = walker.Step ())
427 child->FindElementsInHostCoordinates (cr, r, uielement_list);
429 if (us == uielement_list->First ()) {
430 cairo_new_path (cr);
431 Region all(extents);
432 cairo_set_matrix (cr, &absolute_xform);
433 Render (cr, &all, true);
434 cairo_identity_matrix (cr);
436 res = false;
437 if (CanFindElement ()) {
438 for (int i= r.x; i < (r.x + r.width) && !res; i++)
439 for (int j= r.y; j < (r.y + r.height) && !res; j++)
440 res = cairo_in_fill (cr, i, j) || cairo_in_stroke (cr, i, j);
443 if (!res)
444 uielement_list->Remove (us);
446 cairo_restore (cr);
449 void
450 FrameworkElement::GetSizeForBrush (cairo_t *cr, double *width, double *height)
452 *width = GetActualWidth ();
453 *height = GetActualHeight ();
456 void
457 FrameworkElement::Measure (Size availableSize)
459 //LOG_LAYOUT ("measuring %p %s %g,%g\n", this, GetTypeName (), availableSize.width, availableSize.height);
460 ApplyTemplate ();
462 if (!IsLayoutContainer ()) {
463 UIElement *parent = GetVisualParent ();
465 if (!parent || parent->Is (Type::CANVAS)) {
466 InvalidateArrange ();
467 UpdateBounds ();
468 dirty_flags &= ~DirtyMeasure;
469 return;
473 Size *last = LayoutInformation::GetPreviousConstraint (this);
474 bool domeasure = (this->dirty_flags & DirtyMeasure) > 0;
476 domeasure |= !last || last->width != availableSize.width || last->height != availableSize.height;
478 if (GetVisibility () == VisibilityCollapsed) {
479 SetDesiredSize (Size (0,0));
480 return;
483 if (!domeasure)
484 return;
486 LayoutInformation::SetPreviousConstraint (this, &availableSize);
488 InvalidateArrange ();
489 UpdateBounds ();
491 dirty_flags &= ~DirtyMeasure;
493 Thickness margin = *GetMargin ();
494 Size size = availableSize.GrowBy (-margin);
496 size = ApplySizeConstraints (size);
498 if (measure_cb)
499 size = (*measure_cb)(size);
500 else
501 size = MeasureOverride (size);
503 // postcondition the results
504 size = ApplySizeConstraints (size);
506 size = size.GrowBy (margin);
507 size = size.Min (availableSize);
509 if (GetUseLayoutRounding ()) {
510 size.width = floor (size.width);
511 size.height = floor (size.height);
514 SetDesiredSize (size);
517 Size
518 FrameworkElement::MeasureOverride (Size availableSize)
520 Size desired = Size (0,0);
522 if (!IsLayoutContainer ())
523 return desired;
525 availableSize = ApplySizeConstraints (availableSize);
527 VisualTreeWalker walker = VisualTreeWalker (this);
528 while (UIElement *child = walker.Step ()) {
529 if (child->GetVisibility () != VisibilityVisible)
530 continue;
532 child->Measure (availableSize);
533 desired = child->GetDesiredSize ();
536 desired = ApplySizeConstraints (desired);
538 return desired;
542 // not sure about the disconnect between these two methods.. I would
543 // imagine both should take Rects and ArrangeOverride would return a
544 // rectangle as well..
545 void
546 FrameworkElement::Arrange (Rect finalRect)
548 //LOG_LAYOUT ("arranging %p %s %g,%g,%g,%g\n", this, GetTypeName (), finalRect.x, finalRect.y, finalRect.width, finalRect.height);
549 Rect *slot = LayoutInformation::GetLayoutSlot (this);
550 bool doarrange = this->dirty_flags & DirtyArrange;
552 doarrange |= slot ? *slot != finalRect : true;
554 if (finalRect.width < 0 || finalRect.height < 0
555 || isinf (finalRect.width) || isinf (finalRect.height)
556 || isnan (finalRect.width) || isnan (finalRect.height)) {
557 Size desired = GetDesiredSize ();
558 g_warning ("invalid arguments to Arrange (%g,%g,%g,%g) Desired = (%g,%g)", finalRect.x, finalRect.y, finalRect.width, finalRect.height, desired.width, desired.height);
559 return;
562 if (GetVisibility () == VisibilityCollapsed) {
563 SetRenderSize (Size(0,0));
564 return;
567 if (!doarrange)
568 return;
571 * FIXME I'm not happy with doing this here but until I come
572 * up with a better plan make sure that layout elements have
573 * been measured at least once
575 if (IsContainer () && !LayoutInformation::GetPreviousConstraint (this))
576 Measure (Size (finalRect.width, finalRect.height));
578 LayoutInformation::SetLayoutSlot (this, &finalRect);
579 ClearValue (LayoutInformation::LayoutClipProperty);
580 //LayoutInformation::SetLayoutClip (this, NULL);
582 this->dirty_flags &= ~DirtyArrange;
584 Thickness margin = *GetMargin ();
585 Rect child_rect = finalRect.GrowBy (-margin);
587 cairo_matrix_init_translate (&layout_xform, child_rect.x, child_rect.y);
588 UpdateTransform ();
589 UpdateBounds ();
590 this->dirty_flags &= ~DirtyArrange;
592 Size offer (child_rect.width, child_rect.height);
593 Size response;
594 Size desired = GetDesiredSize ().GrowBy (-margin);
596 HorizontalAlignment horiz = GetHorizontalAlignment ();
597 VerticalAlignment vert = GetVerticalAlignment ();
599 if (horiz != HorizontalAlignmentStretch)
600 offer.width = MIN (offer.width, desired.width);
602 if (vert != VerticalAlignmentStretch)
603 offer.height = MIN (offer.height, desired.height);
605 offer = ApplySizeConstraints (offer);
607 if (arrange_cb)
608 response = (*arrange_cb)(offer);
609 else
610 response = ArrangeOverride (offer);
612 /* XXX FIXME horrible hack */
613 UIElement *parent = GetVisualParent ();
614 bool in_layout = IsLayoutContainer ();
616 if (!in_layout) {
617 if (!parent || parent->Is (Type::CANVAS))
618 return;
620 Size old_size = GetRenderSize ();
621 //Point *old_offset = LayoutInformation::GetVisualOffset (this);
622 ClearValue (LayoutInformation::VisualOffsetProperty);
624 if (in_layout && GetUseLayoutRounding ()) {
625 response.width = floor (response.width);
626 response.height = floor (response.height);
629 SetActualWidth (response.width);
630 SetActualHeight (response.height);
632 response = ApplySizeConstraints (response);
633 Point visual_offset (child_rect.x, child_rect.y);
635 if (GetVisualParent ()) {
636 switch (horiz) {
637 case HorizontalAlignmentLeft:
638 break;
639 case HorizontalAlignmentRight:
640 visual_offset.x += child_rect.width - response.width;
641 break;
642 case HorizontalAlignmentCenter:
643 visual_offset.x += (child_rect.width - response.width) * .5;
644 break;
645 default:
646 visual_offset.x += MAX ((child_rect.width - response.width) * .5, 0);
647 break;
650 switch (vert) {
651 case VerticalAlignmentTop:
652 break;
653 case VerticalAlignmentBottom:
654 visual_offset.y += child_rect.height - response.height;
655 break;
656 case VerticalAlignmentCenter:
657 visual_offset.y += (child_rect.height - response.height) * .5;
658 break;
659 default:
660 visual_offset.y += MAX ((child_rect.height - response.height) * .5, 0);
662 break;
666 cairo_matrix_init_translate (&layout_xform, visual_offset.x, visual_offset.y);
667 LayoutInformation::SetVisualOffset (this, &visual_offset);
668 SetRenderSize (response);
670 Rect layout_clip = finalRect;
671 layout_clip.x -= visual_offset.x;
672 layout_clip.y -= visual_offset.y;
674 layout_clip = layout_clip.GrowBy (-margin);
675 RectangleGeometry *rectangle = new RectangleGeometry ();
676 rectangle->SetRect (&layout_clip);
677 LayoutInformation::SetLayoutClip (this, rectangle);
678 rectangle->unref ();
680 if (old_size != response) { // || (old_offset && *old_offset != visual_offset)) {
681 if (!LayoutInformation::GetLastRenderSize (this))
682 LayoutInformation::SetLastRenderSize (this, &old_size);
684 // XXX what do we do with finalRect.x and y?
685 //printf ("\u231a");
688 Size
689 FrameworkElement::ArrangeOverride (Size finalSize)
691 finalSize = ApplySizeConstraints (finalSize);
693 if (!IsLayoutContainer ())
694 return finalSize;
696 Size arranged = finalSize;
698 VisualTreeWalker walker = VisualTreeWalker (this);
699 while (UIElement *child = walker.Step ()) {
700 if (child->GetVisibility () != VisibilityVisible)
701 continue;
703 Rect childRect (0,0,finalSize.width,finalSize.height);
705 child->Arrange (childRect);
706 arranged = child->GetRenderSize ();
708 arranged = arranged.Max (finalSize);
711 arranged = arranged.Max (finalSize);
713 return arranged;
716 void
717 FrameworkElement::UpdateLayout ()
719 UIElement *element = this;
720 UIElement *parent = NULL;
722 // Seek to the top
723 while ((parent = element->GetVisualParent ())) {
724 if (parent->Is (Type::CANVAS))
725 break;
727 element = parent;
730 Surface *surface = element->GetSurface ();
732 LOG_LAYOUT ("\nFrameworkElement::UpdateLayout: ");
733 List *measure_list = new List ();
734 List *arrange_list = new List ();
735 List *size_list = new List ();
736 bool updated = false;
737 int i = 0;
738 while (i < MAX_LAYOUT_PASSES) {
739 LOG_LAYOUT ("\u267c");
741 measure_list->Clear (true);
742 arrange_list->Clear (true);
743 size_list->Clear (true);
745 i++;
746 DeepTreeWalker measure_walker (element);
747 while (FrameworkElement *child = (FrameworkElement*)measure_walker.Step ()) {
748 FrameworkElement *parent = (FrameworkElement*)child->GetVisualParent ();
750 if ((child->flags & UIElement::RENDER_VISIBLE) == 0) {
751 measure_walker.SkipBranch ();
752 continue;
755 if (child->dirty_flags & DirtyMeasure) {
756 UIElement *parent = child->GetVisualParent ();
757 if ((parent && !parent->Is (Type::CANVAS)) || child->IsContainer ()) {
758 measure_list->Append (new UIElementNode (child));
759 //g_warning ("adding %p, %s", child, child->GetTypeName ());
760 } else if (!measure_list->IsEmpty ()) {
761 measure_walker.SkipBranch ();
765 if (!measure_list->IsEmpty ())
766 continue;
768 if (child->dirty_flags & DirtyArrange)
769 arrange_list->Append (new UIElementNode (child));
771 if (!arrange_list->IsEmpty ())
772 continue;
774 if (child->ReadLocalValue (LayoutInformation::LastRenderSizeProperty))
775 size_list->Append (new UIElementNode (child));
777 if (!size_list->IsEmpty ())
778 continue;
781 if (!measure_list->IsEmpty ()) {
782 if (surface)
783 surface->needs_measure = false;
784 while (UIElementNode* node = (UIElementNode*)measure_list->First ()) {
785 measure_list->Unlink (node);
787 node->uielement->DoMeasure ();
788 //if (node->uielement->GetVisuaParent ()->dirty_flags & dirty_measure)
789 // node->Prepend (new UIElementNode (parent));
791 updated = true;
792 delete (node);
794 } else if (!arrange_list->IsEmpty ()) {
795 if (surface)
796 surface->needs_arrange = false;
797 while (UIElementNode *node = (UIElementNode*)arrange_list->First ()) {
798 arrange_list->Unlink (node);
800 if (surface && surface->needs_measure) {
801 delete (node);
802 break;
805 node->uielement->DoArrange ();
806 //if (node->uielement->GetVisuaParent ()->dirty_flags & dirty_arrange)
807 // node->Prepend (new UIElementNode (parent));
809 updated = true;
810 delete (node);
812 } else if (!size_list->IsEmpty ()) {
813 while (UIElementNode *node = (UIElementNode*)size_list->First ()) {
814 if (surface && (surface->needs_measure || surface->needs_arrange)) {
815 surface->needs_measure = surface->needs_arrange = false;
816 break;
819 size_list->Unlink (node);
820 FrameworkElement *fe = (FrameworkElement*) node->uielement;
822 updated = true;
823 Size *last = LayoutInformation::GetLastRenderSize (fe);
824 if (last) {
825 SizeChangedEventArgs *args = new SizeChangedEventArgs (*last, fe->GetRenderSize ());
826 fe->ClearValue (LayoutInformation::LastRenderSizeProperty, false);
827 fe->Emit (FrameworkElement::SizeChangedEvent, args);
829 delete (node);
831 } else if (updated) {
832 Deployment::GetCurrent()->LayoutUpdated ();
833 break;
837 delete measure_list;
838 delete arrange_list;
839 delete size_list;
841 if (i >= MAX_LAYOUT_PASSES) {
842 LOG_LAYOUT ("\n************** UpdateLayout Bailing Out after %d Passes *******************\n", i);
843 } else {
844 LOG_LAYOUT (" (%d)\n", i);
848 void
849 FrameworkElement::RegisterManagedOverrides (MeasureOverrideCallback measure_cb, ArrangeOverrideCallback arrange_cb,
850 GetDefaultTemplateCallback get_default_template_cb, LoadedCallback loaded_cb)
852 this->measure_cb = measure_cb;
853 this->arrange_cb = arrange_cb;
854 this->get_default_template_cb = get_default_template_cb;
855 this->loaded_cb = loaded_cb;
858 void
859 FrameworkElement::SetDefaultStyle (Style *style)
861 if (style) {
862 Application::GetCurrent()->ApplyStyle (this, style);
863 default_style_applied = true;
864 ((StylePropertyValueProvider*)providers[PropertyPrecedence_DefaultStyle])->SealStyle (style);
869 void
870 FrameworkElement::OnLoaded ()
872 UIElement::OnLoaded ();
874 if (loaded_cb)
875 (*loaded_cb) (this);
878 bool
879 FrameworkElement::ApplyTemplate ()
881 if (GetSubtreeObject ())
882 return false;
884 bool result = DoApplyTemplate ();
885 if (result)
886 OnApplyTemplate ();
887 return result;
890 bool
891 FrameworkElement::DoApplyTemplate ()
893 UIElement *e = GetDefaultTemplate ();
894 if (e) {
895 MoonError err;
896 e->SetParent (this, &err);
897 SetSubtreeObject (e);
898 ElementAdded (e);
900 return e != NULL;
903 void
904 FrameworkElement::ElementRemoved (UIElement *obj)
906 if (GetSubtreeObject () == obj) {
907 MoonError e;
908 obj->SetParent (NULL, &e);
909 SetSubtreeObject (NULL);
911 UIElement::ElementRemoved (obj);
914 UIElement *
915 FrameworkElement::GetDefaultTemplate ()
917 if (get_default_template_cb)
918 return get_default_template_cb (this);
919 return NULL;