1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
5 * Copyright 2007 Novell, Inc. (http://www.novell.com)
7 * See the LICENSE file included with the distribution for details.
19 #include "thickness.h"
23 SetObjectType (Type::BORDER
);
27 Border::MeasureOverride (Size availableSize
)
29 Size desired
= Size (0,0);
31 Thickness border
= *GetPadding () + *GetBorderThickness ();
33 // Get the desired size of our child, and include any margins we set
34 VisualTreeWalker walker
= VisualTreeWalker (this);
35 while (UIElement
*child
= walker
.Step ()) {
36 if (child
->GetVisibility () != VisibilityVisible
)
39 child
->Measure (ApplySizeConstraints (availableSize
.GrowBy (-border
)));
40 desired
= child
->GetDesiredSize ();
43 desired
= desired
.GrowBy (border
);
45 desired
= ApplySizeConstraints (desired
);
47 desired
= desired
.Min (availableSize
);
53 Border::ArrangeOverride (Size finalSize
)
55 Thickness border
= *GetPadding () + *GetBorderThickness ();
57 finalSize
= ApplySizeConstraints (finalSize
);
59 Size arranged
= finalSize
;
61 VisualTreeWalker walker
= VisualTreeWalker (this);
62 while (UIElement
*child
= walker
.Step ()) {
63 if (child
->GetVisibility () != VisibilityVisible
)
66 Size desired
= child
->GetDesiredSize ();
67 Rect
childRect (0,0,finalSize
.width
,finalSize
.height
);
69 childRect
= childRect
.GrowBy (-border
);
72 child
->Arrange (childRect
);
73 arranged
= child
->GetRenderSize ();
74 arranged
= arranged
.GrowBy (border
);
76 arranged
= arranged
.Max (finalSize
);
78 arranged
= ApplySizeConstraints (arranged
);
85 Border::Render (cairo_t
*cr
, Region
*region
, bool path_only
)
87 Brush
*background
= GetBackground ();
88 Brush
*border_brush
= GetBorderBrush ();
90 cairo_set_matrix (cr
, &absolute_xform
);
95 RenderLayoutClip (cr
);
97 CornerRadius
*round
= GetCornerRadius ();
98 CornerRadius inner_adjusted
= CornerRadius (0);
99 CornerRadius outer_adjusted
= CornerRadius (0);
100 Thickness thickness
= *GetBorderThickness ();
101 Rect paint_border
= extents
;
102 Rect paint_background
= paint_border
.GrowBy (-thickness
);
105 inner_adjusted
= *round
;
106 inner_adjusted
.topLeft
= MAX (round
->topLeft
- MAX (thickness
.left
, thickness
.top
) * .5, 0);
107 inner_adjusted
.topRight
= MAX (round
->topRight
- MAX (thickness
.right
, thickness
.top
) * .5, 0);
108 inner_adjusted
.bottomRight
= MAX (round
->bottomRight
- MAX (thickness
.right
, thickness
.bottom
) * .5, 0);
109 inner_adjusted
.bottomLeft
= MAX (round
->bottomLeft
- MAX (thickness
.left
, thickness
.bottom
) * .5, 0);
111 outer_adjusted
= *round
;
112 outer_adjusted
.topLeft
= outer_adjusted
.topLeft
? MAX (round
->topLeft
+ MAX (thickness
.left
, thickness
.top
) * .5, 0) : 0;
113 outer_adjusted
.topRight
= outer_adjusted
.topRight
? MAX (round
->topRight
+ MAX (thickness
.right
, thickness
.top
) * .5, 0) : 0;
114 outer_adjusted
.bottomRight
= outer_adjusted
.bottomRight
? MAX (round
->bottomRight
+ MAX (thickness
.right
, thickness
.bottom
) * .5, 0) : 0;
115 outer_adjusted
.bottomLeft
= outer_adjusted
.bottomLeft
? MAX (round
->bottomLeft
+ MAX (thickness
.left
, thickness
.bottom
) * .5, 0) : 0;
119 * NOTE filling this way can leave alpha artifacts between the border fill and bg fill
120 * but some simple inspection of the ms results make me think that is what happens there
124 cairo_set_fill_rule (cr
, CAIRO_FILL_RULE_EVEN_ODD
);
127 border_brush
->SetupBrush (cr
, paint_border
);
130 paint_border
.Draw (cr
, &outer_adjusted
);
131 paint_background
.Draw (cr
, round
? &inner_adjusted
: NULL
);
134 border_brush
->Fill (cr
);
138 background
->SetupBrush (cr
, round
? paint_background
: NULL
);
140 paint_background
.Draw (cr
, round
? &inner_adjusted
: NULL
);
143 background
->Fill (cr
);
150 Border::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
152 if (args
->GetProperty ()->GetOwnerType() != Type::BORDER
) {
153 FrameworkElement::OnPropertyChanged (args
, error
);
157 if (args
->GetId () == Border::ChildProperty
){
158 if (args
->GetOldValue() && args
->GetOldValue()->AsUIElement()) {
159 ElementRemoved (args
->GetOldValue()->AsUIElement ());
160 SetSubtreeObject (NULL
);
161 if (args
->GetOldValue()->Is(Type::FRAMEWORKELEMENT
)) {
162 args
->GetOldValue()->AsFrameworkElement()->SetLogicalParent (NULL
, error
);
168 if (args
->GetNewValue() && args
->GetNewValue()->AsUIElement()) {
169 SetSubtreeObject (args
->GetNewValue()->AsUIElement());
170 ElementAdded (args
->GetNewValue()->AsUIElement ());
171 if (args
->GetNewValue()->Is(Type::FRAMEWORKELEMENT
)) {
172 FrameworkElement
*fwe
= args
->GetNewValue()->AsFrameworkElement ();
173 if (fwe
->GetLogicalParent() && fwe
->GetLogicalParent() != this) {
174 MoonError::FillIn (error
, MoonError::ARGUMENT
, "Content is already a child of another element");
178 args
->GetNewValue()->AsFrameworkElement()->SetLogicalParent (this, error
);
185 InvalidateMeasure ();
187 else if (args
->GetId () == Border::PaddingProperty
188 || args
->GetId () == Border::BorderThicknessProperty
) {
189 InvalidateMeasure ();
190 } else if (args
->GetId () == Border::BackgroundProperty
) {
193 NotifyListenersOfPropertyChange (args
, error
);
197 Border::OnSubPropertyChanged (DependencyProperty
*prop
, DependencyObject
*obj
, PropertyChangedEventArgs
*subobj_args
)
199 if (prop
&& (prop
->GetId () == Border::BackgroundProperty
|| prop
->GetId () == Border::BorderBrushProperty
)) {
203 FrameworkElement::OnSubPropertyChanged (prop
, obj
, subobj_args
);
207 Border::InsideObject (cairo_t
*cr
, double x
, double y
)
209 if (!FrameworkElement::InsideObject (cr
, x
, y
))
213 cairo_set_matrix (cr
, &absolute_xform
);
215 TransformPoint (&x
, &y
);
217 Render (cr
, NULL
, true);
218 bool inside
= cairo_in_fill (cr
, x
, y
);
225 Border::HitTest (cairo_t
*cr
, Rect r
, List
*uielement_list
)