2009-10-09 Chris Toshok <toshok@ximian.com>
[moon.git] / src / frameworkelement.cpp
blobaaff875700be4326a2095d1835c8b82608896c55
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 "runtime.h"
19 #include "namescope.h"
20 #include "frameworkelement.h"
21 #include "trigger.h"
22 #include "thickness.h"
23 #include "collection.h"
24 #include "style.h"
25 #include "validators.h"
27 #define MAX_LAYOUT_PASSES 250
29 FrameworkElementProvider::FrameworkElementProvider (DependencyObject *obj, PropertyPrecedence precedence) : PropertyValueProvider (obj, precedence)
31 actual_height_value = NULL;
32 actual_width_value = NULL;
33 last = Size (-INFINITY, -INFINITY);
36 FrameworkElementProvider::~FrameworkElementProvider ()
38 delete actual_height_value;
39 delete actual_width_value;
42 Value *
43 FrameworkElementProvider::GetPropertyValue (DependencyProperty *property)
45 if (property->GetId () != FrameworkElement::ActualHeightProperty &&
46 property->GetId () != FrameworkElement::ActualWidthProperty)
47 return NULL;
49 FrameworkElement *element = (FrameworkElement *) obj;
51 Size actual = last.IsEmpty () ? Size () : last;
52 Surface *surface = obj->GetSurface ();
54 if (!LayoutInformation::GetPreviousConstraint (obj) || (surface && surface->IsTopLevel (element) && obj->Is (Type::PANEL)))
55 actual = element->ComputeActualSize ();
57 if (last != actual) {
58 last = actual;
60 if (actual_height_value)
61 delete actual_height_value;
63 if (actual_width_value)
64 delete actual_width_value;
66 actual_height_value = new Value (actual.height);
67 actual_width_value = new Value (actual.width);
70 if (property->GetId () == FrameworkElement::ActualHeightProperty) {
71 return actual_height_value;
72 } else {
73 return actual_width_value;
77 FrameworkElement::FrameworkElement ()
79 SetObjectType (Type::FRAMEWORKELEMENT);
81 default_style_applied = false;
82 measure_cb = NULL;
83 arrange_cb = NULL;
84 bounds_with_children = Rect ();
85 logical_parent = NULL;
87 providers[PropertyPrecedence_LocalStyle] = new StylePropertyValueProvider (this, PropertyPrecedence_LocalStyle);
88 providers[PropertyPrecedence_DefaultStyle] = new StylePropertyValueProvider (this, PropertyPrecedence_DefaultStyle);
89 providers[PropertyPrecedence_DynamicValue] = new FrameworkElementProvider (this, PropertyPrecedence_DynamicValue);
92 FrameworkElement::~FrameworkElement ()
96 void
97 FrameworkElement::RenderLayoutClip (cairo_t *cr)
99 Geometry *geom = LayoutInformation::GetClip (this);
101 if (!geom)
102 return;
104 geom->Draw (cr);
105 cairo_clip (cr);
107 geom->unref ();
110 Point
111 FrameworkElement::GetTransformOrigin ()
113 Point *user_xform_origin = GetRenderTransformOrigin ();
115 double width = GetActualWidth ();
116 double height = GetActualHeight ();
118 return Point (width * user_xform_origin->x,
119 height * user_xform_origin->y);
122 void
123 FrameworkElement::SetLogicalParent (DependencyObject *logical_parent, MoonError *error)
125 if (logical_parent && this->logical_parent && this->logical_parent != logical_parent) {
126 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Element is a child of another element");
127 return;
130 this->logical_parent = logical_parent;
133 void
134 FrameworkElement::ElementAdded (UIElement *item)
136 UIElement::ElementAdded (item);
138 //item->UpdateLayout ();
140 if (IsLayoutContainer () && item->Is (Type::FRAMEWORKELEMENT)) {
141 FrameworkElement *fe = (FrameworkElement *)item;
142 fe->SetActualWidth (0.0);
143 fe->SetActualHeight (0.0);
148 void
149 FrameworkElement::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
151 if (args->GetProperty ()->GetOwnerType() != Type::FRAMEWORKELEMENT) {
152 UIElement::OnPropertyChanged (args, error);
153 return;
156 if (args->GetId () == FrameworkElement::WidthProperty ||
157 args->GetId () == FrameworkElement::MaxWidthProperty ||
158 args->GetId () == FrameworkElement::MinWidthProperty ||
159 args->GetId () == FrameworkElement::MaxHeightProperty ||
160 args->GetId () == FrameworkElement::MinHeightProperty ||
161 args->GetId () == FrameworkElement::HeightProperty ||
162 args->GetId () == FrameworkElement::MarginProperty) {
164 Point *p = GetRenderTransformOrigin ();
166 /* normally we'd only update the bounds of this
167 element on a width/height change, but if the render
168 transform is someplace other than (0,0), the
169 transform needs to be updated as well. */
170 FullInvalidate (p->x != 0.0 || p->y != 0.0);
172 FrameworkElement *visual_parent = (FrameworkElement *)GetVisualParent ();
173 if (visual_parent) {
174 if (visual_parent->Is (Type::CANVAS)) {
175 if (!IsLayoutContainer ()) {
176 ClearValue (FrameworkElement::ActualHeightProperty);
177 ClearValue (FrameworkElement::ActualWidthProperty);
179 InvalidateMeasure ();
180 InvalidateArrange ();
181 } else {
182 visual_parent->InvalidateMeasure ();
183 InvalidateMeasure ();
184 InvalidateArrange ();
186 } else {
187 InvalidateMeasure ();
188 InvalidateArrange ();
190 UpdateBounds ();
192 else if (args->GetId () == FrameworkElement::StyleProperty) {
193 if (args->GetNewValue()) {
194 Style *s = args->GetNewValue()->AsStyle ();
195 if (s) {
196 // this has a side effect of calling
197 // ProviderValueChanged on all values
198 // in the style, so we might end up
199 // with lots of property notifications
200 // here (reentrancy ok?)
202 Application::GetCurrent()->ApplyStyle (this, s);
204 ((StylePropertyValueProvider*)providers[PropertyPrecedence_LocalStyle])->SealStyle (s);
208 else if (args->GetId () == FrameworkElement::HorizontalAlignmentProperty ||
209 args->GetId () == FrameworkElement::VerticalAlignmentProperty) {
210 InvalidateArrange ();
211 FullInvalidate (true);
214 NotifyListenersOfPropertyChange (args, error);
217 Size
218 FrameworkElement::ApplySizeConstraints (const Size &size)
220 Size specified (GetWidth (), GetHeight ());
221 Size constrained (GetMinWidth (), GetMinHeight ());
223 constrained = constrained.Max (size);
225 if (!isnan (specified.width))
226 constrained.width = specified.width;
228 if (!isnan (specified.height))
229 constrained.height = specified.height;
231 constrained = constrained.Min (GetMaxWidth (), GetMaxHeight ());
232 constrained = constrained.Max (GetMinWidth (), GetMinHeight ());
234 return constrained;
237 void
238 FrameworkElement::ComputeBounds ()
240 Size size (GetActualWidth (), GetActualHeight ());
241 size = ApplySizeConstraints (size);
243 extents = Rect (0, 0, size.width, size.height);
245 bounds = IntersectBoundsWithClipPath (extents, false).Transform (&absolute_xform);
246 bounds_with_children = bounds;
248 VisualTreeWalker walker = VisualTreeWalker (this);
249 while (UIElement *item = walker.Step ()) {
250 if (!item->GetRenderVisible ())
251 continue;
253 bounds_with_children = bounds_with_children.Union (item->GetSubtreeBounds ());
257 Rect
258 FrameworkElement::GetSubtreeBounds ()
260 VisualTreeWalker walker = VisualTreeWalker (this);
261 if (GetSubtreeObject () != NULL)
262 return bounds_with_children;
264 return bounds;
267 Size
268 FrameworkElement::ComputeActualSize ()
270 UIElement *parent = GetVisualParent ();
272 if ((parent && !parent->Is (Type::CANVAS)) || (!Is (Type::CANVAS) && IsLayoutContainer ()))
273 return GetDesiredSize ();
275 Size actual (0, 0);
277 actual = ApplySizeConstraints (actual);
279 return actual;
282 bool
283 FrameworkElement::InsideObject (cairo_t *cr, double x, double y)
285 double width = GetActualWidth ();
286 double height = GetActualHeight ();
287 double nx = x, ny = y;
289 TransformPoint (&nx, &ny);
290 if (nx < 0 || ny < 0 || nx > width || ny > height)
291 return false;
293 Geometry *layout_clip = LayoutInformation::GetLayoutClip (this);
294 if (layout_clip && !layout_clip->GetBounds ().PointInside (nx, ny))
295 return false;
297 return UIElement::InsideObject (cr, x, y);
300 void
301 FrameworkElement::HitTest (cairo_t *cr, Point p, List *uielement_list)
303 if (!GetRenderVisible ())
304 return;
306 if (!GetHitTestVisible ())
307 return;
309 // first a quick bounds check
310 if (!GetSubtreeBounds().PointInside (p.x, p.y))
311 return;
313 if (!InsideClip (cr, p.x, p.y))
314 return;
316 /* create our node and stick it on front */
317 List::Node *us = uielement_list->Prepend (new UIElementNode (this));
318 bool hit = false;
320 VisualTreeWalker walker = VisualTreeWalker (this, ZReverse);
321 while (UIElement *child = walker.Step ()) {
322 child->HitTest (cr, p, uielement_list);
324 if (us != uielement_list->First ()) {
325 hit = true;
326 break;
330 if (!hit && !InsideObject (cr, p.x, p.y))
331 uielement_list->Remove (us);
334 void
335 FrameworkElement::FindElementsInHostCoordinates (cairo_t *cr, Point host, List *uielement_list)
337 if (!GetRenderVisible ())
338 return;
340 if (!GetHitTestVisible ())
341 return;
343 if (bounds_with_children.height <= 0)
344 return;
346 cairo_save (cr);
347 cairo_new_path (cr);
349 if (GetClip ()) {
350 RenderClipPath (cr, true);
351 cairo_save (cr);
352 cairo_identity_matrix (cr);
353 bool res = cairo_in_fill (cr, host.x, host.y);
354 cairo_restore (cr);
355 if (!res) {
356 cairo_restore (cr);
357 return;
361 /* create our node and stick it on front */
362 List::Node *us = uielement_list->Prepend (new UIElementNode (this));
364 VisualTreeWalker walker = VisualTreeWalker (this, ZForward);
365 while (UIElement *child = walker.Step ())
366 child->FindElementsInHostCoordinates (cr, host, uielement_list);
368 if (us == uielement_list->First ()) {
369 cairo_new_path (cr);
370 Region all(extents);
371 cairo_set_matrix (cr, &absolute_xform);
372 Render (cr, &all, true);
373 cairo_identity_matrix (cr);
375 if (!CanFindElement () ||
376 !(cairo_in_fill (cr, host.x, host.y) || cairo_in_stroke (cr, host.x, host.y)))
377 uielement_list->Remove (us);
379 cairo_restore (cr);
382 // FIXME: This is not the fastest way of implementing this, decomposing the rectangle into
383 // a series of points is probably going to be quite slow. It's a good first effort.
384 void
385 FrameworkElement::FindElementsInHostCoordinates (cairo_t *cr, Rect r, List *uielement_list)
387 bool res = false;
388 if (!GetRenderVisible ())
389 return;
391 if (!GetHitTestVisible ())
392 return;
394 if (bounds_with_children.height <= 0)
395 return;
397 if (!bounds_with_children.IntersectsWith (r))
398 return;
400 cairo_save (cr);
401 cairo_new_path (cr);
403 if (GetClip ()) {
404 RenderClipPath (cr, true);
405 cairo_save (cr);
406 cairo_identity_matrix (cr);
408 for (int i=r.x; i < r.x + r.width && !res; i++)
409 for (int j=r.y; j < r.y + r.height && !res; j++)
410 res = cairo_in_fill (cr, i, j);
412 cairo_restore (cr);
413 if (!res) {
414 cairo_restore (cr);
415 return;
419 /* create our node and stick it on front */
420 List::Node *us = uielement_list->Prepend (new UIElementNode (this));
422 VisualTreeWalker walker = VisualTreeWalker (this, ZForward);
423 while (UIElement *child = walker.Step ())
424 child->FindElementsInHostCoordinates (cr, r, uielement_list);
426 if (us == uielement_list->First ()) {
427 cairo_new_path (cr);
428 Region all(extents);
429 cairo_set_matrix (cr, &absolute_xform);
430 Render (cr, &all, true);
431 cairo_identity_matrix (cr);
433 res = false;
434 if (CanFindElement ()) {
435 for (int i= r.x; i < (r.x + r.width) && !res; i++)
436 for (int j= r.y; j < (r.y + r.height) && !res; j++)
437 res = cairo_in_fill (cr, i, j) || cairo_in_stroke (cr, i, j);
440 if (!res)
441 uielement_list->Remove (us);
443 cairo_restore (cr);
446 void
447 FrameworkElement::GetSizeForBrush (cairo_t *cr, double *width, double *height)
449 *width = GetActualWidth ();
450 *height = GetActualHeight ();
453 void
454 FrameworkElement::Measure (Size availableSize)
456 //LOG_LAYOUT ("measuring %p %s %g,%g\n", this, GetTypeName (), availableSize.width, availableSize.height);
457 if (Is(Type::CONTROL)) {
458 Control *control = (Control*)this;
459 control->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 *updated_list = new List ();
736 List *size_list = new List ();
737 bool updated = false;
738 int i = 0;
739 while (i < MAX_LAYOUT_PASSES) {
740 LOG_LAYOUT ("\u267c");
742 measure_list->Clear (true);
743 arrange_list->Clear (true);
744 updated_list->Clear (true);
745 size_list->Clear (true);
747 i++;
748 DeepTreeWalker measure_walker (element);
749 while (FrameworkElement *child = (FrameworkElement*)measure_walker.Step ()) {
750 FrameworkElement *parent = (FrameworkElement*)child->GetVisualParent ();
752 if (parent && parent->IsLoaded () && !child->IsLoaded ()) {
753 LOG_LAYOUT ("FrameworkElement::UpdateLayout: element (%p) not yet loaded\n", child);
755 List *load_list = child->WalkTreeForLoaded (false);
756 child->EmitSubtreeLoad (load_list);
757 delete load_list;
760 if ((child->flags & UIElement::RENDER_VISIBLE) == 0) {
761 measure_walker.SkipBranch ();
762 continue;
765 if (child->dirty_flags & DirtyMeasure) {
766 UIElement *parent = child->GetVisualParent ();
767 if ((parent && !parent->Is (Type::CANVAS)) || child->IsContainer ()) {
768 measure_list->Append (new UIElementNode (child));
769 //g_warning ("adding %p, %s", child, child->GetTypeName ());
770 } else if (!measure_list->IsEmpty ()) {
771 measure_walker.SkipBranch ();
775 if (!measure_list->IsEmpty ())
776 continue;
778 if (child->dirty_flags & DirtyArrange)
779 arrange_list->Append (new UIElementNode (child));
781 if (!arrange_list->IsEmpty ())
782 continue;
784 if (child->ReadLocalValue (LayoutInformation::LastRenderSizeProperty))
785 size_list->Append (new UIElementNode (child));
787 if (!size_list->IsEmpty ())
788 continue;
790 if (updated)
791 updated_list->Append (new UIElementNode (child));
794 if (!measure_list->IsEmpty ()) {
795 if (surface)
796 surface->needs_measure = false;
797 while (UIElementNode* node = (UIElementNode*)measure_list->First ()) {
798 measure_list->Unlink (node);
800 node->uielement->DoMeasure ();
801 //if (node->uielement->GetVisuaParent ()->dirty_flags & dirty_measure)
802 // node->Prepend (new UIElementNode (parent));
804 updated = true;
805 delete (node);
807 } else if (!arrange_list->IsEmpty ()) {
808 if (surface)
809 surface->needs_arrange = false;
810 while (UIElementNode *node = (UIElementNode*)arrange_list->First ()) {
811 arrange_list->Unlink (node);
813 if (surface && surface->needs_measure) {
814 delete (node);
815 break;
818 node->uielement->DoArrange ();
819 //if (node->uielement->GetVisuaParent ()->dirty_flags & dirty_arrange)
820 // node->Prepend (new UIElementNode (parent));
822 updated = true;
823 delete (node);
825 } else if (!size_list->IsEmpty ()) {
826 while (UIElementNode *node = (UIElementNode*)size_list->First ()) {
827 if (surface && (surface->needs_measure || surface->needs_arrange)) {
828 surface->needs_measure = surface->needs_arrange = false;
829 break;
832 size_list->Unlink (node);
833 FrameworkElement *fe = (FrameworkElement*) node->uielement;
835 updated = true;
836 Size *last = LayoutInformation::GetLastRenderSize (fe);
837 if (last) {
838 SizeChangedEventArgs *args = new SizeChangedEventArgs (*last, fe->GetRenderSize ());
839 fe->ClearValue (LayoutInformation::LastRenderSizeProperty, false);
840 fe->Emit (FrameworkElement::SizeChangedEvent, args);
842 delete (node);
844 } else if (!updated_list->IsEmpty ()) {
845 updated = false;
846 while (UIElementNode *node = (UIElementNode*)updated_list->First ()) {
847 updated_list->Unlink (node);
848 FrameworkElement *fe = (FrameworkElement*)node->uielement;
850 fe->Emit (LayoutUpdatedEvent);
851 delete (node);
853 break;
857 delete measure_list;
858 delete arrange_list;
859 delete updated_list;
860 delete size_list;
862 if (i >= MAX_LAYOUT_PASSES) {
863 LOG_LAYOUT ("\n************** UpdateLayout Bailing Out after %d Passes *******************\n", i);
864 } else {
865 LOG_LAYOUT (" (%d)\n", i);
869 void
870 FrameworkElement::RegisterManagedOverrides (MeasureOverrideCallback measure_cb, ArrangeOverrideCallback arrange_cb)
872 this->measure_cb = measure_cb;
873 this->arrange_cb = arrange_cb;
876 void
877 FrameworkElement::SetDefaultStyle (Style *style)
879 if (style) {
880 Application::GetCurrent()->ApplyStyle (this, style);
881 default_style_applied = true;
882 ((StylePropertyValueProvider*)providers[PropertyPrecedence_DefaultStyle])->SealStyle (style);