2009-11-13 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / src / grid.cpp
blob3cfe8dd03e50398c8043b853ff078695d195ddc1
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * grid.cpp: canvas definitions.
5 * Contact:
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2008 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
14 #include <config.h>
16 #include <math.h>
18 #include "brush.h"
19 #include "rect.h"
20 #include "canvas.h"
21 #include "grid.h"
22 #include "runtime.h"
23 #include "namescope.h"
24 #include "collection.h"
26 Grid::Grid ()
28 SetObjectType (Type::GRID);
29 row_matrix = NULL;
30 col_matrix = NULL;
33 Grid::~Grid ()
35 DestroyMatrices ();
38 double
39 Grid::Clamp (double val, double min, double max)
41 if (val < min)
42 return min;
43 else if (val > max)
44 return max;
45 return val;
48 void
49 Grid::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
51 if (args->GetProperty ()->GetOwnerType() != Type::GRID) {
52 Panel::OnPropertyChanged (args, error);
53 return;
56 if (args->GetId () == Grid::ShowGridLinesProperty){
57 Invalidate ();
60 InvalidateMeasure ();
62 NotifyListenersOfPropertyChange (args, error);
65 void
66 Grid::OnCollectionChanged (Collection *col, CollectionChangedEventArgs *args)
68 if (col == GetColumnDefinitions () ||
69 col == GetRowDefinitions ()) {
70 InvalidateMeasure ();
71 } else {
72 Panel::OnCollectionChanged (col, args);
76 void
77 Grid::OnCollectionItemChanged (Collection *col, DependencyObject *obj, PropertyChangedEventArgs *args)
79 if (col == GetChildren ()) {
80 if (args->GetId () == Grid::ColumnProperty
81 || args->GetId () == Grid::RowProperty
82 || args->GetId () == Grid::ColumnSpanProperty
83 || args->GetId () == Grid::RowSpanProperty) {
84 InvalidateMeasure ();
86 // SL invalidates the measure on the child when these properties change.
87 // Tested by MeasureAutoRows2 and ChangingGridPropertiesInvalidates
88 ((UIElement *) obj)->InvalidateMeasure ();
89 return;
91 } else if (col == GetColumnDefinitions () || col == GetRowDefinitions ()) {
92 if (args->GetId() != ColumnDefinition::ActualWidthProperty
93 && args->GetId() != RowDefinition::ActualHeightProperty) {
94 InvalidateMeasure ();
96 return;
99 Panel::OnCollectionItemChanged (col, obj, args);
102 Size
103 Grid::MeasureOverride (Size availableSize)
105 Size totalSize = availableSize;
107 ColumnDefinitionCollection *columns = GetColumnDefinitions ();
108 RowDefinitionCollection *rows = GetRowDefinitions ();
109 bool free_col = false;
110 bool free_row = false;
112 int col_count = columns->GetCount ();
113 int row_count = rows->GetCount ();
114 Size total_stars = Size (0,0);
116 if (col_count == 0) {
117 columns = new ColumnDefinitionCollection ();
118 ColumnDefinition *coldef = new ColumnDefinition ();
119 columns->Add (coldef);
120 coldef->unref ();
121 free_col = true;
122 col_count = 1;
125 if (row_count == 0) {
126 rows = new RowDefinitionCollection ();
127 RowDefinition *rowdef = new RowDefinition ();
128 rows->Add (rowdef);
129 rowdef->unref ();
130 free_row = true;
131 row_count = 1;
134 CreateMatrices (row_count, col_count);
136 for (int i = 0; i < row_count; i ++) {
137 RowDefinition *rowdef = rows->GetValueAt (i)->AsRowDefinition ();
138 GridLength* height = rowdef->GetHeight();
140 rowdef->SetActualHeight (INFINITY);
141 row_matrix [i][i] = Segment (0.0, rowdef->GetMinHeight (), rowdef->GetMaxHeight (), height->type);
143 if (height->type == GridUnitTypePixel) {
144 row_matrix [i][i].size = Grid::Clamp (height->val, row_matrix [i][i].min, row_matrix [i][i].max);
145 rowdef->SetActualHeight (row_matrix [i][i].size);
147 if (height->type == GridUnitTypeStar) {
148 row_matrix [i][i].stars = height->val;
149 total_stars.height += height->val;
153 for (int i = 0; i < col_count; i ++) {
154 ColumnDefinition *coldef = columns->GetValueAt (i)->AsColumnDefinition ();
155 GridLength *width = coldef->GetWidth ();
157 coldef->SetActualWidth (INFINITY);
158 col_matrix [i][i] = Segment (0.0, coldef->GetMinWidth (), coldef->GetMaxWidth (), width->type);
160 if (width->type == GridUnitTypePixel) {
161 col_matrix [i][i].size = Grid::Clamp (width->val, col_matrix [i][i].min, col_matrix [i][i].max);
162 coldef->SetActualWidth (col_matrix [i][i].size);
164 if (width->type == GridUnitTypeStar) {
165 col_matrix [i][i].stars = width->val;
166 total_stars.width += width->val;
170 List sizes;
171 GridNode *node;
172 GridNode *separator = new GridNode (NULL, 0, 0, 0);
173 sizes.Append (separator);
175 // Pre-process the grid children so that we know what types of elements we have so
176 // we can apply our special measuring rules.
177 GridWalker grid_walker (this, row_matrix, row_matrix_dim, col_matrix, col_matrix_dim);
178 for (int i = 0; i < 6; i++) {
179 // These bools tell us which grid element type we should be measuring. i.e.
180 // 'star/auto' means we should measure elements with a star row and auto col
181 bool auto_auto = i == 0;
182 bool star_auto = i == 1;
183 bool auto_star = i == 2;
184 bool star_auto_again = i == 3;
185 bool non_star = i == 4;
186 bool remaining_star = i == 5;
188 VisualTreeWalker walker = VisualTreeWalker (this);
189 while (UIElement *child = walker.Step ()) {
190 gint32 col, row;
191 gint32 colspan, rowspan;
192 Size child_size = Size (0,0);
193 bool star_col = false;
194 bool star_row = false;
195 bool auto_col = false;
196 bool auto_row = false;
198 col = MIN (Grid::GetColumn (child), col_count - 1);
199 row = MIN (Grid::GetRow (child), row_count - 1);
200 colspan = MIN (Grid::GetColumnSpan (child), col_count - col);
201 rowspan = MIN (Grid::GetRowSpan (child), row_count - row);
203 for (int r = row; r < row + rowspan; r++) {
204 star_row |= row_matrix [r][r].type == GridUnitTypeStar;
205 auto_row |= row_matrix [r][r].type == GridUnitTypeAuto;
207 for (int c = col; c < col + colspan; c++) {
208 star_col |= col_matrix [c][c].type == GridUnitTypeStar;
209 auto_col |= col_matrix [c][c].type == GridUnitTypeAuto;
212 // This series of if statements checks whether or not we should measure
213 // the current element and also if we need to override the sizes
214 // passed to the Measure call.
216 // If the element has Auto rows and Auto columns and does not span Star
217 // rows/cols it should only be measured in the auto_auto phase.
218 // There are similar rules governing auto/star and star/auto elements.
219 // NOTE: star/auto elements are measured twice. The first time with
220 // an override for height, the second time without it.
221 if (auto_row && auto_col && !star_row && !star_col) {
222 if (!auto_auto)
223 continue;
224 child_size.width = INFINITY;
225 child_size.height = INFINITY;
227 else if (star_row && auto_col) {
228 if (!(star_auto || star_auto_again))
229 continue;
231 if (star_auto && grid_walker.HasAutoStar ())
232 child_size.height = INFINITY;
233 child_size.width = INFINITY;
234 } else if (auto_row && star_col && !star_row) {
235 if (!auto_star)
236 continue;
238 child_size.height = INFINITY;
239 } else if ((auto_row || auto_col) && !(star_row || star_col)) {
240 if (!non_star)
241 continue;
242 if (auto_row)
243 child_size.height = INFINITY;
244 if (auto_col)
245 child_size.width = INFINITY;
246 } else if (!(star_row || star_col)) {
247 if (!non_star)
248 continue;
249 } else {
250 if (!remaining_star)
251 continue;
254 for (int r = row; r < row + rowspan; r++) {
255 if (row_matrix [r][r].type == GridUnitTypeStar) {
256 double v = availableSize.height * row_matrix [r][r].stars / total_stars.height;
257 child_size.height += Grid::Clamp (v, row_matrix [r][r].min, row_matrix [r][r].max);
258 } else {
259 child_size.height += row_matrix [r][r].size;
262 for (int c = col; c < col + colspan; c++) {
263 if (col_matrix [c][c].type == GridUnitTypeStar) {
264 double v = availableSize.width * col_matrix [c][c].stars / total_stars.width;
265 child_size.width += Grid::Clamp (v, col_matrix [c][c].min, col_matrix [c][c].max);
266 } else {
267 child_size.width += col_matrix [c][c].size;
271 child->Measure (child_size);
272 Size desired = child->GetDesiredSize();
274 // Elements distribute their height based on two rules:
275 // 1) Elements with rowspan/colspan == 1 distribute their height first
276 // 2) Everything else distributes in a LIFO manner.
277 // As such, add all UIElements with rowspan/colspan == 1 after the separator in
278 // the list and everything else before it. Then to process, just keep popping
279 // elements off the end of the list.
280 node = new GridNode (row_matrix, row + rowspan - 1, row, desired.height);
281 sizes.InsertBefore (node, node->row == node->col ? separator->next : separator);
283 node = new GridNode (col_matrix, col + colspan - 1, col, desired.width);
284 sizes.InsertBefore (node, node->row == node->col ? separator->next : separator);
287 sizes.Unlink (separator);
289 while (GridNode *node= (GridNode *) sizes.Last ()) {
290 node->matrix [node->row][node->col].size = MAX (node->matrix [node->row][node->col].size, node->size);
291 AllocateGridSegments (row_count, col_count);
292 sizes.Remove (node);
295 // Calculate how much unused space we have so the next round of
296 // measurements uses the right sizes for Star segments
297 availableSize = totalSize;
298 for (int r = 0; r < row_matrix_dim; r++)
299 if (row_matrix [r][r].type != GridUnitTypeStar)
300 availableSize.height = MAX (availableSize.height - row_matrix [r][r].size, 0);
302 for (int c = 0; c < col_matrix_dim; c++)
303 if (col_matrix [c][c].type != GridUnitTypeStar)
304 availableSize.width = MAX (availableSize.width - col_matrix [c][c].size, 0);
306 sizes.Append (separator);
309 sizes.Remove (separator);
311 // We have to calulate the desired grid size before expanding
312 // star segments to consume available space.
313 Size grid_size = Size (0, 0);
314 for (int c = 0; c < col_count; c ++)
315 grid_size.width += col_matrix [c][c].size;
316 for (int r = 0; r < row_count; r ++)
317 grid_size.height += row_matrix [r][r].size;
319 grid_size = grid_size.Max (GetWidth (), GetHeight ());
321 // This is where we do the final expansion of star rows. Right now the value
322 // of 'size' for star segments in row_matrix and col_matrix contains the
323 // size that the segments would naturally take up.
325 bool has_child = GetChildren ()->GetCount () > 0;
326 if (columns->GetCount () > 0)
327 TryExpandStarCols (totalSize, !has_child, !has_child);
328 if (rows->GetCount () > 0)
329 TryExpandStarRows (totalSize, !has_child, !has_child);
331 if (free_col) {
332 columns->unref ();
334 if (free_row) {
335 rows->unref ();
337 // now choose whichever is smaller, our chosen size or the availableSize.
338 return totalSize.Min (grid_size);
341 void
342 Grid::TryExpandStarRows (Size availableSize, bool force_width_nan, bool force_height_nan)
344 RowDefinitionCollection *rows = GetRowDefinitions ();
345 bool expand_stars = GetVerticalAlignment () == VerticalAlignmentStretch || !isnan (GetHeight ());
346 if (force_height_nan)
347 expand_stars &= !isnan (GetHeight ());
349 if (expand_stars && availableSize.height != INFINITY) {
350 // When expanding star rows, we need to zero out their height before
351 // calling AssignSize. AssignSize takes care of distributing the
352 // available size when there are Mins and Maxs applied.
353 for (int i = 0; i < row_matrix_dim; i++) {
354 if (row_matrix [i][i].type == GridUnitTypeStar)
355 row_matrix [i][i].size = 0.0;
356 else
357 availableSize.height = MAX (availableSize.height - row_matrix [i][i].size, 0);
360 AssignSize (row_matrix, 0, row_matrix_dim - 1, &availableSize.height, GridUnitTypeStar);
361 if (rows->GetCount () > 0) {
362 for (int i = 0; i < row_matrix_dim; i++)
363 if (row_matrix [i][i].type == GridUnitTypeStar)
364 rows->GetValueAt (i)->AsRowDefinition ()->SetActualHeight (row_matrix [i][i].size);
369 void
370 Grid::TryExpandStarCols (Size availableSize, bool force_width_nan, bool force_height_nan)
372 ColumnDefinitionCollection *columns = GetColumnDefinitions ();
373 bool expand_stars = GetHorizontalAlignment () == HorizontalAlignmentStretch || !isnan (GetWidth ());
374 if (force_width_nan)
375 expand_stars &= !isnan (GetWidth ());
377 if (expand_stars && availableSize.width != INFINITY) {
378 for (int i = 0; i < col_matrix_dim; i++) {
379 if (col_matrix [i][i].type == GridUnitTypeStar)
380 col_matrix [i][i].size = 0;
381 else
382 availableSize.width = MAX (availableSize.width - col_matrix [i][i].size, 0);
385 AssignSize (col_matrix, 0, col_matrix_dim - 1, &availableSize.width, GridUnitTypeStar);
387 if (columns->GetCount () > 0) {
388 for (int i = 0; i < col_matrix_dim; i++)
389 if (col_matrix [i][i].type == GridUnitTypeStar)
390 columns->GetValueAt (i)->AsColumnDefinition ()->SetActualWidth (col_matrix [i][i].size);
395 void
396 Grid::AllocateGridSegments (int row_count, int col_count)
398 // First allocate the heights of the RowDefinitions, then allocate
399 // the widths of the ColumnDefinitions.
400 for (int i = 0; i < 2; i ++) {
401 Segment **matrix = i == 0 ? row_matrix : col_matrix;
402 int count = i == 0 ? row_count : col_count;
404 for (int row = count - 1; row >= 0; row--) {
405 for (int col = row; col >= 0; col--) {
406 bool spans_star = false;
407 for (int j = row; j >= col; j --)
408 spans_star |= matrix [j][j].type == GridUnitTypeStar;
410 // This is the amount of pixels which must be available between the grid rows
411 // at index 'col' and 'row'. i.e. if 'row' == 0 and 'col' == 2, there must
412 // be at least 'matrix [row][col].size' pixels of height allocated between
413 // all the rows in the range col -> row.
414 double current = matrix [row][col].size;
416 // Count how many pixels have already been allocated between the grid rows
417 // in the range col -> row. The amount of pixels allocated to each grid row/column
418 // is found on the diagonal of the matrix.
419 double total_allocated = 0;
420 for (int i = row; i >= col; i--)
421 total_allocated += matrix [i][i].size;
423 // If the size requirement has not been met, allocate the additional required
424 // size between 'pixel' rows, then 'star' rows, finally 'auto' rows, until all
425 // height has been assigned.
426 if (total_allocated < current) {
427 double additional = current - total_allocated;
428 if (spans_star) {
429 AssignSize (matrix, col, row, &additional, GridUnitTypeStar);
430 } else {
431 AssignSize (matrix, col, row, &additional, GridUnitTypePixel);
432 AssignSize (matrix, col, row, &additional, GridUnitTypeAuto);
440 void
441 Grid::AssignSize (Segment **matrix, int start, int end, double *size, GridUnitType type)
443 double count = 0;
444 bool assigned;
446 // Count how many segments are of the correct type. If we're measuring Star rows/cols
447 // we need to count the number of stars instead.
448 for (int i = start; i <= end; i++)
449 if (matrix [i][i].type == type && matrix [i][i].size < matrix [i][i].max)
450 count += type == GridUnitTypeStar ? matrix [i][i].stars : 1;
452 do {
453 assigned = false;
454 double contribution = *size / count;
456 for (int i = start; i <= end; i++) {
457 if (!(matrix [i][i].type == type && matrix [i][i].size < matrix [i][i].max))
458 continue;
459 double newsize = matrix [i][i].size;
460 newsize += contribution * (type == GridUnitTypeStar ? matrix [i][i].stars : 1);
461 newsize = MIN (newsize, matrix [i][i].max);
462 assigned |= newsize > matrix [i][i].size;
463 *size -= newsize - matrix [i][i].size;
464 matrix [i][i].size = newsize;
466 } while (assigned);
469 void
470 Grid::DestroyMatrices ()
472 if (row_matrix != NULL) {
473 for (int i = 0; i < row_matrix_dim; i++)
474 delete [] row_matrix [i];
475 delete [] row_matrix;
476 row_matrix = NULL;
479 if (col_matrix != NULL) {
480 for (int i = 0; i < col_matrix_dim; i++)
481 delete [] col_matrix [i];
482 delete [] col_matrix;
483 col_matrix = NULL;
487 void
488 Grid::CreateMatrices (int row_count, int col_count)
490 DestroyMatrices ();
492 row_matrix_dim = row_count;
493 col_matrix_dim = col_count;
495 row_matrix = new Segment *[row_count];
496 for (int i = 0; i < row_count; i++) {
497 row_matrix [i] = new Segment [row_count];
498 for (int j = 0; j < row_count; j++)
499 row_matrix [i][j] = Segment ();
502 col_matrix = new Segment *[col_count];
503 for (int i = 0; i < col_count; i++) {
504 col_matrix [i] = new Segment [col_count];
505 for (int j = 0; j < col_count; j++)
506 col_matrix [i][j] = Segment ();
510 void
511 Grid::ComputeBounds ()
513 Panel::ComputeBounds ();
515 if (GetShowGridLines ()) {
516 extents = Rect (0,0,GetActualWidth (),GetActualHeight ());
517 bounds = IntersectBoundsWithClipPath (extents, false).Transform (&absolute_xform);
518 bounds_with_children = bounds_with_children.Union (bounds);
521 void
522 Grid::PostRender (cairo_t *cr, Region *region, bool front_to_back)
524 // render our chidren if not in front to back mode
525 if (!front_to_back) {
526 VisualTreeWalker walker = VisualTreeWalker (this, ZForward);
527 while (UIElement *child = walker.Step ())
528 child->DoRender (cr, region);
531 if (GetShowGridLines ()) {
532 double offset = 0;
533 double dash = 4;
534 ColumnDefinitionCollection *cols = GetColumnDefinitions ();
535 RowDefinitionCollection *rows = GetRowDefinitions ();
537 cairo_set_line_width(cr, 1.0);
538 // Initially render a blue color
539 cairo_set_dash (cr, &dash, 1, offset);
540 cairo_set_source_rgb (cr, 0.4, 0.4, 1.0);
542 // Draw gridlines between each pair of columns/rows
543 for (int count = 0; count < 2; count++) {
545 for (int i = 0, offset = 0; i < cols->GetCount () - 1; i++) {
546 ColumnDefinition *def = cols->GetValueAt (i)->AsColumnDefinition ();
547 offset += def->GetActualWidth ();
548 cairo_move_to (cr, offset, 0);
549 cairo_line_to (cr, offset, GetActualHeight ());
552 for (int i = 0, offset = 0; i < rows->GetCount () -1; i++) {
553 RowDefinition *def = rows->GetValueAt (i)->AsRowDefinition ();
554 offset += def->GetActualHeight ();
555 cairo_move_to (cr, 0, offset);
556 cairo_line_to (cr, GetActualWidth (), offset);
559 cairo_stroke (cr);
561 // For the second pass render a yellow color in the gaps between the previous dashes
562 cairo_set_dash (cr, &dash, 1, dash);
563 cairo_set_source_rgb (cr, 1.0, 1.0, 0.3);
567 // Chain up in front_to_back mode since we've alread rendered content
568 UIElement::PostRender (cr, region, true);
571 Size
572 Grid::ArrangeOverride (Size finalSize)
574 ColumnDefinitionCollection *columns = GetColumnDefinitions ();
575 RowDefinitionCollection *rows = GetRowDefinitions ();
577 int col_count = columns->GetCount ();
578 int row_count = rows->GetCount ();
580 HorizontalAlignment horiz = !isnan (GetWidth ()) ? HorizontalAlignmentStretch : GetHorizontalAlignment ();
581 VerticalAlignment vert = !isnan (GetHeight ()) ? VerticalAlignmentStretch : GetVerticalAlignment ();
583 Size total_consumed = Size (0, 0);
584 for (int c = 0; c < col_matrix_dim; c++)
585 total_consumed.width += col_matrix [c][c].size;
586 for (int r = 0; r < row_matrix_dim; r++)
587 total_consumed.height += row_matrix [r][r].size;
589 if (total_consumed.width != finalSize.width)
590 TryExpandStarCols (finalSize, false, false);
591 if (total_consumed.height != finalSize.height)
592 TryExpandStarRows (finalSize, false, false);
594 for (int c = 0; c < col_count; c++)
595 columns->GetValueAt (c)->AsColumnDefinition ()->SetActualWidth (col_matrix [c][c].size);
596 for (int r = 0; r < row_count; r++)
597 rows->GetValueAt (r)->AsRowDefinition ()->SetActualHeight (row_matrix [r][r].size);
599 bool first = true;
600 Size arranged = finalSize;
602 VisualTreeWalker walker = VisualTreeWalker (this);
603 while (UIElement *child = walker.Step ()) {
604 gint32 col = MIN (Grid::GetColumn (child), col_matrix_dim - 1);
605 gint32 row = MIN (Grid::GetRow (child), row_matrix_dim - 1);
606 gint32 colspan = MIN (Grid::GetColumnSpan (child), col_matrix_dim - col);
607 gint32 rowspan = MIN (Grid::GetRowSpan (child), row_matrix_dim - row);
609 Rect child_final = Rect (0, 0, 0, 0);
610 Size min_size;
611 Size max_size;
613 if (first) {
614 arranged = Size ();
615 first = false;
618 for (int c = 0; c < col + colspan; c++) {
619 if (c < col) {
620 child_final.x += col_matrix [c][c].size;
621 } else {
622 child_final.width += col_matrix [c][c].size;
624 min_size.width += col_matrix [c][c].min;
625 max_size.width += col_matrix [c][c].size;;
629 for (int r = 0; r < row + rowspan; r++) {
630 if (r < row) {
631 child_final.y += row_matrix [r][r].size;
632 } else {
633 child_final.height += row_matrix [r][r].size;
635 min_size.height += row_matrix [r][r].min;
636 max_size.height += row_matrix [r][r].max;
640 child->Arrange (child_final);
642 if (horiz == HorizontalAlignmentStretch)
643 arranged.width = MAX (child_final.x + child_final.width, finalSize.width);
644 else
645 arranged.width = MAX (child_final.x + child_final.width, arranged.width);
647 if (vert == VerticalAlignmentStretch)
648 arranged.height = MAX (child_final.y + child_final.height, finalSize.height);
649 else
650 arranged.height = MAX (child_final.y + child_final.height, arranged.height);
653 return arranged;
657 // ColumnDefinitionCollection
660 ColumnDefinitionCollection::ColumnDefinitionCollection ()
662 SetObjectType (Type::COLUMNDEFINITION_COLLECTION);
665 ColumnDefinitionCollection::~ColumnDefinitionCollection ()
669 bool
670 ColumnDefinitionCollection::AddedToCollection (Value *value, MoonError *error)
672 if (Contains (value)) {
673 MoonError::FillIn (error, MoonError::ARGUMENT, "ColumnDefinition is already a member of this collection.");
674 return false;
676 return DependencyObjectCollection::AddedToCollection (value, error);
680 // ColumnDefinition
683 ColumnDefinition::ColumnDefinition ()
685 SetObjectType (Type::COLUMNDEFINITION);
688 ColumnDefinition::~ColumnDefinition ()
693 // RowDefinitionCollection
696 RowDefinitionCollection::RowDefinitionCollection ()
698 SetObjectType (Type::ROWDEFINITION_COLLECTION);
701 RowDefinitionCollection::~RowDefinitionCollection ()
705 bool
706 RowDefinitionCollection::AddedToCollection (Value *value, MoonError *error)
708 if (Contains (value)) {
709 MoonError::FillIn (error, MoonError::ARGUMENT, "RowDefinition is already a member of this collection.");
710 return false;
712 return DependencyObjectCollection::AddedToCollection (value, error);
716 // RowDefinition
719 RowDefinition::RowDefinition ()
721 SetObjectType (Type::ROWDEFINITION);
724 RowDefinition::~RowDefinition ()
728 Segment::Segment ()
730 Init (0.0, 0.0, INFINITY, GridUnitTypePixel);
733 Segment::Segment (double size, double min, double max, GridUnitType type)
735 Init (size, min, max, type);
738 void
739 Segment::Init (double size, double min, double max, GridUnitType type)
741 this->max = max;
742 this->min = min;
743 this->stars = 0;
744 this->type = type;
746 this->size = Grid::Clamp (size, min, max);
749 GridWalker::GridWalker (Grid *grid, Segment **row_matrix, int row_count, Segment **col_matrix, int col_count)
751 has_auto_auto = false;
752 has_star_auto = false;
753 has_auto_star = false;
755 VisualTreeWalker walker (grid);
756 while (UIElement *child = walker.Step ()) {
757 bool star_col = false;
758 bool star_row = false;
759 bool auto_col = false;
760 bool auto_row = false;
762 gint32 col = MIN (Grid::GetColumn (child), col_count - 1);
763 gint32 row = MIN (Grid::GetRow (child), row_count - 1);
764 gint32 colspan = MIN (Grid::GetColumnSpan (child), col_count - col);
765 gint32 rowspan = MIN (Grid::GetRowSpan (child), row_count - row);
767 for (int r = row; r < row + rowspan; r++) {
768 star_row |= row_matrix [r][r].type == GridUnitTypeStar;
769 auto_row |= row_matrix [r][r].type == GridUnitTypeAuto;
771 for (int c = col; c < col + colspan; c++) {
772 star_col |= col_matrix [c][c].type == GridUnitTypeStar;
773 auto_col |= col_matrix [c][c].type == GridUnitTypeAuto;
776 has_auto_auto |= auto_row && auto_col && !star_row && !star_col;
777 has_star_auto |= star_row && auto_col;
778 has_auto_star |= auto_row && star_col;