1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * frameworkelement.cpp:
5 * Copyright 2007 Novell, Inc. (http://www.novell.com)
7 * See the LICENSE file included with the distribution for details.
17 #include "application.h"
18 #include "deployment.h"
20 #include "namescope.h"
21 #include "frameworkelement.h"
23 #include "thickness.h"
24 #include "collection.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
;
44 FrameworkElement::Dispose ()
46 if (default_template
!= NULL
) {
47 default_template
->SetParent (NULL
, NULL
);
48 default_template
= NULL
;
50 UIElement::Dispose ();
54 FrameworkElementProvider::GetPropertyValue (DependencyProperty
*property
)
56 if (property
->GetId () != FrameworkElement::ActualHeightProperty
&&
57 property
->GetId () != FrameworkElement::ActualWidthProperty
)
60 FrameworkElement
*element
= (FrameworkElement
*) obj
;
62 Size actual
= element
->ComputeActualSize ();
67 if (actual_height_value
)
68 delete actual_height_value
;
70 if (actual_width_value
)
71 delete actual_width_value
;
73 actual_height_value
= new Value (actual
.height
);
74 actual_width_value
= new Value (actual
.width
);
77 if (property
->GetId () == FrameworkElement::ActualHeightProperty
) {
78 return actual_height_value
;
80 return actual_width_value
;
84 FrameworkElement::FrameworkElement ()
86 SetObjectType (Type::FRAMEWORKELEMENT
);
88 default_template
= NULL
;
89 default_style_applied
= false;
90 get_default_template_cb
= NULL
;
94 bounds_with_children
= Rect ();
95 logical_parent
= NULL
;
97 providers
[PropertyPrecedence_LocalStyle
] = new StylePropertyValueProvider (this, PropertyPrecedence_LocalStyle
);
98 providers
[PropertyPrecedence_DefaultStyle
] = new StylePropertyValueProvider (this, PropertyPrecedence_DefaultStyle
);
99 providers
[PropertyPrecedence_DynamicValue
] = new FrameworkElementProvider (this, PropertyPrecedence_DynamicValue
);
102 FrameworkElement::~FrameworkElement ()
107 FrameworkElement::RenderLayoutClip (cairo_t
*cr
)
109 FrameworkElement
*element
= this;
110 cairo_matrix_t xform
;
112 /* store off the current transform since the following loop is about the blow it away */
113 cairo_get_matrix (cr
, &xform
);
116 Geometry
*geom
= LayoutInformation::GetLayoutClip (element
);
123 // translate by the negative visual offset of the
124 // element to get the parent's coordinate space.
125 Point
*visual_offset
= LayoutInformation::GetVisualOffset (element
);
127 cairo_translate (cr
, -visual_offset
->x
, -visual_offset
->y
);
129 element
= (FrameworkElement
*)element
->GetVisualParent ();
132 /* restore the transform after we're done clipping */
133 cairo_set_matrix (cr
, &xform
);
137 FrameworkElement::GetTransformOrigin ()
139 Point
*user_xform_origin
= GetRenderTransformOrigin ();
141 double width
= GetActualWidth ();
142 double height
= GetActualHeight ();
144 return Point (width
* user_xform_origin
->x
,
145 height
* user_xform_origin
->y
);
149 FrameworkElement::SetLogicalParent (DependencyObject
*logical_parent
, MoonError
*error
)
151 if (logical_parent
&& this->logical_parent
&& this->logical_parent
!= logical_parent
) {
152 MoonError::FillIn (error
, MoonError::INVALID_OPERATION
, "Element is a child of another element");
156 this->logical_parent
= logical_parent
;
160 FrameworkElement::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
162 if (args
->GetProperty ()->GetOwnerType() != Type::FRAMEWORKELEMENT
) {
163 UIElement::OnPropertyChanged (args
, error
);
167 if (args
->GetId () == FrameworkElement::WidthProperty
||
168 args
->GetId () == FrameworkElement::MaxWidthProperty
||
169 args
->GetId () == FrameworkElement::MinWidthProperty
||
170 args
->GetId () == FrameworkElement::MaxHeightProperty
||
171 args
->GetId () == FrameworkElement::MinHeightProperty
||
172 args
->GetId () == FrameworkElement::HeightProperty
||
173 args
->GetId () == FrameworkElement::MarginProperty
) {
175 Point
*p
= GetRenderTransformOrigin ();
177 /* normally we'd only update the bounds of this
178 element on a width/height change, but if the render
179 transform is someplace other than (0,0), the
180 transform needs to be updated as well. */
181 FullInvalidate (p
->x
!= 0.0 || p
->y
!= 0.0);
183 FrameworkElement
*visual_parent
= (FrameworkElement
*)GetVisualParent ();
185 visual_parent
->InvalidateMeasure ();
188 InvalidateMeasure ();
189 InvalidateArrange ();
192 else if (args
->GetId () == FrameworkElement::StyleProperty
) {
193 if (args
->GetNewValue()) {
194 Style
*s
= args
->GetNewValue()->AsStyle ();
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
);
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 if (GetUseLayoutRounding ()) {
235 constrained
.width
= round (constrained
.width
);
236 constrained
.height
= round (constrained
.height
);
242 FrameworkElement::ComputeBounds ()
244 Size
size (GetActualWidth (), GetActualHeight ());
245 size
= ApplySizeConstraints (size
);
247 extents
= Rect (0, 0, size
.width
, size
.height
);
249 bounds
= IntersectBoundsWithClipPath (extents
, false).Transform (&absolute_xform
);
250 bounds_with_children
= bounds
;
252 VisualTreeWalker walker
= VisualTreeWalker (this);
253 while (UIElement
*item
= walker
.Step ()) {
254 if (!item
->GetRenderVisible ())
257 bounds_with_children
= bounds_with_children
.Union (item
->GetSubtreeBounds ());
262 FrameworkElement::GetSubtreeBounds ()
264 VisualTreeWalker walker
= VisualTreeWalker (this);
265 if (GetSubtreeObject () != NULL
)
266 return bounds_with_children
;
272 FrameworkElement::ComputeActualSize ()
274 UIElement
*parent
= GetVisualParent ();
276 if (GetVisibility () != VisibilityVisible
)
277 return Size (0.0, 0.0);
279 if ((parent
&& !parent
->Is (Type::CANVAS
)) || (IsLayoutContainer ()))
280 return GetRenderSize ();
284 actual
= ApplySizeConstraints (actual
);
290 FrameworkElement::InsideLayoutClip (double x
, double y
)
292 Geometry
*layout_clip
= LayoutInformation::GetClip (this);
298 TransformPoint (&x
, &y
);
299 inside
= layout_clip
->GetBounds ().PointInside (x
, y
);
300 layout_clip
->unref ();
306 FrameworkElement::InsideObject (cairo_t
*cr
, double x
, double y
)
308 Size
framework (GetActualWidth (), GetActualHeight ());
309 double nx
= x
, ny
= y
;
311 TransformPoint (&nx
, &ny
);
312 if (nx
< 0 || ny
< 0 || nx
> framework
.width
|| ny
> framework
.height
)
315 if (!InsideLayoutClip (x
, y
))
318 return UIElement::InsideObject (cr
, x
, y
);
322 FrameworkElement::HitTest (cairo_t
*cr
, Point p
, List
*uielement_list
)
324 if (!GetRenderVisible ())
327 if (!GetHitTestVisible ())
330 // first a quick bounds check
331 if (!GetSubtreeBounds().PointInside (p
.x
, p
.y
))
334 /* the clip property is global so we can short out here */
335 if (!InsideClip (cr
, p
.x
, p
.y
))
338 /* create our node and stick it on front */
339 List::Node
*us
= uielement_list
->Prepend (new UIElementNode (this));
342 VisualTreeWalker walker
= VisualTreeWalker (this, ZReverse
);
343 while (UIElement
*child
= walker
.Step ()) {
344 child
->HitTest (cr
, p
, uielement_list
);
346 if (us
!= uielement_list
->First ()) {
352 if (!hit
&& !InsideObject (cr
, p
.x
, p
.y
))
353 uielement_list
->Remove (us
);
357 FrameworkElement::FindElementsInHostCoordinates (cairo_t
*cr
, Point host
, List
*uielement_list
)
359 if (GetVisibility () != VisibilityVisible
)
362 if (!GetHitTestVisible ())
365 if (bounds_with_children
.height
<= 0)
368 /* the clip property is global so we can short out here */
369 if (!InsideClip (cr
, host
.x
, host
.y
))
374 /* create our node and stick it on front */
375 List::Node
*us
= uielement_list
->Prepend (new UIElementNode (this));
377 VisualTreeWalker walker
= VisualTreeWalker (this, ZForward
);
378 while (UIElement
*child
= walker
.Step ())
379 child
->FindElementsInHostCoordinates (cr
, host
, uielement_list
);
381 if (us
== uielement_list
->First ()) {
383 cairo_identity_matrix (cr
);
385 if (!CanFindElement () || !InsideObject (cr
, host
.x
, host
.y
))
386 uielement_list
->Remove (us
);
391 // FIXME: This is not the fastest way of implementing this, decomposing the rectangle into
392 // a series of points is probably going to be quite slow. It's a good first effort.
394 FrameworkElement::FindElementsInHostCoordinates (cairo_t
*cr
, Rect r
, List
*uielement_list
)
397 if (GetVisibility () != VisibilityVisible
)
400 if (!GetHitTestVisible ())
403 if (bounds_with_children
.height
<= 0)
406 if (!bounds_with_children
.IntersectsWith (r
))
412 Geometry
*clip
= GetClip ();
414 if (!r
.IntersectsWith (clip
->GetBounds ().Transform (&absolute_xform
)))
416 r
= r
.Intersection (clip
->GetBounds ().Transform (&absolute_xform
));
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 ()) {
428 cairo_identity_matrix (cr
);
431 if (CanFindElement ()) {
432 res
= bounds
.Intersection (r
) == bounds
;
434 for (int i
= r
.x
; i
< (r
.x
+ r
.width
) && !res
; i
++)
435 for (int j
= r
.y
; j
< (r
.y
+ r
.height
) && !res
; j
++)
436 res
= InsideObject (cr
, i
, j
);
440 uielement_list
->Remove (us
);
446 FrameworkElement::GetSizeForBrush (cairo_t
*cr
, double *width
, double *height
)
448 *width
= GetActualWidth ();
449 *height
= GetActualHeight ();
453 FrameworkElement::Measure (Size availableSize
)
455 //LOG_LAYOUT ("measuring %p %s %g,%g\n", this, GetTypeName (), availableSize.width, availableSize.height);
457 Size
*last
= LayoutInformation::GetPreviousConstraint (this);
458 bool domeasure
= (this->dirty_flags
& DirtyMeasure
) > 0;
460 domeasure
|= !last
|| last
->width
!= availableSize
.width
|| last
->height
!= availableSize
.height
;
462 if (GetVisibility () != VisibilityVisible
) {
463 LayoutInformation::SetPreviousConstraint (this, &availableSize
);
464 SetDesiredSize (Size (0,0));
470 UIElement
*parent
= GetVisualParent ();
471 /* unit tests show a short circuit in this case */
473 if (!parent && !IsContainer () && (!GetSurface () || (GetSurface () && !GetSurface ()->IsTopLevel (this)))) {
474 SetDesiredSize (Size (0,0));
482 LayoutInformation::SetPreviousConstraint (this, &availableSize
);
484 InvalidateArrange ();
487 dirty_flags
&= ~DirtyMeasure
;
489 Thickness margin
= *GetMargin ();
490 Size size
= availableSize
.GrowBy (-margin
);
492 size
= ApplySizeConstraints (size
);
495 size
= (*measure_cb
)(size
);
497 size
= MeasureOverride (size
);
499 hidden_desire
= size
;
501 if (!parent
|| parent
->Is (Type::CANVAS
)) {
502 if (Is (Type::CANVAS
) || !IsLayoutContainer ()) {
503 SetDesiredSize (Size (0,0));
508 // postcondition the results
509 size
= ApplySizeConstraints (size
);
511 size
= size
.GrowBy (margin
);
512 size
= size
.Min (availableSize
);
514 if (GetUseLayoutRounding ()) {
515 size
.width
= round (size
.width
);
516 size
.height
= round (size
.height
);
519 SetDesiredSize (size
);
523 FrameworkElement::MeasureOverride (Size availableSize
)
525 Size desired
= Size (0,0);
527 availableSize
= availableSize
.Max (desired
);
529 VisualTreeWalker walker
= VisualTreeWalker (this);
530 while (UIElement
*child
= walker
.Step ()) {
531 child
->Measure (availableSize
);
532 desired
= child
->GetDesiredSize ();
535 return desired
.Min (availableSize
);
539 // not sure about the disconnect between these two methods.. I would
540 // imagine both should take Rects and ArrangeOverride would return a
541 // rectangle as well..
543 FrameworkElement::Arrange (Rect finalRect
)
545 //LOG_LAYOUT ("arranging %p %s %g,%g,%g,%g\n", this, GetTypeName (), finalRect.x, finalRect.y, finalRect.width, finalRect.height);
546 Rect
*slot
= LayoutInformation::GetLayoutSlot (this);
547 bool doarrange
= this->dirty_flags
& DirtyArrange
;
549 if (GetUseLayoutRounding ()) {
551 rounded
.x
= round (finalRect
.x
);
552 rounded
.y
= round (finalRect
.y
);
553 //rounded.width = MAX (round ((finalRect.x + finalRect.width) - rounded.x), 0);
554 //rounded.height = MAX (round ((finalRect.y + finalRect.height) - rounded.y), 0);
555 rounded
.width
= round (finalRect
.width
);
556 rounded
.height
= round (finalRect
.height
);
560 doarrange
|= slot
? *slot
!= finalRect
: true;
562 if (finalRect
.width
< 0 || finalRect
.height
< 0
563 || isinf (finalRect
.width
) || isinf (finalRect
.height
)
564 || isnan (finalRect
.width
) || isnan (finalRect
.height
)) {
565 Size desired
= GetDesiredSize ();
566 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
);
570 UIElement
*parent
= GetVisualParent ();
571 /* unit tests show a short circuit in this case */
573 if (!parent && !IsContainer () && (!GetSurface () || (GetSurface () && !GetSurface ()->IsTopLevel (this)))) {
577 if (GetVisibility () != VisibilityVisible
) {
578 LayoutInformation::SetLayoutSlot (this, &finalRect
);
586 * FIXME I'm not happy with doing this here but until I come
587 * up with a better plan make sure that layout elements have
588 * been measured at least once
590 Size
*measure
= LayoutInformation::GetPreviousConstraint (this);
591 if (IsContainer () && !measure
)
592 Measure (Size (finalRect
.width
, finalRect
.height
));
593 measure
= LayoutInformation::GetPreviousConstraint (this);
595 ClearValue (LayoutInformation::LayoutClipProperty
);
597 this->dirty_flags
&= ~DirtyArrange
;
599 Thickness margin
= *GetMargin ();
600 Rect child_rect
= finalRect
.GrowBy (-margin
);
602 cairo_matrix_init_translate (&layout_xform
, child_rect
.x
, child_rect
.y
);
605 this->dirty_flags
&= ~DirtyArrange
;
607 Size offer
= hidden_desire
;
610 Size stretched
= ApplySizeConstraints (Size (child_rect
.width
, child_rect
.height
));
611 Size framework
= ApplySizeConstraints (Size ());
613 HorizontalAlignment horiz
= GetHorizontalAlignment ();
614 VerticalAlignment vert
= GetVerticalAlignment ();
616 if (horiz
== HorizontalAlignmentStretch
)
617 framework
.width
= MAX (framework
.width
, stretched
.width
);
619 if (vert
== VerticalAlignmentStretch
)
620 framework
.height
= MAX (framework
.height
, stretched
.height
);
622 offer
= offer
.Max (framework
);
624 LayoutInformation::SetLayoutSlot (this, &finalRect
);
627 response
= (*arrange_cb
)(offer
);
629 response
= ArrangeOverride (offer
);
631 Point
visual_offset (child_rect
.x
, child_rect
.y
);
632 LayoutInformation::SetVisualOffset (this, &visual_offset
);
634 Size old_size
= GetRenderSize ();
636 if (GetUseLayoutRounding ()) {
637 response
.width
= round (response
.width
);
638 response
.height
= round (response
.height
);
641 SetRenderSize (response
);
643 if (!parent
|| parent
->Is (Type::CANVAS
)) {
644 if (!IsLayoutContainer ()) {
645 SetRenderSize (Size (0,0));
650 Size constrainedResponse
= response
.Min (ApplySizeConstraints (response
));
652 /* it doesn't appear we apply aligment or layout clipping to toplevel elements */
653 bool toplevel
= IsAttached () && GetDeployment ()->GetSurface ()->IsTopLevel (this);
657 case HorizontalAlignmentLeft
:
659 case HorizontalAlignmentRight
:
660 visual_offset
.x
+= child_rect
.width
- constrainedResponse
.width
;
662 case HorizontalAlignmentCenter
:
663 visual_offset
.x
+= (child_rect
.width
- constrainedResponse
.width
) * .5;
666 visual_offset
.x
+= MAX ((child_rect
.width
- constrainedResponse
.width
) * .5, 0);
671 case VerticalAlignmentTop
:
673 case VerticalAlignmentBottom
:
674 visual_offset
.y
+= child_rect
.height
- constrainedResponse
.height
;
676 case VerticalAlignmentCenter
:
677 visual_offset
.y
+= (child_rect
.height
- constrainedResponse
.height
) * .5;
680 visual_offset
.y
+= MAX ((child_rect
.height
- constrainedResponse
.height
) * .5, 0);
686 cairo_matrix_init_translate (&layout_xform
, visual_offset
.x
, visual_offset
.y
);
687 LayoutInformation::SetVisualOffset (this, &visual_offset
);
689 Rect
element (0, 0, response
.width
, response
.height
);
690 Rect layout_clip
= child_rect
;
691 layout_clip
.x
= MAX (child_rect
.x
- visual_offset
.x
, 0);
692 layout_clip
.y
= MAX (child_rect
.y
- visual_offset
.y
, 0);
693 if (GetUseLayoutRounding ()) {
694 layout_clip
.x
= round (layout_clip
.x
);
695 layout_clip
.y
= round (layout_clip
.y
);
698 if (((!toplevel
&& element
!= element
.Intersection (layout_clip
)) || constrainedResponse
!= response
) && !Is (Type::CANVAS
) && ((parent
&& !parent
->Is (Type::CANVAS
)) || IsContainer ())) {
699 Size framework_clip
= ApplySizeConstraints (Size (INFINITY
, INFINITY
));
700 layout_clip
= layout_clip
.Intersection (Rect (0, 0, framework_clip
.width
, framework_clip
.height
));
701 RectangleGeometry
*rectangle
= new RectangleGeometry ();
702 rectangle
->SetRect (&layout_clip
);
703 LayoutInformation::SetLayoutClip (this, rectangle
);
707 if (old_size
!= response
) { // || (old_offset && *old_offset != visual_offset)) {
708 if (!LayoutInformation::GetLastRenderSize (this)) {
709 LayoutInformation::SetLastRenderSize (this, &old_size
);
710 PropagateFlagUp (DIRTY_SIZE_HINT
);
716 FrameworkElement::ArrangeOverride (Size finalSize
)
718 Size arranged
= finalSize
;
720 VisualTreeWalker walker
= VisualTreeWalker (this);
721 while (UIElement
*child
= walker
.Step ()) {
722 Rect
childRect (0,0,finalSize
.width
,finalSize
.height
);
724 child
->Arrange (childRect
);
725 arranged
= arranged
.Max (finalSize
);
732 FrameworkElement::UpdateLayout ()
734 UIElement
*element
= this;
735 UIElement
*parent
= NULL
;
738 while ((parent
= element
->GetVisualParent ())) {
742 LOG_LAYOUT ("\nFrameworkElement::UpdateLayout: ");
743 List
*measure_list
= new List ();
744 List
*arrange_list
= new List ();
745 List
*size_list
= new List ();
746 bool updated
= false;
748 while (i
< MAX_LAYOUT_PASSES
) {
749 LOG_LAYOUT ("\u267c");
751 // If we abort the arrange phase because InvalidateMeasure was called or if
752 // we abort the size phase because InvalidateMeasure/InvalidateArrange
753 // was called, we need to put the hint flags back otherwise we'll skip that
754 // branch during the next pass.
755 while (UIElementNode
*node
= (UIElementNode
*)arrange_list
->First ()) {
756 node
->uielement
->PropagateFlagUp (DIRTY_ARRANGE_HINT
);
757 arrange_list
->Remove (node
);
759 while (UIElementNode
*node
= (UIElementNode
*)size_list
->First ()) {
760 node
->uielement
->PropagateFlagUp (DIRTY_SIZE_HINT
);
761 size_list
->Remove (node
);
765 // Figure out which type of elements we should be selected - dirty measure, arrange or size
766 UIElementFlags flag
= NONE
;
767 if (element
->HasFlag (DIRTY_MEASURE_HINT
))
768 flag
= DIRTY_MEASURE_HINT
;
769 else if (element
->HasFlag (DIRTY_ARRANGE_HINT
))
770 flag
= DIRTY_ARRANGE_HINT
;
771 else if (element
->HasFlag (DIRTY_SIZE_HINT
))
772 flag
= DIRTY_SIZE_HINT
;
775 DeepTreeWalker
measure_walker (element
);
776 while (FrameworkElement
*child
= (FrameworkElement
*)measure_walker
.Step ()) {
777 if (child
->GetVisibility () != VisibilityVisible
|| !child
->HasFlag (flag
)) {
778 measure_walker
.SkipBranch ();
782 child
->ClearFlag (flag
);
784 case DIRTY_MEASURE_HINT
:
785 if (child
->dirty_flags
& DirtyMeasure
)
786 measure_list
->Append (new UIElementNode (child
));
788 case DIRTY_ARRANGE_HINT
:
789 if (child
->dirty_flags
& DirtyArrange
)
790 arrange_list
->Append (new UIElementNode (child
));
792 case DIRTY_SIZE_HINT
:
793 if (child
->ReadLocalValue (LayoutInformation::LastRenderSizeProperty
))
794 size_list
->Append (new UIElementNode (child
));
802 if (flag
== DIRTY_MEASURE_HINT
) {
803 while (UIElementNode
* node
= (UIElementNode
*)measure_list
->First ()) {
804 measure_list
->Unlink (node
);
806 node
->uielement
->DoMeasure ();
811 } else if (flag
== DIRTY_ARRANGE_HINT
) {
812 while (UIElementNode
*node
= (UIElementNode
*)arrange_list
->First ()) {
813 arrange_list
->Unlink (node
);
815 node
->uielement
->DoArrange ();
819 if (element
->HasFlag (DIRTY_MEASURE_HINT
))
822 } else if (flag
== DIRTY_SIZE_HINT
) {
823 while (UIElementNode
*node
= (UIElementNode
*)size_list
->First ()) {
824 if (element
->HasFlag (DIRTY_MEASURE_HINT
) ||
825 element
->HasFlag (DIRTY_ARRANGE_HINT
)) {
829 size_list
->Unlink (node
);
830 FrameworkElement
*fe
= (FrameworkElement
*) node
->uielement
;
833 Size
*last
= LayoutInformation::GetLastRenderSize (fe
);
835 SizeChangedEventArgs
*args
= new SizeChangedEventArgs (*last
, fe
->GetRenderSize ());
836 fe
->ClearValue (LayoutInformation::LastRenderSizeProperty
, false);
837 fe
->Emit (FrameworkElement::SizeChangedEvent
, args
);
843 GetDeployment ()->LayoutUpdated ();
845 // If emitting LayoutUpdate invalidated measures/arranges, we should loop again
846 if (element
->HasFlag (DIRTY_MEASURE_HINT
) || element
->HasFlag (DIRTY_ARRANGE_HINT
))
857 if (i
>= MAX_LAYOUT_PASSES
) {
858 // FIXME we shouldn't have to do this updated call here but otherwise we'll miss it completely
860 GetDeployment ()->LayoutUpdated ();
861 g_warning ("\n************** UpdateLayout Bailing Out after %d Passes *******************\n", i
);
863 LOG_LAYOUT (" (%d)\n", i
);
866 DeepTreeWalker
verifier (element
);
867 while (UIElement
*e
= verifier
.Step ()) {
868 if (e
->GetVisibility () != VisibilityVisible
) {
869 verifier
.SkipBranch ();
872 if (e
->dirty_flags
& DirtyMeasure
)
873 g_warning ("%s still has dirty measure after the layout pass\n", e
->GetType ()->GetName());
874 if (e
->dirty_flags
& DirtyArrange
)
875 g_warning ("%s still has dirty arrange after the layout pass\n", e
->GetType ()->GetName());
876 if (e
->ReadLocalValue (LayoutInformation::LastRenderSizeProperty
))
877 g_warning ("%s still has LastRenderSize after the layout pass\n", e
->GetType ()->GetName());
884 FrameworkElement::RegisterManagedOverrides (MeasureOverrideCallback measure_cb
, ArrangeOverrideCallback arrange_cb
,
885 GetDefaultTemplateCallback get_default_template_cb
, LoadedCallback loaded_cb
)
887 this->measure_cb
= measure_cb
;
888 this->arrange_cb
= arrange_cb
;
889 this->get_default_template_cb
= get_default_template_cb
;
890 this->loaded_cb
= loaded_cb
;
894 FrameworkElement::SetDefaultStyle (Style
*style
)
897 Application::GetCurrent()->ApplyStyle (this, style
);
898 default_style_applied
= true;
899 ((StylePropertyValueProvider
*)providers
[PropertyPrecedence_DefaultStyle
])->SealStyle (style
);
905 FrameworkElement::OnLoaded ()
907 UIElement::OnLoaded ();
914 FrameworkElement::ApplyTemplate ()
916 if (GetSubtreeObject ())
919 bool result
= DoApplyTemplate ();
926 FrameworkElement::DoApplyTemplate ()
928 UIElement
*e
= GetDefaultTemplate ();
931 e
->SetParent (this, &err
);
932 if (default_template
)
933 default_template
->SetParent (NULL
, NULL
);
934 default_template
= e
;
935 SetSubtreeObject (e
);
942 FrameworkElement::OnApplyTemplate ()
944 Emit (TemplateAppliedEvent
);
948 FrameworkElement::ElementRemoved (UIElement
*obj
)
950 if (GetSubtreeObject () == obj
) {
952 obj
->SetParent (NULL
, &e
);
953 SetSubtreeObject (NULL
);
955 UIElement::ElementRemoved (obj
);
959 FrameworkElement::GetDefaultTemplate ()
961 if (get_default_template_cb
)
962 return get_default_template_cb (this);