fixed the build
[moon.git] / src / frameworkelement.cpp
blob77a9c9fe1d3495ec98c704b867596b478681eb8d
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 measure_cb = NULL;
84 arrange_cb = NULL;
85 bounds_with_children = Rect ();
86 logical_parent = NULL;
88 providers[PropertyPrecedence_LocalStyle] = new StylePropertyValueProvider (this, PropertyPrecedence_LocalStyle);
89 providers[PropertyPrecedence_DefaultStyle] = new StylePropertyValueProvider (this, PropertyPrecedence_DefaultStyle);
90 providers[PropertyPrecedence_DynamicValue] = new FrameworkElementProvider (this, PropertyPrecedence_DynamicValue);
93 FrameworkElement::~FrameworkElement ()
97 void
98 FrameworkElement::RenderLayoutClip (cairo_t *cr)
100 Geometry *geom = LayoutInformation::GetClip (this);
102 if (!geom)
103 return;
105 geom->Draw (cr);
106 cairo_clip (cr);
108 geom->unref ();
111 Point
112 FrameworkElement::GetTransformOrigin ()
114 Point *user_xform_origin = GetRenderTransformOrigin ();
116 double width = GetActualWidth ();
117 double height = GetActualHeight ();
119 return Point (width * user_xform_origin->x,
120 height * user_xform_origin->y);
123 void
124 FrameworkElement::SetLogicalParent (DependencyObject *logical_parent, MoonError *error)
126 if (logical_parent && this->logical_parent && this->logical_parent != logical_parent) {
127 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Element is a child of another element");
128 return;
131 this->logical_parent = logical_parent;
134 void
135 FrameworkElement::ElementAdded (UIElement *item)
137 UIElement::ElementAdded (item);
139 //item->UpdateLayout ();
141 if (IsLayoutContainer () && item->Is (Type::FRAMEWORKELEMENT)) {
142 FrameworkElement *fe = (FrameworkElement *)item;
143 fe->SetActualWidth (0.0);
144 fe->SetActualHeight (0.0);
149 void
150 FrameworkElement::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
152 if (args->GetProperty ()->GetOwnerType() != Type::FRAMEWORKELEMENT) {
153 UIElement::OnPropertyChanged (args, error);
154 return;
157 if (args->GetId () == FrameworkElement::WidthProperty ||
158 args->GetId () == FrameworkElement::MaxWidthProperty ||
159 args->GetId () == FrameworkElement::MinWidthProperty ||
160 args->GetId () == FrameworkElement::MaxHeightProperty ||
161 args->GetId () == FrameworkElement::MinHeightProperty ||
162 args->GetId () == FrameworkElement::HeightProperty ||
163 args->GetId () == FrameworkElement::MarginProperty) {
165 Point *p = GetRenderTransformOrigin ();
167 /* normally we'd only update the bounds of this
168 element on a width/height change, but if the render
169 transform is someplace other than (0,0), the
170 transform needs to be updated as well. */
171 FullInvalidate (p->x != 0.0 || p->y != 0.0);
173 FrameworkElement *visual_parent = (FrameworkElement *)GetVisualParent ();
174 if (visual_parent) {
175 if (visual_parent->Is (Type::CANVAS)) {
176 if (!IsLayoutContainer ()) {
177 ClearValue (FrameworkElement::ActualHeightProperty);
178 ClearValue (FrameworkElement::ActualWidthProperty);
180 InvalidateMeasure ();
181 InvalidateArrange ();
182 } else {
183 visual_parent->InvalidateMeasure ();
184 InvalidateMeasure ();
185 InvalidateArrange ();
187 } else {
188 InvalidateMeasure ();
189 InvalidateArrange ();
191 UpdateBounds ();
193 else if (args->GetId () == FrameworkElement::StyleProperty) {
194 if (args->GetNewValue()) {
195 Style *s = args->GetNewValue()->AsStyle ();
196 if (s) {
197 // this has a side effect of calling
198 // ProviderValueChanged on all values
199 // in the style, so we might end up
200 // with lots of property notifications
201 // here (reentrancy ok?)
203 Application::GetCurrent()->ApplyStyle (this, s);
205 ((StylePropertyValueProvider*)providers[PropertyPrecedence_LocalStyle])->SealStyle (s);
209 else if (args->GetId () == FrameworkElement::HorizontalAlignmentProperty ||
210 args->GetId () == FrameworkElement::VerticalAlignmentProperty) {
211 InvalidateArrange ();
212 FullInvalidate (true);
215 NotifyListenersOfPropertyChange (args, error);
218 Size
219 FrameworkElement::ApplySizeConstraints (const Size &size)
221 Size specified (GetWidth (), GetHeight ());
222 Size constrained (GetMinWidth (), GetMinHeight ());
224 constrained = constrained.Max (size);
226 if (!isnan (specified.width))
227 constrained.width = specified.width;
229 if (!isnan (specified.height))
230 constrained.height = specified.height;
232 constrained = constrained.Min (GetMaxWidth (), GetMaxHeight ());
233 constrained = constrained.Max (GetMinWidth (), GetMinHeight ());
235 return constrained;
238 void
239 FrameworkElement::ComputeBounds ()
241 Size size (GetActualWidth (), GetActualHeight ());
242 size = ApplySizeConstraints (size);
244 extents = Rect (0, 0, size.width, size.height);
246 bounds = IntersectBoundsWithClipPath (extents, false).Transform (&absolute_xform);
247 bounds_with_children = bounds;
249 VisualTreeWalker walker = VisualTreeWalker (this);
250 while (UIElement *item = walker.Step ()) {
251 if (!item->GetRenderVisible ())
252 continue;
254 bounds_with_children = bounds_with_children.Union (item->GetSubtreeBounds ());
258 Rect
259 FrameworkElement::GetSubtreeBounds ()
261 VisualTreeWalker walker = VisualTreeWalker (this);
262 if (GetSubtreeObject () != NULL)
263 return bounds_with_children;
265 return bounds;
268 Size
269 FrameworkElement::ComputeActualSize ()
271 UIElement *parent = GetVisualParent ();
273 if ((parent && !parent->Is (Type::CANVAS)) || (!Is (Type::CANVAS) && IsLayoutContainer ()))
274 return GetDesiredSize ();
276 Size actual (0, 0);
278 actual = ApplySizeConstraints (actual);
280 return actual;
283 bool
284 FrameworkElement::InsideObject (cairo_t *cr, double x, double y)
286 double width = GetActualWidth ();
287 double height = GetActualHeight ();
288 double nx = x, ny = y;
290 TransformPoint (&nx, &ny);
291 if (nx < 0 || ny < 0 || nx > width || ny > height)
292 return false;
294 Geometry *layout_clip = LayoutInformation::GetLayoutClip (this);
295 if (layout_clip && !layout_clip->GetBounds ().PointInside (nx, ny))
296 return false;
298 return UIElement::InsideObject (cr, x, y);
301 void
302 FrameworkElement::HitTest (cairo_t *cr, Point p, List *uielement_list)
304 if (!GetRenderVisible ())
305 return;
307 if (!GetHitTestVisible ())
308 return;
310 // first a quick bounds check
311 if (!GetSubtreeBounds().PointInside (p.x, p.y))
312 return;
314 if (!InsideClip (cr, p.x, p.y))
315 return;
317 /* create our node and stick it on front */
318 List::Node *us = uielement_list->Prepend (new UIElementNode (this));
319 bool hit = false;
321 VisualTreeWalker walker = VisualTreeWalker (this, ZReverse);
322 while (UIElement *child = walker.Step ()) {
323 child->HitTest (cr, p, uielement_list);
325 if (us != uielement_list->First ()) {
326 hit = true;
327 break;
331 if (!hit && !InsideObject (cr, p.x, p.y))
332 uielement_list->Remove (us);
335 void
336 FrameworkElement::FindElementsInHostCoordinates (cairo_t *cr, Point host, List *uielement_list)
338 if (!GetRenderVisible ())
339 return;
341 if (!GetHitTestVisible ())
342 return;
344 if (bounds_with_children.height <= 0)
345 return;
347 cairo_save (cr);
348 cairo_new_path (cr);
350 if (GetClip ()) {
351 RenderClipPath (cr, true);
352 cairo_save (cr);
353 cairo_identity_matrix (cr);
354 bool res = cairo_in_fill (cr, host.x, host.y);
355 cairo_restore (cr);
356 if (!res) {
357 cairo_restore (cr);
358 return;
362 /* create our node and stick it on front */
363 List::Node *us = uielement_list->Prepend (new UIElementNode (this));
365 VisualTreeWalker walker = VisualTreeWalker (this, ZForward);
366 while (UIElement *child = walker.Step ())
367 child->FindElementsInHostCoordinates (cr, host, uielement_list);
369 if (us == uielement_list->First ()) {
370 cairo_new_path (cr);
371 Region all(extents);
372 cairo_set_matrix (cr, &absolute_xform);
373 Render (cr, &all, true);
374 cairo_identity_matrix (cr);
376 if (!CanFindElement () ||
377 !(cairo_in_fill (cr, host.x, host.y) || cairo_in_stroke (cr, host.x, host.y)))
378 uielement_list->Remove (us);
380 cairo_restore (cr);
383 // FIXME: This is not the fastest way of implementing this, decomposing the rectangle into
384 // a series of points is probably going to be quite slow. It's a good first effort.
385 void
386 FrameworkElement::FindElementsInHostCoordinates (cairo_t *cr, Rect r, List *uielement_list)
388 bool res = false;
389 if (!GetRenderVisible ())
390 return;
392 if (!GetHitTestVisible ())
393 return;
395 if (bounds_with_children.height <= 0)
396 return;
398 if (!bounds_with_children.IntersectsWith (r))
399 return;
401 cairo_save (cr);
402 cairo_new_path (cr);
404 if (GetClip ()) {
405 RenderClipPath (cr, true);
406 cairo_save (cr);
407 cairo_identity_matrix (cr);
409 for (int i=r.x; i < r.x + r.width && !res; i++)
410 for (int j=r.y; j < r.y + r.height && !res; j++)
411 res = cairo_in_fill (cr, i, j);
413 cairo_restore (cr);
414 if (!res) {
415 cairo_restore (cr);
416 return;
420 /* create our node and stick it on front */
421 List::Node *us = uielement_list->Prepend (new UIElementNode (this));
423 VisualTreeWalker walker = VisualTreeWalker (this, ZForward);
424 while (UIElement *child = walker.Step ())
425 child->FindElementsInHostCoordinates (cr, r, uielement_list);
427 if (us == uielement_list->First ()) {
428 cairo_new_path (cr);
429 Region all(extents);
430 cairo_set_matrix (cr, &absolute_xform);
431 Render (cr, &all, true);
432 cairo_identity_matrix (cr);
434 res = false;
435 if (CanFindElement ()) {
436 for (int i= r.x; i < (r.x + r.width) && !res; i++)
437 for (int j= r.y; j < (r.y + r.height) && !res; j++)
438 res = cairo_in_fill (cr, i, j) || cairo_in_stroke (cr, i, j);
441 if (!res)
442 uielement_list->Remove (us);
444 cairo_restore (cr);
447 void
448 FrameworkElement::GetSizeForBrush (cairo_t *cr, double *width, double *height)
450 *width = GetActualWidth ();
451 *height = GetActualHeight ();
454 void
455 FrameworkElement::Measure (Size availableSize)
457 //LOG_LAYOUT ("measuring %p %s %g,%g\n", this, GetTypeName (), availableSize.width, availableSize.height);
458 if (Is(Type::CONTROL)) {
459 Control *control = (Control*)this;
460 control->ApplyTemplate();
463 if (!IsLayoutContainer ()) {
464 UIElement *parent = GetVisualParent ();
466 if (!parent || parent->Is (Type::CANVAS)) {
467 InvalidateArrange ();
468 UpdateBounds ();
469 dirty_flags &= ~DirtyMeasure;
470 return;
474 Size *last = LayoutInformation::GetPreviousConstraint (this);
475 bool domeasure = (this->dirty_flags & DirtyMeasure) > 0;
477 domeasure |= !last || last->width != availableSize.width || last->height != availableSize.height;
479 if (GetVisibility () == VisibilityCollapsed) {
480 SetDesiredSize (Size (0,0));
481 return;
484 if (!domeasure)
485 return;
487 LayoutInformation::SetPreviousConstraint (this, &availableSize);
489 InvalidateArrange ();
490 UpdateBounds ();
492 dirty_flags &= ~DirtyMeasure;
494 Thickness margin = *GetMargin ();
495 Size size = availableSize.GrowBy (-margin);
497 size = ApplySizeConstraints (size);
499 if (measure_cb)
500 size = (*measure_cb)(size);
501 else
502 size = MeasureOverride (size);
504 // postcondition the results
505 size = ApplySizeConstraints (size);
507 size = size.GrowBy (margin);
508 size = size.Min (availableSize);
510 if (GetUseLayoutRounding ()) {
511 size.width = floor (size.width);
512 size.height = floor (size.height);
515 SetDesiredSize (size);
518 Size
519 FrameworkElement::MeasureOverride (Size availableSize)
521 Size desired = Size (0,0);
523 if (!IsLayoutContainer ())
524 return desired;
526 availableSize = ApplySizeConstraints (availableSize);
528 VisualTreeWalker walker = VisualTreeWalker (this);
529 while (UIElement *child = walker.Step ()) {
530 if (child->GetVisibility () != VisibilityVisible)
531 continue;
533 child->Measure (availableSize);
534 desired = child->GetDesiredSize ();
537 desired = ApplySizeConstraints (desired);
539 return desired;
543 // not sure about the disconnect between these two methods.. I would
544 // imagine both should take Rects and ArrangeOverride would return a
545 // rectangle as well..
546 void
547 FrameworkElement::Arrange (Rect finalRect)
549 //LOG_LAYOUT ("arranging %p %s %g,%g,%g,%g\n", this, GetTypeName (), finalRect.x, finalRect.y, finalRect.width, finalRect.height);
550 Rect *slot = LayoutInformation::GetLayoutSlot (this);
551 bool doarrange = this->dirty_flags & DirtyArrange;
553 doarrange |= slot ? *slot != finalRect : true;
555 if (finalRect.width < 0 || finalRect.height < 0
556 || isinf (finalRect.width) || isinf (finalRect.height)
557 || isnan (finalRect.width) || isnan (finalRect.height)) {
558 Size desired = GetDesiredSize ();
559 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);
560 return;
563 if (GetVisibility () == VisibilityCollapsed) {
564 SetRenderSize (Size(0,0));
565 return;
568 if (!doarrange)
569 return;
572 * FIXME I'm not happy with doing this here but until I come
573 * up with a better plan make sure that layout elements have
574 * been measured at least once
576 if (IsContainer () && !LayoutInformation::GetPreviousConstraint (this))
577 Measure (Size (finalRect.width, finalRect.height));
579 LayoutInformation::SetLayoutSlot (this, &finalRect);
580 ClearValue (LayoutInformation::LayoutClipProperty);
581 //LayoutInformation::SetLayoutClip (this, NULL);
583 this->dirty_flags &= ~DirtyArrange;
585 Thickness margin = *GetMargin ();
586 Rect child_rect = finalRect.GrowBy (-margin);
588 cairo_matrix_init_translate (&layout_xform, child_rect.x, child_rect.y);
589 UpdateTransform ();
590 UpdateBounds ();
591 this->dirty_flags &= ~DirtyArrange;
593 Size offer (child_rect.width, child_rect.height);
594 Size response;
595 Size desired = GetDesiredSize ().GrowBy (-margin);
597 HorizontalAlignment horiz = GetHorizontalAlignment ();
598 VerticalAlignment vert = GetVerticalAlignment ();
600 if (horiz != HorizontalAlignmentStretch)
601 offer.width = MIN (offer.width, desired.width);
603 if (vert != VerticalAlignmentStretch)
604 offer.height = MIN (offer.height, desired.height);
606 offer = ApplySizeConstraints (offer);
608 if (arrange_cb)
609 response = (*arrange_cb)(offer);
610 else
611 response = ArrangeOverride (offer);
613 /* XXX FIXME horrible hack */
614 UIElement *parent = GetVisualParent ();
615 bool in_layout = IsLayoutContainer ();
617 if (!in_layout) {
618 if (!parent || parent->Is (Type::CANVAS))
619 return;
621 Size old_size = GetRenderSize ();
622 //Point *old_offset = LayoutInformation::GetVisualOffset (this);
623 ClearValue (LayoutInformation::VisualOffsetProperty);
625 if (in_layout && GetUseLayoutRounding ()) {
626 response.width = floor (response.width);
627 response.height = floor (response.height);
630 SetActualWidth (response.width);
631 SetActualHeight (response.height);
633 response = ApplySizeConstraints (response);
634 Point visual_offset (child_rect.x, child_rect.y);
636 if (GetVisualParent ()) {
637 switch (horiz) {
638 case HorizontalAlignmentLeft:
639 break;
640 case HorizontalAlignmentRight:
641 visual_offset.x += child_rect.width - response.width;
642 break;
643 case HorizontalAlignmentCenter:
644 visual_offset.x += (child_rect.width - response.width) * .5;
645 break;
646 default:
647 visual_offset.x += MAX ((child_rect.width - response.width) * .5, 0);
648 break;
651 switch (vert) {
652 case VerticalAlignmentTop:
653 break;
654 case VerticalAlignmentBottom:
655 visual_offset.y += child_rect.height - response.height;
656 break;
657 case VerticalAlignmentCenter:
658 visual_offset.y += (child_rect.height - response.height) * .5;
659 break;
660 default:
661 visual_offset.y += MAX ((child_rect.height - response.height) * .5, 0);
663 break;
667 cairo_matrix_init_translate (&layout_xform, visual_offset.x, visual_offset.y);
668 LayoutInformation::SetVisualOffset (this, &visual_offset);
669 SetRenderSize (response);
671 Rect layout_clip = finalRect;
672 layout_clip.x -= visual_offset.x;
673 layout_clip.y -= visual_offset.y;
675 layout_clip = layout_clip.GrowBy (-margin);
676 RectangleGeometry *rectangle = new RectangleGeometry ();
677 rectangle->SetRect (&layout_clip);
678 LayoutInformation::SetLayoutClip (this, rectangle);
679 rectangle->unref ();
681 if (old_size != response) { // || (old_offset && *old_offset != visual_offset)) {
682 if (!LayoutInformation::GetLastRenderSize (this))
683 LayoutInformation::SetLastRenderSize (this, &old_size);
685 // XXX what do we do with finalRect.x and y?
686 //printf ("\u231a");
689 Size
690 FrameworkElement::ArrangeOverride (Size finalSize)
692 finalSize = ApplySizeConstraints (finalSize);
694 if (!IsLayoutContainer ())
695 return finalSize;
697 Size arranged = finalSize;
699 VisualTreeWalker walker = VisualTreeWalker (this);
700 while (UIElement *child = walker.Step ()) {
701 if (child->GetVisibility () != VisibilityVisible)
702 continue;
704 Rect childRect (0,0,finalSize.width,finalSize.height);
706 child->Arrange (childRect);
707 arranged = child->GetRenderSize ();
709 arranged = arranged.Max (finalSize);
712 arranged = arranged.Max (finalSize);
714 return arranged;
717 void
718 FrameworkElement::UpdateLayout ()
720 UIElement *element = this;
721 UIElement *parent = NULL;
723 // Seek to the top
724 while ((parent = element->GetVisualParent ())) {
725 if (parent->Is (Type::CANVAS))
726 break;
728 element = parent;
731 Surface *surface = element->GetSurface ();
733 LOG_LAYOUT ("\nFrameworkElement::UpdateLayout: ");
734 List *measure_list = new List ();
735 List *arrange_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 size_list->Clear (true);
746 i++;
747 DeepTreeWalker measure_walker (element);
748 while (FrameworkElement *child = (FrameworkElement*)measure_walker.Step ()) {
749 FrameworkElement *parent = (FrameworkElement*)child->GetVisualParent ();
751 if (parent && parent->IsLoaded () && !child->IsLoaded ()) {
752 LOG_LAYOUT ("FrameworkElement::UpdateLayout: element (%p) not yet loaded\n", child);
754 List *load_list = child->WalkTreeForLoaded (false);
755 child->EmitSubtreeLoad (load_list);
756 delete load_list;
759 if ((child->flags & UIElement::RENDER_VISIBLE) == 0) {
760 measure_walker.SkipBranch ();
761 continue;
764 if (child->dirty_flags & DirtyMeasure) {
765 UIElement *parent = child->GetVisualParent ();
766 if ((parent && !parent->Is (Type::CANVAS)) || child->IsContainer ()) {
767 measure_list->Append (new UIElementNode (child));
768 //g_warning ("adding %p, %s", child, child->GetTypeName ());
769 } else if (!measure_list->IsEmpty ()) {
770 measure_walker.SkipBranch ();
774 if (!measure_list->IsEmpty ())
775 continue;
777 if (child->dirty_flags & DirtyArrange)
778 arrange_list->Append (new UIElementNode (child));
780 if (!arrange_list->IsEmpty ())
781 continue;
783 if (child->ReadLocalValue (LayoutInformation::LastRenderSizeProperty))
784 size_list->Append (new UIElementNode (child));
786 if (!size_list->IsEmpty ())
787 continue;
790 if (!measure_list->IsEmpty ()) {
791 if (surface)
792 surface->needs_measure = false;
793 while (UIElementNode* node = (UIElementNode*)measure_list->First ()) {
794 measure_list->Unlink (node);
796 node->uielement->DoMeasure ();
797 //if (node->uielement->GetVisuaParent ()->dirty_flags & dirty_measure)
798 // node->Prepend (new UIElementNode (parent));
800 updated = true;
801 delete (node);
803 } else if (!arrange_list->IsEmpty ()) {
804 if (surface)
805 surface->needs_arrange = false;
806 while (UIElementNode *node = (UIElementNode*)arrange_list->First ()) {
807 arrange_list->Unlink (node);
809 if (surface && surface->needs_measure) {
810 delete (node);
811 break;
814 node->uielement->DoArrange ();
815 //if (node->uielement->GetVisuaParent ()->dirty_flags & dirty_arrange)
816 // node->Prepend (new UIElementNode (parent));
818 updated = true;
819 delete (node);
821 } else if (!size_list->IsEmpty ()) {
822 while (UIElementNode *node = (UIElementNode*)size_list->First ()) {
823 if (surface && (surface->needs_measure || surface->needs_arrange)) {
824 surface->needs_measure = surface->needs_arrange = false;
825 break;
828 size_list->Unlink (node);
829 FrameworkElement *fe = (FrameworkElement*) node->uielement;
831 updated = true;
832 Size *last = LayoutInformation::GetLastRenderSize (fe);
833 if (last) {
834 SizeChangedEventArgs *args = new SizeChangedEventArgs (*last, fe->GetRenderSize ());
835 fe->ClearValue (LayoutInformation::LastRenderSizeProperty, false);
836 fe->Emit (FrameworkElement::SizeChangedEvent, args);
838 delete (node);
840 } else if (updated) {
841 Deployment::GetCurrent()->LayoutUpdated ();
842 break;
846 delete measure_list;
847 delete arrange_list;
848 delete size_list;
850 if (i >= MAX_LAYOUT_PASSES) {
851 LOG_LAYOUT ("\n************** UpdateLayout Bailing Out after %d Passes *******************\n", i);
852 } else {
853 LOG_LAYOUT (" (%d)\n", i);
857 void
858 FrameworkElement::RegisterManagedOverrides (MeasureOverrideCallback measure_cb, ArrangeOverrideCallback arrange_cb)
860 this->measure_cb = measure_cb;
861 this->arrange_cb = arrange_cb;
864 void
865 FrameworkElement::SetDefaultStyle (Style *style)
867 if (style) {
868 Application::GetCurrent()->ApplyStyle (this, style);
869 default_style_applied = true;
870 ((StylePropertyValueProvider*)providers[PropertyPrecedence_DefaultStyle])->SealStyle (style);