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 child
->Measure (availableSize
.GrowBy (-border
));
37 desired
= child
->GetDesiredSize ();
40 desired
= desired
.GrowBy (border
);
42 desired
= desired
.Min (availableSize
);
48 Border::ArrangeOverride (Size finalSize
)
50 Thickness border
= *GetPadding () + *GetBorderThickness ();
52 Size arranged
= finalSize
;
54 VisualTreeWalker walker
= VisualTreeWalker (this);
55 while (UIElement
*child
= walker
.Step ()) {
56 Rect
childRect (0,0,finalSize
.width
,finalSize
.height
);
58 childRect
= childRect
.GrowBy (-border
);
61 child
->Arrange (childRect
);
63 arranged
= Size (childRect
.width
, childRect
.height
).GrowBy (border
);
65 arranged
= arranged
.Max (finalSize
);
72 Border::Render (cairo_t
*cr
, Region
*region
, bool path_only
)
74 Brush
*background
= GetBackground ();
75 Brush
*border_brush
= GetBorderBrush ();
77 cairo_set_matrix (cr
, &absolute_xform
);
82 RenderLayoutClip (cr
);
84 CornerRadius
*round
= GetCornerRadius ();
85 CornerRadius inner_adjusted
= CornerRadius (0);
86 CornerRadius outer_adjusted
= CornerRadius (0);
87 Thickness thickness
= *GetBorderThickness ();
88 Rect paint_border
= extents
;
89 Rect paint_background
= paint_border
.GrowBy (-thickness
);
92 inner_adjusted
= *round
;
93 inner_adjusted
.topLeft
= MAX (round
->topLeft
- MAX (thickness
.left
, thickness
.top
) * .5, 0);
94 inner_adjusted
.topRight
= MAX (round
->topRight
- MAX (thickness
.right
, thickness
.top
) * .5, 0);
95 inner_adjusted
.bottomRight
= MAX (round
->bottomRight
- MAX (thickness
.right
, thickness
.bottom
) * .5, 0);
96 inner_adjusted
.bottomLeft
= MAX (round
->bottomLeft
- MAX (thickness
.left
, thickness
.bottom
) * .5, 0);
98 outer_adjusted
= *round
;
99 outer_adjusted
.topLeft
= outer_adjusted
.topLeft
? MAX (round
->topLeft
+ MAX (thickness
.left
, thickness
.top
) * .5, 0) : 0;
100 outer_adjusted
.topRight
= outer_adjusted
.topRight
? MAX (round
->topRight
+ MAX (thickness
.right
, thickness
.top
) * .5, 0) : 0;
101 outer_adjusted
.bottomRight
= outer_adjusted
.bottomRight
? MAX (round
->bottomRight
+ MAX (thickness
.right
, thickness
.bottom
) * .5, 0) : 0;
102 outer_adjusted
.bottomLeft
= outer_adjusted
.bottomLeft
? MAX (round
->bottomLeft
+ MAX (thickness
.left
, thickness
.bottom
) * .5, 0) : 0;
106 * NOTE filling this way can leave alpha artifacts between the border fill and bg fill
107 * but some simple inspection of the ms results make me think that is what happens there
111 cairo_set_fill_rule (cr
, CAIRO_FILL_RULE_EVEN_ODD
);
114 border_brush
->SetupBrush (cr
, paint_border
);
117 paint_border
.Draw (cr
, &outer_adjusted
);
118 paint_background
.Draw (cr
, round
? &inner_adjusted
: NULL
);
121 border_brush
->Fill (cr
);
125 background
->SetupBrush (cr
, round
? paint_background
: NULL
);
127 paint_background
.Draw (cr
, round
? &inner_adjusted
: NULL
);
130 background
->Fill (cr
);
137 Border::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
139 if (args
->GetProperty ()->GetOwnerType() != Type::BORDER
) {
140 FrameworkElement::OnPropertyChanged (args
, error
);
144 if (args
->GetId () == Border::ChildProperty
){
145 if (args
->GetOldValue() && args
->GetOldValue()->AsUIElement()) {
146 ElementRemoved (args
->GetOldValue()->AsUIElement ());
147 SetSubtreeObject (NULL
);
148 if (args
->GetOldValue()->Is(GetDeployment (), Type::FRAMEWORKELEMENT
)) {
149 args
->GetOldValue()->AsFrameworkElement()->SetLogicalParent (NULL
, error
);
155 if (args
->GetNewValue() && args
->GetNewValue()->AsUIElement()) {
156 SetSubtreeObject (args
->GetNewValue()->AsUIElement());
157 ElementAdded (args
->GetNewValue()->AsUIElement ());
158 if (args
->GetNewValue()->Is(GetDeployment (), Type::FRAMEWORKELEMENT
)) {
159 FrameworkElement
*fwe
= args
->GetNewValue()->AsFrameworkElement ();
160 if (fwe
->GetLogicalParent() && fwe
->GetLogicalParent() != this) {
161 MoonError::FillIn (error
, MoonError::ARGUMENT
, "Content is already a child of another element");
165 args
->GetNewValue()->AsFrameworkElement()->SetLogicalParent (this, error
);
172 InvalidateMeasure ();
174 else if (args
->GetId () == Border::PaddingProperty
175 || args
->GetId () == Border::BorderThicknessProperty
) {
176 InvalidateMeasure ();
177 } else if (args
->GetId () == Border::BackgroundProperty
) {
180 NotifyListenersOfPropertyChange (args
, error
);
184 Border::OnSubPropertyChanged (DependencyProperty
*prop
, DependencyObject
*obj
, PropertyChangedEventArgs
*subobj_args
)
186 if (prop
&& (prop
->GetId () == Border::BackgroundProperty
|| prop
->GetId () == Border::BorderBrushProperty
)) {
190 FrameworkElement::OnSubPropertyChanged (prop
, obj
, subobj_args
);
194 Border::InsideObject (cairo_t
*cr
, double x
, double y
)
196 if (!FrameworkElement::InsideObject (cr
, x
, y
))
201 cairo_set_matrix (cr
, &absolute_xform
);
203 TransformPoint (&x
, &y
);
205 Render (cr
, NULL
, true);
206 bool inside
= cairo_in_fill (cr
, x
, y
);
213 Border::HitTest (cairo_t
*cr
, Rect r
, List
*uielement_list
)