/// <summary> /// Calculates a rectangle that contains the specified location /// </summary> /// <param name="location">The location to test against</param> /// <returns>If the specified location is enclosed within the rectangle, returned rectangle is /// identical to the current one. Otherwise, returned rectangle's edges are extended to ensure /// the location is enclosed by the returned rectangle</returns> public MatrixRect GrowTo(MatrixLoc location) { MatrixRect rect = this; if (location.Row < rect.Row) { rect.RowCount += rect.Row - location.Row; rect.Row = location.Row; } else if (location.Row >= rect.LastRow) { rect.RowCount += location.Row - rect.LastRow + 1; } if (location.Column < rect.Column) { rect.ColumnCount += rect.Column - location.Column; rect.Column = location.Column; } else if (location.Column >= rect.LastColumn) { rect.ColumnCount += location.Column - rect.LastColumn + 1; } return(rect); }
/// <summary> /// Resizes the container to the specified size /// </summary> /// <param name="newSize">New size to which the container is to be resized</param> /// <param name="justify">Resize justification, which indicates the edge at which widgets are to /// remain in their current positions (i.e. right justification will make the left edge move left/right /// while right edge's location stays constant)</param> public void Resize(MatrixSize newSize, WidgetContainerResizeJustify justify) { if (newSize.RowCount > 256 || newSize.ColumnCount > 256) { throw new ApplicationException(string.Format("Attemp to allocate too much ({0} x {1})", newSize.RowCount, newSize.ColumnCount)); } else if (newSize == this.Bounds.Size) { return; } Validate(); MatrixSize currentSize = this.Size; MatrixSize originShift = currentSize - newSize; if (!justify.HasFlag(WidgetContainerResizeJustify.Bottom)) { originShift.RowCount = 0; } if (!justify.HasFlag(WidgetContainerResizeJustify.Right)) { originShift.ColumnCount = 0; } MatrixRect newContainerBounds = new MatrixRect( _containerBounds.Location + originShift, newSize); // Cells in the intersection of original bounding rectangle and the new bounding // rectangle are the ones that will survive the resize operation. Once we identify // the intersection of the two rectangles, we need to iterate through the original // array and copy those cells into the new array MatrixRect existingCellBounds = _containerBounds.Intersect(newContainerBounds); // normalize existing cell bounding box around 0-based arrays. existingCellBounds.Location = new MatrixLoc(originShift.RowCount > 0 ? originShift.RowCount : 0, originShift.ColumnCount > 0 ? originShift.ColumnCount : 0); Array2D <WidgetData> newArray = new Array2D <WidgetData>(newSize); foreach (var loc in existingCellBounds) { newArray[loc - originShift] = _widgetArray[loc]; } _widgetArray = newArray; _containerBounds = newContainerBounds; this.IsDirty = true; Validate(); OnContainerResized(); Validate(); }
/// <summary> /// Returns a new rectangle which represents the intersection between current rectangle /// and the second one which is passed in /// </summary> /// <param name="other">The other rectangle to test against</param> /// <returns>A rectangle which represents the intersection</returns> public MatrixRect Intersect(MatrixRect other) { MatrixLoc topLeft = new MatrixLoc(Math.Max(this.Row, other.Row), Math.Max(this.Column, other.Column)); MatrixLoc bottomRight = new MatrixLoc(Math.Min(this.LastRow, other.LastRow), Math.Min(this.LastColumn, other.LastColumn)); MatrixSize size = bottomRight - topLeft; if (size.ColumnCount < 0) { size.ColumnCount = 0; } if (size.RowCount < 0) { size.RowCount = 0; } return(new MatrixRect(topLeft, size)); }
private void SetWidget(MatrixLoc location, WidgetData widget) { WidgetData removedWidget = null; Validate(); // the same widget is being inserted at the same spot where it is already located, // let not do anything and just exit if (widget != null && widget.Parent == this && widget.Location == location) { return; } MatrixRect neededBounds = _containerBounds.GrowTo(location); // If the cell being modified within the bounds of the current array, let's make sure // the existing cell is empty. Otherwise, we need to reallocate the array before // we can assign the widget to it. if (neededBounds.Size == _containerBounds.Size) { removedWidget = ClearWidget(location); } else if (widget != null) { WidgetContainerResizeJustify resizeJustify = (_containerBounds.Row == neededBounds.Row ? WidgetContainerResizeJustify.Top : WidgetContainerResizeJustify.Bottom) | (_containerBounds.Column == neededBounds.Column ? WidgetContainerResizeJustify.Left : WidgetContainerResizeJustify.Right); Resize(neededBounds.Size, resizeJustify); } Validate(); if (widget != null) { if (widget.HasOwner) { widget.Parent.Remove(widget); } _widgetArray[_containerBounds.ToIndex(location)] = widget; widget.SetOwner(this, location); widget.IsDirtyChanged += OnChildIsDirtyChanged; if (removedWidget != null) { OnWidgetReplaced(location, removedWidget, widget); removedWidget = null; } else { OnWidgetAdded(location, widget); } } if (removedWidget != null) { OnWidgetRemoved(location, removedWidget); } Validate(); IsDirty = true; }