/// <summary> /// Sets the bits in the region starting at location and having /// given width and height /// </summary> /// <param name="location">Top Left of the the Region</param> /// <param name="width">Width of the Region</param> /// <param name="height">Height of the Region</param> internal void SetRegion(MatrixCell location, int width, int height) { long targetRow = location.Row; long targetCol = location.Col; int targetWidth = width; int targetHeight = height; // Interchange Row & Column and width & height if the BitOrientation is Vertical if (BitOrientation == Orientation.Vertical) { targetRow = location.Col; targetCol = location.Row; targetWidth = height; targetHeight = width; } // Optimization: If the region is only 1 bit wide and high if ((targetWidth == 1) && (targetHeight == 1)) { this[targetRow, targetCol] = true; return; } for (var row = 0; row < targetHeight; row++) { for (var col = 0; col < targetWidth; col++) { this[targetRow + row, targetCol + col] = true; } } }
/// <summary> /// Tries to find an empty region of given width and height starting /// from the startIndex row. /// </summary> /// <param name="startIndex">The row to start the search from</param> /// <param name="width">Width of the Region</param> /// <param name="height">Height of the Region</param> /// <param name="cell">The cell location</param> /// <returns>true if successful otherwise false</returns> internal bool TryFindRegion(long startIndex, int width, int height, out MatrixCell cell) { cell = MatrixCell.InvalidCell; // Swap width and height if the BitOrientation is Vertical if ((BitOrientation == Orientation.Vertical) && (width != height)) { var temp = width; width = height; height = temp; } if ((startIndex < 0 || startIndex >= _rowsInternal) || (startIndex + (height - 1) >= _rowsInternal) || ((width < 1) || (width > MaxBitsPerItem)) || (width > _columnsInternal)) { return(false); } // Optimization: If both width and height are 1 then use a faster // loop to find the next empty cell if ((width == 1) && (height == 1)) { for (var row = startIndex; row < _rowsInternal; row++) { for (var col = 0; col < _columnsInternal; col++) { // Is the cell unset? if (this[row, col]) { continue; } // Swap the row and col values if the BitOrientation is Vertical cell = (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, col) : new MatrixCell(col, row); return(true); } } // If the code has reached here it means that it did not find any unset // bit in the entire matrix. Return false from here. return(false); } var mask = (((UInt64)1) << width) - 1; for (var row = startIndex; row < (_rowsInternal - height + 1); row++) { // Quickcheck: If the row is empty then no need to check individual bits in the row if (!RowHasData(row)) { // Current column has no bits set. Check the bits in the next (height - 1) // rows starting at the same column position (0) to check if they are unset if (!AnyBitsSetInRegion(row, 0, width, height)) { // Swap the row and col values if the BitOrientation is Vertical cell = (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, 0) : new MatrixCell(0, row); return(true); } } // Row is not empty and has some set bits. Check if there are // 'width' continuous unset bits in the column. // 1. Check the first 'width' bits var rowData = 0UL; var col = 0; for (; col < width; col++) { rowData <<= 1; rowData |= this[row, col] ? 1UL : 0UL; } if ((rowData & mask) == 0) { // Current column has 'width' unset bits starting from 0 position. // Check the bits in the next (height - 1) rows starting at the same // column position (0) to check if they are unset if (!AnyBitsSetInRegion(row, 0, width, height)) { // Swap the row and col values if the BitOrientation is Vertical cell = (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, 0) : new MatrixCell(0, row); return(true); } } // Shift the rowData by 1 bit and clear the (width + 1)th most significant bit. // This way a set of 'width' continuous bits is matched against the mask // to check if all the bits are zero. var colBegin = 0; while (col < _columnsInternal) { rowData <<= 1; rowData &= mask; rowData |= this[row, col++] ? 1UL : 0UL; colBegin++; if ((rowData & mask) != 0) { continue; } // Current column has 'width' unset bits starting from colBegin position. // Check the bits in the next (height - 1) rows starting at the same // column position (colBegin) to check if they are unset if (AnyBitsSetInRegion(row, colBegin, width, height)) { continue; } // Swap the row and col values if the BitOrientation is Vertical cell = (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, colBegin) : new MatrixCell(colBegin, row); return(true); } } return(false); }
/// <summary> /// Checks if the given UIElement can fit in the given cell location /// </summary> /// <param name="element">UIElement</param> /// <param name="cell">Cell location</param> /// <returns>True if the UIElement fits otherwise False.</returns> private bool IsValidCellPosition(UIElement element, MatrixCell cell) { if (!cell.IsValid()) return false; var info = _fluidBits[element]; return (cell.Row + info.Height <= _maxCellRows) && (cell.Col + info.Width <= _maxCellCols); }
/// <summary> /// Gets the list of cell locations which are vacated when the given element is /// moved to the given cell location. /// </summary> /// <param name="element">UIElement</param> /// <param name="cell">Cell location</param> /// <returns>List of cell locations</returns> private List<MatrixCell> GetVacatedCells(UIElement element, MatrixCell cell) { var result = new List<MatrixCell>(); var info = _fluidBits[element]; var baseRow = info.Row; var baseCol = info.Col; var width = info.Width; var height = info.Height; var minRow = cell.Row; var maxRow = minRow + height; var minCol = cell.Col; var maxCol = minCol + width; for (var i = 0; i < height; i++) { for (var j = 0; j < width; j++) { var row = baseRow + i; var col = baseCol + j; var isInside = (row >= minRow) && (row < maxRow) && (col >= minCol) && (col < maxCol); if (!isInside) result.Add(new MatrixCell(row, col)); } } return result; }
/// <summary> /// Gets the list of children overlapped by the given element when it is /// moved to the given cell location. /// </summary> /// <param name="element">UIElement</param> /// <param name="cell">Cell location</param> /// <returns>List of overlapped UIElements</returns> private List<UIElement> GetOverlappedChildren(UIElement element, MatrixCell cell) { var result = new List<UIElement>(); var info = _fluidBits[element]; for (var row = 0; row < info.Height; row++) { for (var col = 0; col < info.Width; col++) { var item = _fluidBits.Where(t => t.Value.Contains(cell.Row + row, cell.Col + col)).Select(t => t.Key).FirstOrDefault(); if ((item != null) && !ReferenceEquals(item, element) && (!result.Contains(item))) { result.Add(item); } } } return result; }
/// <summary> /// Tries to find an empty region of given width and height starting /// from the startIndex row. /// </summary> /// <param name="startIndex">The row to start the search from</param> /// <param name="width">Width of the Region</param> /// <param name="height">Height of the Region</param> /// <param name="cell">The cell location</param> /// <returns>true if successful otherwise false</returns> internal bool TryFindRegion(long startIndex, int width, int height, out MatrixCell cell) { cell = MatrixCell.InvalidCell; // Swap width and height if the BitOrientation is Vertical if ((BitOrientation == Orientation.Vertical) && (width != height)) { var temp = width; width = height; height = temp; } if ((startIndex < 0 || startIndex >= _rowsInternal) || (startIndex + (height - 1) >= _rowsInternal) || ((width < 1) || (width > MaxBitsPerItem)) || (width > _columnsInternal)) return false; // Optimization: If both width and height are 1 then use a faster // loop to find the next empty cell if ((width == 1) && (height == 1)) { for (var row = startIndex; row < _rowsInternal; row++) { for (var col = 0; col < _columnsInternal; col++) { // Is the cell unset? if (this[row, col]) continue; // Swap the row and col values if the BitOrientation is Vertical cell = (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, col) : new MatrixCell(col, row); return true; } } // If the code has reached here it means that it did not find any unset // bit in the entire matrix. Return false from here. return false; } var mask = (((UInt64)1) << width) - 1; for (var row = startIndex; row < (_rowsInternal - height + 1); row++) { // Quickcheck: If the row is empty then no need to check individual bits in the row if (!RowHasData(row)) { // Current column has no bits set. Check the bits in the next (height - 1) // rows starting at the same column position (0) to check if they are unset if (!AnyBitsSetInRegion(row, 0, width, height)) { // Swap the row and col values if the BitOrientation is Vertical cell = (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, 0) : new MatrixCell(0, row); return true; } } // Row is not empty and has some set bits. Check if there are // 'width' continuous unset bits in the column. // 1. Check the first 'width' bits var rowData = 0UL; var col = 0; for (; col < width; col++) { rowData <<= 1; rowData |= this[row, col] ? 1UL : 0UL; } if ((rowData & mask) == 0) { // Current column has 'width' unset bits starting from 0 position. // Check the bits in the next (height - 1) rows starting at the same // column position (0) to check if they are unset if (!AnyBitsSetInRegion(row, 0, width, height)) { // Swap the row and col values if the BitOrientation is Vertical cell = (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, 0) : new MatrixCell(0, row); return true; } } // Shift the rowData by 1 bit and clear the (width + 1)th most significant bit. // This way a set of 'width' continuous bits is matched against the mask // to check if all the bits are zero. var colBegin = 0; while (col < _columnsInternal) { rowData <<= 1; rowData &= mask; rowData |= this[row, col++] ? 1UL : 0UL; colBegin++; if ((rowData & mask) != 0) continue; // Current column has 'width' unset bits starting from colBegin position. // Check the bits in the next (height - 1) rows starting at the same // column position (colBegin) to check if they are unset if (AnyBitsSetInRegion(row, colBegin, width, height)) continue; // Swap the row and col values if the BitOrientation is Vertical cell = (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, colBegin) : new MatrixCell(colBegin, row); return true; } } return false; }
/// <summary> /// Sets the bits in the region starting at location and having /// given width and height /// </summary> /// <param name="location">Top Left of the the Region</param> /// <param name="width">Width of the Region</param> /// <param name="height">Height of the Region</param> internal void SetRegion(MatrixCell location, int width, int height) { long targetRow = location.Row; long targetCol = location.Col; int targetWidth = width; int targetHeight = height; // Interchange Row & Column and width & height if the BitOrientation is Vertical if (BitOrientation == Orientation.Vertical) { targetRow = location.Col; targetCol = location.Row; targetWidth = height; targetHeight = width; } // Optimization: If the region is only 1 bit wide and high if ((targetWidth == 1) && (targetHeight == 1)) { this[targetRow, targetCol] = true; return; } for (var row = 0; row < targetHeight; row++) { for (var col = 0; col < targetWidth; col++) { this[targetRow + row, targetCol + col] = true; } } }