2009-12-03 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / src / panel.cpp
blobd4956c3529bab1946d0954a8600012fb3b576624
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * panel.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 "canvas.h"
14 #include "geometry.h"
15 #include "panel.h"
16 #include "brush.h"
17 #include "math.h"
18 #include "collection.h"
19 #include "runtime.h"
20 #include "deployment.h"
22 Panel::Panel ()
24 SetObjectType (Type::PANEL);
25 mouse_over = NULL;
27 SetSubtreeObject (GetChildren());
30 Panel::~Panel()
34 #define DEBUG_BOUNDS 0
35 #define CAIRO_CLIP 0
37 #if DEBUG_BOUNDS
38 static void space (int n)
40 for (int i = 0; i < n; i++)
41 putchar (' ');
43 static int levelb = 0;
44 #endif
46 void
47 Panel::ComputeBounds ()
49 #if DEBUG_BOUNDS
50 levelb += 4;
51 space (levelb);
52 printf ("Panel: Enter ComputeBounds (%s)\n", GetName());
53 #endif
55 // Clear the previous values
56 extents = bounds = bounds_with_children = Rect ();
58 VisualTreeWalker walker = VisualTreeWalker (this);
59 while (UIElement *item = walker.Step ()) {
61 // if the item isn't drawn, skip it
62 if (!item->GetRenderVisible ())
63 continue;
65 Rect r = item->GetSubtreeBounds ();
66 r = IntersectBoundsWithClipPath (r, true);
68 #if DEBUG_BOUNDS
69 space (levelb + 4);
70 printf ("Item (%s, %s) bounds %g %g %g %g\n", item->GetName (), item->GetTypeName (),
71 r.x, r.y, r.width, r.height);
72 #endif
73 bounds_with_children = bounds_with_children.Union (r);
76 Brush *bg = GetBackground();
77 if (bg) {
78 extents = Rect (0,0,GetActualWidth (),GetActualHeight ());
79 bounds = IntersectBoundsWithClipPath (extents, false).Transform (&absolute_xform);
80 bounds_with_children = bounds_with_children.Union (bounds);
83 #if DEBUG_BOUNDS
84 space (levelb);
85 printf ("Panel: Leave ComputeBounds (%g %g %g %g)\n",
86 bounds.x, bounds.y, bounds.width, bounds.height);
87 space (levelb);
88 printf ("Panel: Leave ComputeBounds (%g %g %g %g)\n",
89 bounds_with_children.x, bounds_with_children.y, bounds_with_children.width, bounds_with_children.height);
90 levelb -= 4;
91 #endif
94 void
95 Panel::ShiftPosition (Point p)
97 double dx = p.x - bounds.x;
98 double dy = p.y - bounds.y;
100 // need to do this after computing the delta
101 FrameworkElement::ShiftPosition (p);
103 bounds_with_children.x += dx;
104 bounds_with_children.y += dy;
107 //#define DEBUG_INVALIDATE 1
109 void
110 Panel::Render (cairo_t *cr, Region *region, bool path_only)
112 Brush *background = GetBackground ();
114 cairo_set_matrix (cr, &absolute_xform);
116 Size framework (GetActualWidth (), GetActualHeight ());
117 framework = ApplySizeConstraints (framework);
118 Rect area = Rect (0.0, 0.0, framework.width, framework.height);
120 cairo_save (cr);
121 if (!path_only)
122 RenderLayoutClip (cr);
124 cairo_new_path (cr);
125 area.Draw (cr);
127 if (background && area.width > 0 && area.height > 0 && !path_only) {
128 background->SetupBrush (cr, area);
129 background->Fill (cr);
131 cairo_restore (cr);
134 Rect
135 Panel::GetCoverageBounds ()
137 Brush *background = GetBackground ();
139 if (background && background->IsOpaque ())
140 return bounds;
142 return Rect ();
145 bool
146 Panel::InsideObject (cairo_t *cr, double x, double y)
148 if (GetBackground ())
149 return FrameworkElement::InsideObject (cr, x, y);
151 return false;
154 bool
155 Panel::EmptyBackground ()
157 return GetBackground () == NULL;
160 Size
161 Panel::MeasureOverride (Size availableSize)
163 Size result = Size (0,0);
164 return result;
167 void
168 Panel::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
170 if (args->GetProperty ()->GetOwnerType() != Type::PANEL) {
171 FrameworkElement::OnPropertyChanged (args, error);
172 return;
175 if (args->GetId () == Panel::BackgroundProperty) {
176 /* several of the bounds values are conditional on having a brush */
177 UpdateBounds ();
178 Invalidate ();
179 } else if (args->GetId () == Panel::ChildrenProperty) {
180 Collection *collection;
182 SetSubtreeObject (args->GetNewValue() ? args->GetNewValue()->AsCollection() : NULL);
184 if (args->GetOldValue()) {
185 collection = args->GetOldValue()->AsCollection ();
186 for (int i = 0; i < collection->GetCount (); i++)
187 ElementRemoved (collection->GetValueAt (i)->AsUIElement());
190 if (args->GetNewValue()) {
191 collection = args->GetNewValue()->AsCollection ();
192 for (int i = 0; i < collection->GetCount (); i++)
193 ElementAdded (collection->GetValueAt (i)->AsUIElement ());
196 UpdateBounds();
199 NotifyListenersOfPropertyChange (args, error);
202 void
203 Panel::OnSubPropertyChanged (DependencyProperty *prop, DependencyObject *obj, PropertyChangedEventArgs *subobj_args)
205 if (prop && prop->GetId () == Panel::BackgroundProperty) {
206 Invalidate ();
207 } else {
208 FrameworkElement::OnSubPropertyChanged (prop, obj, subobj_args);
212 void
213 Panel::OnCollectionChanged (Collection *col, CollectionChangedEventArgs *args)
215 if (col == GetChildren ()) {
216 MoonError error;
218 switch (args->GetChangedAction()) {
219 case CollectionChangedActionReplace:
220 if (args->GetOldItem()->Is(GetDeployment (), Type::FRAMEWORKELEMENT))
221 args->GetOldItem()->AsFrameworkElement()->SetLogicalParent (NULL, &error /* XXX unused */);
222 ElementRemoved (args->GetOldItem()->AsUIElement ());
223 // now fall thru to Add
224 case CollectionChangedActionAdd:
225 if (args->GetNewItem()->Is(GetDeployment (), Type::FRAMEWORKELEMENT))
226 args->GetNewItem()->AsFrameworkElement()->SetLogicalParent (this, &error /* XXX unused */);
227 ElementAdded (args->GetNewItem()->AsUIElement ());
228 break;
229 case CollectionChangedActionRemove:
230 if (args->GetOldItem()->Is(GetDeployment (), Type::FRAMEWORKELEMENT))
231 args->GetOldItem()->AsFrameworkElement()->SetLogicalParent (NULL, &error /* XXX unused */);
232 ElementRemoved (args->GetOldItem()->AsUIElement ());
233 break;
234 case CollectionChangedActionClearing:
235 for (int i = 0; i < col->GetCount (); i++) {
236 UIElement *ui = col->GetValueAt (i)->AsUIElement ();
237 if (ui->Is(Type::FRAMEWORKELEMENT))
238 ((FrameworkElement*)ui)->SetLogicalParent (NULL, &error /* XXX unused */);
239 ElementRemoved (ui);
241 break;
242 case CollectionChangedActionCleared:
243 // nothing needed here.
244 break;
246 } else {
247 FrameworkElement::OnCollectionChanged (col, args);
252 void
253 Panel::OnLoaded ()
255 FrameworkElement::OnLoaded ();
257 if (IsAttached ()) {
258 // queue a resort based on ZIndex
259 GetDeployment ()->GetSurface ()->AddDirtyElement (this, DirtyChildrenZIndices);
263 void
264 Panel::ElementAdded (UIElement *item)
266 FrameworkElement::ElementAdded (item);
268 if (IsAttached ()) {
269 // queue a resort based on ZIndex
270 GetDeployment ()->GetSurface ()->AddDirtyElement (this, DirtyChildrenZIndices);
274 void
275 Panel::ElementRemoved (UIElement *item)
277 FrameworkElement::ElementRemoved (item);
279 if (IsAttached ()) {
280 // queue a resort based on ZIndex
281 GetDeployment ()->GetSurface ()->AddDirtyElement (this, DirtyChildrenZIndices);
286 void
287 Panel::OnCollectionItemChanged (Collection *col, DependencyObject *obj, PropertyChangedEventArgs *args)
289 if (col == GetChildren()) {
290 // if a child changes its ZIndex property we need to resort our Children
291 if (args->GetId () == Canvas::ZIndexProperty) {
292 ((UIElement *) obj)->Invalidate ();
293 if (IsAttached ()) {
294 // queue a resort based on ZIndex
295 GetDeployment ()->GetSurface ()->AddDirtyElement (this, DirtyChildrenZIndices);
297 return;
301 FrameworkElement::OnCollectionItemChanged (col, obj, args);