just kick off another build
[moon.git] / src / frameworkelement.cpp
blob60929bfc8c21d65bc190538dc03c9fc292fe3e11
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 bool
149 FrameworkElement::SetValueWithErrorImpl (DependencyProperty *property, Value *value, MoonError *error)
151 return UIElement::SetValueWithErrorImpl (property, value, error);
154 void
155 FrameworkElement::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
157 if (args->GetProperty ()->GetOwnerType() != Type::FRAMEWORKELEMENT) {
158 UIElement::OnPropertyChanged (args, error);
159 return;
162 if (args->GetId () == FrameworkElement::WidthProperty ||
163 args->GetId () == FrameworkElement::MaxWidthProperty ||
164 args->GetId () == FrameworkElement::MinWidthProperty ||
165 args->GetId () == FrameworkElement::MaxHeightProperty ||
166 args->GetId () == FrameworkElement::MinHeightProperty ||
167 args->GetId () == FrameworkElement::HeightProperty ||
168 args->GetId () == FrameworkElement::MarginProperty) {
170 Point *p = GetRenderTransformOrigin ();
172 /* normally we'd only update the bounds of this
173 element on a width/height change, but if the render
174 transform is someplace other than (0,0), the
175 transform needs to be updated as well. */
176 FullInvalidate (p->x != 0.0 || p->y != 0.0);
178 FrameworkElement *visual_parent = (FrameworkElement *)GetVisualParent ();
179 if (visual_parent) {
180 if (visual_parent->Is (Type::CANVAS)) {
181 if (!IsLayoutContainer ()) {
182 ClearValue (FrameworkElement::ActualHeightProperty);
183 ClearValue (FrameworkElement::ActualWidthProperty);
185 InvalidateMeasure ();
186 InvalidateArrange ();
187 } else {
188 visual_parent->InvalidateMeasure ();
189 InvalidateMeasure ();
190 InvalidateArrange ();
192 } else {
193 InvalidateMeasure ();
194 InvalidateArrange ();
196 UpdateBounds ();
198 else if (args->GetId () == FrameworkElement::StyleProperty) {
199 if (args->GetNewValue()) {
200 Style *s = args->GetNewValue()->AsStyle ();
201 if (s) {
202 // this has a side effect of calling
203 // ProviderValueChanged on all values
204 // in the style, so we might end up
205 // with lots of property notifications
206 // here (reentrancy ok?)
208 Application::GetCurrent()->ApplyStyle (this, s);
210 ((StylePropertyValueProvider*)providers[PropertyPrecedence_LocalStyle])->SealStyle (s);
214 else if (args->GetId () == FrameworkElement::HorizontalAlignmentProperty ||
215 args->GetId () == FrameworkElement::VerticalAlignmentProperty) {
216 InvalidateArrange ();
217 FullInvalidate (true);
220 NotifyListenersOfPropertyChange (args, error);
223 Size
224 FrameworkElement::ApplySizeConstraints (const Size &size)
226 Size specified (GetWidth (), GetHeight ());
227 Size constrained (GetMinWidth (), GetMinHeight ());
229 constrained = constrained.Max (size);
231 if (!isnan (specified.width))
232 constrained.width = specified.width;
234 if (!isnan (specified.height))
235 constrained.height = specified.height;
237 constrained = constrained.Min (GetMaxWidth (), GetMaxHeight ());
238 constrained = constrained.Max (GetMinWidth (), GetMinHeight ());
240 return constrained;
243 void
244 FrameworkElement::ComputeBounds ()
246 Size size (GetActualWidth (), GetActualHeight ());
247 size = ApplySizeConstraints (size);
249 extents = Rect (0, 0, size.width, size.height);
251 bounds = IntersectBoundsWithClipPath (extents, false).Transform (&absolute_xform);
252 bounds_with_children = bounds;
254 VisualTreeWalker walker = VisualTreeWalker (this);
255 while (UIElement *item = walker.Step ()) {
256 if (!item->GetRenderVisible ())
257 continue;
259 bounds_with_children = bounds_with_children.Union (item->GetSubtreeBounds ());
263 Rect
264 FrameworkElement::GetSubtreeBounds ()
266 VisualTreeWalker walker = VisualTreeWalker (this);
267 if (GetSubtreeObject () != NULL)
268 return bounds_with_children;
270 return bounds;
273 Size
274 FrameworkElement::ComputeActualSize ()
276 UIElement *parent = GetVisualParent ();
278 if ((parent && !parent->Is (Type::CANVAS)) || (!Is (Type::CANVAS) && IsLayoutContainer ()))
279 return GetDesiredSize ();
281 Size actual (0, 0);
283 actual = ApplySizeConstraints (actual);
285 return actual;
288 bool
289 FrameworkElement::InsideObject (cairo_t *cr, double x, double y)
291 double width = GetActualWidth ();
292 double height = GetActualHeight ();
293 double nx = x, ny = y;
295 TransformPoint (&nx, &ny);
296 if (nx < 0 || ny < 0 || nx > width || ny > height)
297 return false;
299 Geometry *layout_clip = LayoutInformation::GetLayoutClip (this);
300 if (layout_clip && !layout_clip->GetBounds ().PointInside (nx, ny))
301 return false;
303 return UIElement::InsideObject (cr, x, y);
306 void
307 FrameworkElement::HitTest (cairo_t *cr, Point p, List *uielement_list)
309 if (!GetRenderVisible ())
310 return;
312 if (!GetHitTestVisible ())
313 return;
315 // first a quick bounds check
316 if (!GetSubtreeBounds().PointInside (p.x, p.y))
317 return;
319 if (!InsideClip (cr, p.x, p.y))
320 return;
322 /* create our node and stick it on front */
323 List::Node *us = uielement_list->Prepend (new UIElementNode (this));
324 bool hit = false;
326 VisualTreeWalker walker = VisualTreeWalker (this, ZReverse);
327 while (UIElement *child = walker.Step ()) {
328 child->HitTest (cr, p, uielement_list);
330 if (us != uielement_list->First ()) {
331 hit = true;
332 break;
336 if (!hit && !InsideObject (cr, p.x, p.y))
337 uielement_list->Remove (us);
340 void
341 FrameworkElement::FindElementsInHostCoordinates (cairo_t *cr, Point host, List *uielement_list)
343 if (!GetRenderVisible ())
344 return;
346 if (!GetHitTestVisible ())
347 return;
349 if (bounds_with_children.height <= 0)
350 return;
352 cairo_save (cr);
353 cairo_new_path (cr);
355 if (GetClip ()) {
356 RenderClipPath (cr, true);
357 cairo_save (cr);
358 cairo_identity_matrix (cr);
359 bool res = cairo_in_fill (cr, host.x, host.y);
360 cairo_restore (cr);
361 if (!res) {
362 cairo_restore (cr);
363 return;
367 /* create our node and stick it on front */
368 List::Node *us = uielement_list->Prepend (new UIElementNode (this));
370 VisualTreeWalker walker = VisualTreeWalker (this, ZForward);
371 while (UIElement *child = walker.Step ())
372 child->FindElementsInHostCoordinates (cr, host, uielement_list);
374 if (us == uielement_list->First ()) {
375 cairo_new_path (cr);
376 Region all(extents);
377 cairo_set_matrix (cr, &absolute_xform);
378 Render (cr, &all, true);
379 cairo_identity_matrix (cr);
381 if (!CanFindElement () ||
382 !(cairo_in_fill (cr, host.x, host.y) || cairo_in_stroke (cr, host.x, host.y)))
383 uielement_list->Remove (us);
385 cairo_restore (cr);
388 // FIXME: This is not the fastest way of implementing this, decomposing the rectangle into
389 // a series of points is probably going to be quite slow. It's a good first effort.
390 void
391 FrameworkElement::FindElementsInHostCoordinates (cairo_t *cr, Rect r, List *uielement_list)
393 bool res = false;
394 if (!GetRenderVisible ())
395 return;
397 if (!GetHitTestVisible ())
398 return;
400 if (bounds_with_children.height <= 0)
401 return;
403 if (!bounds_with_children.IntersectsWith (r))
404 return;
406 cairo_save (cr);
407 cairo_new_path (cr);
409 if (GetClip ()) {
410 RenderClipPath (cr, true);
411 cairo_save (cr);
412 cairo_identity_matrix (cr);
414 for (int i=r.x; i < r.x + r.width && !res; i++)
415 for (int j=r.y; j < r.y + r.height && !res; j++)
416 res = cairo_in_fill (cr, i, j);
418 cairo_restore (cr);
419 if (!res) {
420 cairo_restore (cr);
421 return;
425 /* create our node and stick it on front */
426 List::Node *us = uielement_list->Prepend (new UIElementNode (this));
428 VisualTreeWalker walker = VisualTreeWalker (this, ZForward);
429 while (UIElement *child = walker.Step ())
430 child->FindElementsInHostCoordinates (cr, r, uielement_list);
432 if (us == uielement_list->First ()) {
433 cairo_new_path (cr);
434 Region all(extents);
435 cairo_set_matrix (cr, &absolute_xform);
436 Render (cr, &all, true);
437 cairo_identity_matrix (cr);
439 res = false;
440 if (CanFindElement ()) {
441 for (int i= r.x; i < (r.x + r.width) && !res; i++)
442 for (int j= r.y; j < (r.y + r.height) && !res; j++)
443 res = cairo_in_fill (cr, i, j) || cairo_in_stroke (cr, i, j);
446 if (!res)
447 uielement_list->Remove (us);
449 cairo_restore (cr);
452 void
453 FrameworkElement::GetSizeForBrush (cairo_t *cr, double *width, double *height)
455 *width = GetActualWidth ();
456 *height = GetActualHeight ();
459 void
460 FrameworkElement::Measure (Size availableSize)
462 //LOG_LAYOUT ("measuring %p %s %g,%g\n", this, GetTypeName (), availableSize.width, availableSize.height);
463 if (Is(Type::CONTROL)) {
464 Control *control = (Control*)this;
465 control->ApplyTemplate();
468 if (!IsLayoutContainer ()) {
469 UIElement *parent = GetVisualParent ();
471 if (!parent || parent->Is (Type::CANVAS)) {
472 InvalidateArrange ();
473 UpdateBounds ();
474 dirty_flags &= ~DirtyMeasure;
475 return;
479 Size *last = LayoutInformation::GetPreviousConstraint (this);
480 bool domeasure = (this->dirty_flags & DirtyMeasure) > 0;
482 domeasure |= !last || last->width != availableSize.width || last->height != availableSize.height;
484 if (GetVisibility () == VisibilityCollapsed) {
485 SetDesiredSize (Size (0,0));
486 return;
489 if (!domeasure)
490 return;
492 LayoutInformation::SetPreviousConstraint (this, &availableSize);
494 InvalidateArrange ();
495 UpdateBounds ();
497 dirty_flags &= ~DirtyMeasure;
499 Thickness margin = *GetMargin ();
500 Size size = availableSize.GrowBy (-margin);
502 size = ApplySizeConstraints (size);
504 if (measure_cb)
505 size = (*measure_cb)(size);
506 else
507 size = MeasureOverride (size);
509 // postcondition the results
510 size = ApplySizeConstraints (size);
512 size = size.GrowBy (margin);
513 size = size.Min (availableSize);
515 if (GetUseLayoutRounding ()) {
516 size.width = floor (size.width);
517 size.height = floor (size.height);
520 SetDesiredSize (size);
523 Size
524 FrameworkElement::MeasureOverride (Size availableSize)
526 Size desired = Size (0,0);
528 if (!IsLayoutContainer ())
529 return desired;
531 availableSize = ApplySizeConstraints (availableSize);
533 VisualTreeWalker walker = VisualTreeWalker (this);
534 while (UIElement *child = walker.Step ()) {
535 if (child->GetVisibility () != VisibilityVisible)
536 continue;
538 child->Measure (availableSize);
539 desired = child->GetDesiredSize ();
542 desired = ApplySizeConstraints (desired);
544 return desired;
548 // not sure about the disconnect between these two methods.. I would
549 // imagine both should take Rects and ArrangeOverride would return a
550 // rectangle as well..
551 void
552 FrameworkElement::Arrange (Rect finalRect)
554 //LOG_LAYOUT ("arranging %p %s %g,%g,%g,%g\n", this, GetTypeName (), finalRect.x, finalRect.y, finalRect.width, finalRect.height);
555 Rect *slot = LayoutInformation::GetLayoutSlot (this);
556 bool doarrange = this->dirty_flags & DirtyArrange;
558 doarrange |= slot ? *slot != finalRect : true;
560 if (finalRect.width < 0 || finalRect.height < 0
561 || isinf (finalRect.width) || isinf (finalRect.height)
562 || isnan (finalRect.width) || isnan (finalRect.height)) {
563 Size desired = GetDesiredSize ();
564 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);
565 return;
568 if (GetVisibility () == VisibilityCollapsed) {
569 SetRenderSize (Size(0,0));
570 return;
573 if (!doarrange)
574 return;
577 * FIXME I'm not happy with doing this here but until I come
578 * up with a better plan make sure that layout elements have
579 * been measured at least once
581 if (IsContainer () && !LayoutInformation::GetPreviousConstraint (this))
582 Measure (Size (finalRect.width, finalRect.height));
584 LayoutInformation::SetLayoutSlot (this, &finalRect);
585 ClearValue (LayoutInformation::LayoutClipProperty);
586 //LayoutInformation::SetLayoutClip (this, NULL);
588 this->dirty_flags &= ~DirtyArrange;
590 Thickness margin = *GetMargin ();
591 Rect child_rect = finalRect.GrowBy (-margin);
593 cairo_matrix_init_translate (&layout_xform, child_rect.x, child_rect.y);
594 UpdateTransform ();
595 UpdateBounds ();
596 this->dirty_flags &= ~DirtyArrange;
598 Size offer (child_rect.width, child_rect.height);
599 Size response;
600 Size desired = GetDesiredSize ().GrowBy (-margin);
602 HorizontalAlignment horiz = GetHorizontalAlignment ();
603 VerticalAlignment vert = GetVerticalAlignment ();
605 if (horiz != HorizontalAlignmentStretch)
606 offer.width = MIN (offer.width, desired.width);
608 if (vert != VerticalAlignmentStretch)
609 offer.height = MIN (offer.height, desired.height);
611 offer = ApplySizeConstraints (offer);
613 if (arrange_cb)
614 response = (*arrange_cb)(offer);
615 else
616 response = ArrangeOverride (offer);
618 /* XXX FIXME horrible hack */
619 UIElement *parent = GetVisualParent ();
620 bool in_layout = IsLayoutContainer ();
622 if (!in_layout) {
623 if (!parent || parent->Is (Type::CANVAS))
624 return;
626 Size old_size = GetRenderSize ();
627 //Point *old_offset = LayoutInformation::GetVisualOffset (this);
628 ClearValue (LayoutInformation::VisualOffsetProperty);
630 if (in_layout && GetUseLayoutRounding ()) {
631 response.width = floor (response.width);
632 response.height = floor (response.height);
635 SetActualWidth (response.width);
636 SetActualHeight (response.height);
638 response = ApplySizeConstraints (response);
639 Point visual_offset (child_rect.x, child_rect.y);
641 if (GetVisualParent ()) {
642 switch (horiz) {
643 case HorizontalAlignmentLeft:
644 break;
645 case HorizontalAlignmentRight:
646 visual_offset.x += child_rect.width - response.width;
647 break;
648 case HorizontalAlignmentCenter:
649 visual_offset.x += (child_rect.width - response.width) * .5;
650 break;
651 default:
652 visual_offset.x += MAX ((child_rect.width - response.width) * .5, 0);
653 break;
656 switch (vert) {
657 case VerticalAlignmentTop:
658 break;
659 case VerticalAlignmentBottom:
660 visual_offset.y += child_rect.height - response.height;
661 break;
662 case VerticalAlignmentCenter:
663 visual_offset.y += (child_rect.height - response.height) * .5;
664 break;
665 default:
666 visual_offset.y += MAX ((child_rect.height - response.height) * .5, 0);
668 break;
672 cairo_matrix_init_translate (&layout_xform, visual_offset.x, visual_offset.y);
673 LayoutInformation::SetVisualOffset (this, &visual_offset);
674 SetRenderSize (response);
676 Rect layout_clip = finalRect;
677 layout_clip.x -= visual_offset.x;
678 layout_clip.y -= visual_offset.y;
680 layout_clip = layout_clip.GrowBy (-margin);
681 RectangleGeometry *rectangle = new RectangleGeometry ();
682 rectangle->SetRect (&layout_clip);
683 LayoutInformation::SetLayoutClip (this, rectangle);
684 rectangle->unref ();
686 if (old_size != response) { // || (old_offset && *old_offset != visual_offset)) {
687 if (!LayoutInformation::GetLastRenderSize (this))
688 LayoutInformation::SetLastRenderSize (this, &old_size);
690 // XXX what do we do with finalRect.x and y?
691 //printf ("\u231a");
694 Size
695 FrameworkElement::ArrangeOverride (Size finalSize)
697 finalSize = ApplySizeConstraints (finalSize);
699 if (!IsLayoutContainer ())
700 return finalSize;
702 Size arranged = finalSize;
704 VisualTreeWalker walker = VisualTreeWalker (this);
705 while (UIElement *child = walker.Step ()) {
706 if (child->GetVisibility () != VisibilityVisible)
707 continue;
709 Rect childRect (0,0,finalSize.width,finalSize.height);
711 child->Arrange (childRect);
712 arranged = child->GetRenderSize ();
714 arranged = arranged.Max (finalSize);
717 arranged = arranged.Max (finalSize);
719 return arranged;
722 void
723 FrameworkElement::UpdateLayout ()
725 UIElement *element = this;
726 UIElement *parent = NULL;
728 // Seek to the top
729 while ((parent = element->GetVisualParent ())) {
730 if (parent->Is (Type::CANVAS))
731 break;
733 element = parent;
736 Surface *surface = element->GetSurface ();
738 LOG_LAYOUT ("\nFrameworkElement::UpdateLayout: ");
739 List *measure_list = new List ();
740 List *arrange_list = new List ();
741 List *updated_list = new List ();
742 List *size_list = new List ();
743 bool updated = false;
744 int i = 0;
745 while (i < MAX_LAYOUT_PASSES) {
746 LOG_LAYOUT ("\u267c");
748 measure_list->Clear (true);
749 arrange_list->Clear (true);
750 updated_list->Clear (true);
751 size_list->Clear (true);
753 i++;
754 DeepTreeWalker measure_walker (element);
755 while (FrameworkElement *child = (FrameworkElement*)measure_walker.Step ()) {
756 FrameworkElement *parent = (FrameworkElement*)child->GetVisualParent ();
758 if (parent && parent->IsLoaded () && !child->IsLoaded ()) {
759 LOG_LAYOUT ("FrameworkElement::UpdateLayout: element (%p) not yet loaded\n", child);
761 List *load_list = child->WalkTreeForLoaded (false);
762 child->EmitSubtreeLoad (load_list);
763 delete load_list;
766 if ((child->flags & UIElement::RENDER_VISIBLE) == 0) {
767 measure_walker.SkipBranch ();
768 continue;
771 if (child->dirty_flags & DirtyMeasure) {
772 UIElement *parent = child->GetVisualParent ();
773 if ((parent && !parent->Is (Type::CANVAS)) || child->IsContainer ()) {
774 measure_list->Append (new UIElementNode (child));
775 //g_warning ("adding %p, %s", child, child->GetTypeName ());
776 } else if (!measure_list->IsEmpty ()) {
777 measure_walker.SkipBranch ();
781 if (!measure_list->IsEmpty ())
782 continue;
784 if (child->dirty_flags & DirtyArrange)
785 arrange_list->Append (new UIElementNode (child));
787 if (!arrange_list->IsEmpty ())
788 continue;
790 if (child->ReadLocalValue (LayoutInformation::LastRenderSizeProperty))
791 size_list->Append (new UIElementNode (child));
793 if (!size_list->IsEmpty ())
794 continue;
796 if (updated)
797 updated_list->Append (new UIElementNode (child));
800 if (!measure_list->IsEmpty ()) {
801 if (surface)
802 surface->needs_measure = false;
803 while (UIElementNode* node = (UIElementNode*)measure_list->First ()) {
804 measure_list->Unlink (node);
806 node->uielement->DoMeasure ();
807 //if (node->uielement->GetVisuaParent ()->dirty_flags & dirty_measure)
808 // node->Prepend (new UIElementNode (parent));
810 updated = true;
811 delete (node);
813 } else if (!arrange_list->IsEmpty ()) {
814 if (surface)
815 surface->needs_arrange = false;
816 while (UIElementNode *node = (UIElementNode*)arrange_list->First ()) {
817 arrange_list->Unlink (node);
819 if (surface && surface->needs_measure) {
820 delete (node);
821 break;
824 node->uielement->DoArrange ();
825 //if (node->uielement->GetVisuaParent ()->dirty_flags & dirty_arrange)
826 // node->Prepend (new UIElementNode (parent));
828 updated = true;
829 delete (node);
831 } else if (!size_list->IsEmpty ()) {
832 while (UIElementNode *node = (UIElementNode*)size_list->First ()) {
833 if (surface && (surface->needs_measure || surface->needs_arrange)) {
834 surface->needs_measure = surface->needs_arrange = false;
835 break;
838 size_list->Unlink (node);
839 FrameworkElement *fe = (FrameworkElement*) node->uielement;
841 updated = true;
842 Size *last = LayoutInformation::GetLastRenderSize (fe);
843 if (last) {
844 SizeChangedEventArgs *args = new SizeChangedEventArgs (*last, fe->GetRenderSize ());
845 fe->ClearValue (LayoutInformation::LastRenderSizeProperty, false);
846 fe->Emit (FrameworkElement::SizeChangedEvent, args);
848 delete (node);
850 } else if (!updated_list->IsEmpty ()) {
851 updated = false;
852 while (UIElementNode *node = (UIElementNode*)updated_list->First ()) {
853 updated_list->Unlink (node);
854 FrameworkElement *fe = (FrameworkElement*)node->uielement;
856 fe->Emit (LayoutUpdatedEvent);
857 delete (node);
859 break;
863 delete measure_list;
864 delete arrange_list;
865 delete updated_list;
866 delete size_list;
868 if (i >= MAX_LAYOUT_PASSES) {
869 LOG_LAYOUT ("\n************** UpdateLayout Bailing Out after %d Passes *******************\n", i);
870 } else {
871 LOG_LAYOUT (" (%d)\n", i);
875 void
876 FrameworkElement::RegisterManagedOverrides (MeasureOverrideCallback measure_cb, ArrangeOverrideCallback arrange_cb)
878 this->measure_cb = measure_cb;
879 this->arrange_cb = arrange_cb;
882 void
883 FrameworkElement::SetDefaultStyle (Style *style)
885 if (style) {
886 Application::GetCurrent()->ApplyStyle (this, style);
887 default_style_applied = true;
888 ((StylePropertyValueProvider*)providers[PropertyPrecedence_DefaultStyle])->SealStyle (style);