2009-06-17 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / src / panel.cpp
blobc8c808ad2b5a1dca649da514dfb64230ef4e9fe8
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"
21 Panel::Panel ()
23 SetObjectType (Type::PANEL);
24 mouse_over = NULL;
26 SetSubtreeObject (GetChildren());
29 Panel::~Panel()
33 #define DEBUG_BOUNDS 0
34 #define CAIRO_CLIP 0
36 #if DEBUG_BOUNDS
37 static void space (int n)
39 for (int i = 0; i < n; i++)
40 putchar (' ');
42 static int levelb = 0;
43 #endif
45 void
46 Panel::ComputeBounds ()
48 #if DEBUG_BOUNDS
49 levelb += 4;
50 space (levelb);
51 printf ("Panel: Enter ComputeBounds (%s)\n", GetName());
52 #endif
54 // Clear the previous values
55 extents = bounds = bounds_with_children = Rect ();
57 VisualTreeWalker walker = VisualTreeWalker (this);
58 while (UIElement *item = walker.Step ()) {
60 // if the item isn't drawn, skip it
61 if (!item->GetRenderVisible ())
62 continue;
64 Rect r = item->GetSubtreeBounds ();
65 r = IntersectBoundsWithClipPath (r, true);
67 #if DEBUG_BOUNDS
68 space (levelb + 4);
69 printf ("Item (%s, %s) bounds %g %g %g %g\n", item->GetName (), item->GetTypeName (),
70 r.x, r.y, r.width, r.height);
71 #endif
72 bounds_with_children = bounds_with_children.Union (r);
75 Brush *bg = GetBackground();
76 if (bg) {
77 extents = Rect (0,0,GetActualWidth (),GetActualHeight ());
78 bounds = IntersectBoundsWithClipPath (extents, false).Transform (&absolute_xform);
79 bounds_with_children = bounds_with_children.Union (bounds);
82 #if DEBUG_BOUNDS
83 space (levelb);
84 printf ("Panel: Leave ComputeBounds (%g %g %g %g)\n",
85 bounds.x, bounds.y, bounds.width, bounds.height);
86 space (levelb);
87 printf ("Panel: Leave ComputeBounds (%g %g %g %g)\n",
88 bounds_with_children.x, bounds_with_children.y, bounds_with_children.width, bounds_with_children.height);
89 levelb -= 4;
90 #endif
93 void
94 Panel::ShiftPosition (Point p)
96 double dx = p.x - bounds.x;
97 double dy = p.y - bounds.y;
99 // need to do this after computing the delta
100 FrameworkElement::ShiftPosition (p);
102 bounds_with_children.x += dx;
103 bounds_with_children.y += dy;
106 //#define DEBUG_INVALIDATE 1
108 void
109 Panel::Render (cairo_t *cr, Region *region, bool path_only)
111 Brush *background = GetBackground ();
113 cairo_set_matrix (cr, &absolute_xform);
115 Rect area = Rect (0.0, 0.0, GetActualWidth (), GetActualHeight ());
116 cairo_new_path (cr);
117 area.Draw (cr);
119 if (background && area.width > 0 && area.height > 0 && !path_only) {
120 background->SetupBrush (cr, area);
121 background->Fill (cr);
125 Rect
126 Panel::GetCoverageBounds ()
128 Brush *background = GetBackground ();
130 if (background && background->IsOpaque ())
131 return bounds;
133 return Rect ();
136 bool
137 Panel::InsideObject (cairo_t *cr, double x, double y)
139 if (GetBackground ())
140 return FrameworkElement::InsideObject (cr, x, y);
142 return false;
145 bool
146 Panel::EmptyBackground ()
148 return GetBackground () == NULL;
151 Size
152 Panel::MeasureOverride (Size availableSize)
154 Size result = Size (0,0);
155 return result;
158 void
159 Panel::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
161 if (args->GetProperty ()->GetOwnerType() != Type::PANEL) {
162 FrameworkElement::OnPropertyChanged (args, error);
163 return;
166 if (args->GetId () == Panel::BackgroundProperty)
167 Invalidate ();
169 if (args->GetId () == Panel::ChildrenProperty) {
170 Collection *collection;
172 if (args->GetOldValue()) {
173 collection = args->GetOldValue()->AsCollection ();
174 for (int i = 0; i < collection->GetCount (); i++)
175 ElementRemoved (collection->GetValueAt (i)->AsUIElement());
178 if (args->GetNewValue()) {
179 collection = args->GetNewValue()->AsCollection ();
180 for (int i = 0; i < collection->GetCount (); i++)
181 ElementAdded (collection->GetValueAt (i)->AsUIElement ());
184 SetSubtreeObject (args->GetNewValue() ? args->GetNewValue()->AsCollection() : NULL);
186 UpdateBounds();
189 NotifyListenersOfPropertyChange (args, error);
192 void
193 Panel::OnSubPropertyChanged (DependencyProperty *prop, DependencyObject *obj, PropertyChangedEventArgs *subobj_args)
195 if (prop && prop->GetId () == Panel::BackgroundProperty) {
196 Invalidate ();
197 } else {
198 FrameworkElement::OnSubPropertyChanged (prop, obj, subobj_args);
202 void
203 Panel::OnCollectionChanged (Collection *col, CollectionChangedEventArgs *args)
205 if (col == GetChildren ()) {
206 MoonError error;
208 switch (args->GetChangedAction()) {
209 case CollectionChangedActionReplace:
210 if (args->GetOldItem()->Is(Type::FRAMEWORKELEMENT))
211 args->GetOldItem()->AsFrameworkElement()->SetLogicalParent (NULL, &error /* XXX unused */);
212 ElementRemoved (args->GetOldItem()->AsUIElement ());
213 // now fall thru to Add
214 case CollectionChangedActionAdd:
215 ElementAdded (args->GetNewItem()->AsUIElement ());
216 if (args->GetNewItem()->Is(Type::FRAMEWORKELEMENT))
217 args->GetNewItem()->AsFrameworkElement()->SetLogicalParent (this, &error /* XXX unused */);
218 break;
219 case CollectionChangedActionRemove:
220 if (args->GetOldItem()->Is(Type::FRAMEWORKELEMENT))
221 args->GetOldItem()->AsFrameworkElement()->SetLogicalParent (NULL, &error /* XXX unused */);
222 ElementRemoved (args->GetOldItem()->AsUIElement ());
223 break;
224 case CollectionChangedActionClearing:
225 for (int i = 0; i < col->GetCount (); i++) {
226 UIElement *ui = col->GetValueAt (i)->AsUIElement ();
227 if (ui->Is(Type::FRAMEWORKELEMENT))
228 ((FrameworkElement*)ui)->SetLogicalParent (NULL, &error /* XXX unused */);
229 ElementRemoved (ui);
231 break;
232 case CollectionChangedActionCleared:
233 // nothing needed here.
234 break;
236 } else {
237 FrameworkElement::OnCollectionChanged (col, args);
242 void
243 Panel::OnLoaded ()
245 FrameworkElement::OnLoaded ();
247 if (GetSurface ()) {
248 // queue a resort based on ZIndex
249 GetSurface ()->AddDirtyElement (this, DirtyChildrenZIndices);
253 void
254 Panel::ElementAdded (UIElement *item)
256 FrameworkElement::ElementAdded (item);
258 if (GetSurface ()) {
259 // queue a resort based on ZIndex
260 GetSurface ()->AddDirtyElement (this, DirtyChildrenZIndices);
264 void
265 Panel::ElementRemoved (UIElement *item)
267 FrameworkElement::ElementRemoved (item);
269 if (GetSurface ()) {
270 // queue a resort based on ZIndex
271 GetSurface ()->AddDirtyElement (this, DirtyChildrenZIndices);
276 void
277 Panel::OnCollectionItemChanged (Collection *col, DependencyObject *obj, PropertyChangedEventArgs *args)
279 if (col == GetChildren()) {
280 // if a child changes its ZIndex property we need to resort our Children
281 if (args->GetId () == Canvas::ZIndexProperty) {
282 ((UIElement *) obj)->Invalidate ();
283 if (GetSurface ()) {
284 // queue a resort based on ZIndex
285 GetSurface ()->AddDirtyElement (this, DirtyChildrenZIndices);
287 return;
291 FrameworkElement::OnCollectionItemChanged (col, obj, args);