diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridDropHandler.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridDropHandler.java | 840 |
1 files changed, 0 insertions, 840 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridDropHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridDropHandler.java deleted file mode 100644 index 8bdb56bfe..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridDropHandler.java +++ /dev/null @@ -1,840 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.eclipse.org/org/documents/epl-v10.php - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.ide.common.layout.grid; - -import static com.android.SdkConstants.ATTR_COLUMN_COUNT; -import static com.android.SdkConstants.ATTR_LAYOUT_COLUMN; -import static com.android.SdkConstants.ATTR_LAYOUT_COLUMN_SPAN; -import static com.android.SdkConstants.ATTR_LAYOUT_GRAVITY; -import static com.android.SdkConstants.ATTR_LAYOUT_ROW; -import static com.android.SdkConstants.ATTR_LAYOUT_ROW_SPAN; -import static com.android.ide.common.layout.GravityHelper.getGravity; -import static com.android.ide.common.layout.GridLayoutRule.GRID_SIZE; -import static com.android.ide.common.layout.GridLayoutRule.MARGIN_SIZE; -import static com.android.ide.common.layout.GridLayoutRule.MAX_CELL_DIFFERENCE; -import static com.android.ide.common.layout.GridLayoutRule.SHORT_GAP_DP; -import static com.android.ide.common.layout.grid.GridModel.UNDEFINED; -import static java.lang.Math.abs; - -import com.android.ide.common.api.DropFeedback; -import com.android.ide.common.api.IDragElement; -import com.android.ide.common.api.INode; -import com.android.ide.common.api.IViewMetadata; -import com.android.ide.common.api.Margins; -import com.android.ide.common.api.Point; -import com.android.ide.common.api.Rect; -import com.android.ide.common.api.SegmentType; -import com.android.ide.common.layout.BaseLayoutRule; -import com.android.ide.common.layout.GravityHelper; -import com.android.ide.common.layout.GridLayoutRule; -import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Locale; - -/** - * The {@link GridDropHandler} handles drag and drop operations into and within a - * GridLayout, computing guidelines, handling drops to edit the grid model, and so on. - */ -public class GridDropHandler { - private final GridModel mGrid; - private final GridLayoutRule mRule; - private GridMatch mColumnMatch; - private GridMatch mRowMatch; - - /** - * Creates a new {@link GridDropHandler} for - * @param gridLayoutRule the corresponding {@link GridLayoutRule} - * @param layout the GridLayout node - * @param view the view instance of the grid layout receiving the drop - */ - public GridDropHandler(GridLayoutRule gridLayoutRule, INode layout, Object view) { - mRule = gridLayoutRule; - mGrid = GridModel.get(mRule.getRulesEngine(), layout, view); - } - - /** - * Computes the best horizontal and vertical matches for a drag to the given position. - * - * @param feedback a {@link DropFeedback} object containing drag state like the drag - * bounds and the drag baseline - * @param p the mouse position - */ - public void computeMatches(DropFeedback feedback, Point p) { - mRowMatch = mColumnMatch = null; - feedback.tooltip = null; - - Rect bounds = mGrid.layout.getBounds(); - int x1 = p.x; - int y1 = p.y; - - Rect dragBounds = feedback.dragBounds; - int w = dragBounds != null ? dragBounds.w : 0; - int h = dragBounds != null ? dragBounds.h : 0; - if (!GridLayoutRule.sGridMode) { - if (dragBounds != null) { - // Sometimes the items are centered under the mouse so - // offset by the top left corner distance - x1 += dragBounds.x; - y1 += dragBounds.y; - } - - int x2 = x1 + w; - int y2 = y1 + h; - - if (x2 < bounds.x || y2 < bounds.y || x1 > bounds.x2() || y1 > bounds.y2()) { - return; - } - - List<GridMatch> columnMatches = new ArrayList<GridMatch>(); - List<GridMatch> rowMatches = new ArrayList<GridMatch>(); - int max = BaseLayoutRule.getMaxMatchDistance(); - - // Column matches: - addLeftSideMatch(x1, columnMatches, max); - addRightSideMatch(x2, columnMatches, max); - addCenterColumnMatch(bounds, x1, y1, x2, y2, columnMatches, max); - - // Row matches: - int row = (mGrid.getViewCount() == 0) ? 0 : mGrid.getClosestRow(y1); - int rowY = mGrid.getRowY(row); - addTopMatch(y1, rowMatches, max, row, rowY); - addBaselineMatch(feedback.dragBaseline, y1, rowMatches, max, row, rowY); - addBottomMatch(y2, rowMatches, max); - - // Look for gap-matches: Predefined spacing between widgets. - // TODO: Make this use metadata for predefined spacing between - // pairs of types of components. For example, buttons have certain - // inserts in their 9-patch files (depending on the theme) that should - // be considered and subtracted from the overall proposed distance! - addColumnGapMatch(bounds, x1, x2, columnMatches, max); - addRowGapMatch(bounds, y1, y2, rowMatches, max); - - // Fallback: Split existing cell. Also do snap-to-grid. - if (GridLayoutRule.sSnapToGrid) { - x1 = ((x1 - MARGIN_SIZE - bounds.x) / GRID_SIZE) * GRID_SIZE - + MARGIN_SIZE + bounds.x; - y1 = ((y1 - MARGIN_SIZE - bounds.y) / GRID_SIZE) * GRID_SIZE - + MARGIN_SIZE + bounds.y; - x2 = x1 + w; - y2 = y1 + h; - } - - - if (columnMatches.size() == 0 && x1 >= bounds.x) { - // Split the current cell since we have no matches - // TODO: Decide whether it should be gravity left or right... - columnMatches.add(new GridMatch(SegmentType.LEFT, 0, x1, mGrid.getColumn(x1), - true /* createCell */, UNDEFINED)); - } - if (rowMatches.size() == 0 && y1 >= bounds.y) { - rowMatches.add(new GridMatch(SegmentType.TOP, 0, y1, mGrid.getRow(y1), - true /* createCell */, UNDEFINED)); - } - - // Pick best matches - Collections.sort(rowMatches); - Collections.sort(columnMatches); - - mColumnMatch = null; - mRowMatch = null; - String columnDescription = null; - String rowDescription = null; - if (columnMatches.size() > 0) { - mColumnMatch = columnMatches.get(0); - columnDescription = mColumnMatch.getDisplayName(mGrid.layout); - } - if (rowMatches.size() > 0) { - mRowMatch = rowMatches.get(0); - rowDescription = mRowMatch.getDisplayName(mGrid.layout); - } - - if (columnDescription != null && rowDescription != null) { - feedback.tooltip = columnDescription + '\n' + rowDescription; - } - - feedback.invalidTarget = mColumnMatch == null || mRowMatch == null; - } else { - // Find which cell we're inside. - - // TODO: Find out where within the cell we are, and offer to tweak the gravity - // based on the position. - int column = mGrid.getColumn(x1); - int row = mGrid.getRow(y1); - - int leftDistance = mGrid.getColumnDistance(column, x1); - int rightDistance = mGrid.getColumnDistance(column + 1, x1); - int topDistance = mGrid.getRowDistance(row, y1); - int bottomDistance = mGrid.getRowDistance(row + 1, y1); - - int SLOP = 2; - int radius = mRule.getNewCellSize(); - if (rightDistance < radius + SLOP) { - column = Math.min(column + 1, mGrid.actualColumnCount); - leftDistance = rightDistance; - } - if (bottomDistance < radius + SLOP) { - row = Math.min(row + 1, mGrid.actualRowCount); - topDistance = bottomDistance; - } - - boolean createColumn = leftDistance < radius + SLOP; - boolean createRow = topDistance < radius + SLOP; - if (x1 >= bounds.x2()) { - createColumn = true; - } - if (y1 >= bounds.y2()) { - createRow = true; - } - - int cellWidth = leftDistance + rightDistance; - int cellHeight = topDistance + bottomDistance; - SegmentType horizontalType = SegmentType.LEFT; - SegmentType verticalType = SegmentType.TOP; - int minDistance = 10; // Don't center or right/bottom align in tiny cells - if (!createColumn && leftDistance > minDistance - && dragBounds != null && dragBounds.w < cellWidth - 10) { - if (rightDistance < leftDistance) { - horizontalType = SegmentType.RIGHT; - } - - int centerDistance = Math.abs(cellWidth / 2 - leftDistance); - if (centerDistance < leftDistance / 2 && centerDistance < rightDistance / 2) { - horizontalType = SegmentType.CENTER_HORIZONTAL; - } - } - if (!createRow && topDistance > minDistance - && dragBounds != null && dragBounds.h < cellHeight - 10) { - if (bottomDistance < topDistance) { - verticalType = SegmentType.BOTTOM; - } - int centerDistance = Math.abs(cellHeight / 2 - topDistance); - if (centerDistance < topDistance / 2 && centerDistance < bottomDistance / 2) { - verticalType = SegmentType.CENTER_VERTICAL; - } - } - - mColumnMatch = new GridMatch(horizontalType, 0, x1, column, createColumn, 0); - mRowMatch = new GridMatch(verticalType, 0, y1, row, createRow, 0); - - StringBuilder description = new StringBuilder(50); - String rowString = Integer.toString(mColumnMatch.cellIndex + 1); - String columnString = Integer.toString(mRowMatch.cellIndex + 1); - if (mRowMatch.createCell && mRowMatch.cellIndex < mGrid.actualRowCount) { - description.append(String.format("Shift row %1$d down", mRowMatch.cellIndex + 1)); - description.append('\n'); - } - if (mColumnMatch.createCell && mColumnMatch.cellIndex < mGrid.actualColumnCount) { - description.append(String.format("Shift column %1$d right", - mColumnMatch.cellIndex + 1)); - description.append('\n'); - } - description.append(String.format("Insert into cell (%1$s,%2$s)", - rowString, columnString)); - description.append('\n'); - description.append(String.format("Align %1$s, %2$s", - horizontalType.name().toLowerCase(Locale.US), - verticalType.name().toLowerCase(Locale.US))); - feedback.tooltip = description.toString(); - } - } - - /** - * Adds a match to align the left edge with some other edge. - */ - private void addLeftSideMatch(int x1, List<GridMatch> columnMatches, int max) { - int column = (mGrid.getViewCount() == 0) ? 0 : mGrid.getClosestColumn(x1); - int columnX = mGrid.getColumnX(column); - int distance = abs(columnX - x1); - if (distance <= max) { - columnMatches.add(new GridMatch(SegmentType.LEFT, distance, columnX, column, - false, UNDEFINED)); - } - } - - /** - * Adds a match to align the right edge with some other edge. - */ - private void addRightSideMatch(int x2, List<GridMatch> columnMatches, int max) { - // TODO: Only match the right hand side if the drag bounds fit fully within the - // cell! Ditto for match below. - int columnRight = (mGrid.getViewCount() == 0) ? 0 : mGrid.getClosestColumn(x2); - int rightDistance = mGrid.getColumnDistance(columnRight, x2); - if (rightDistance < max) { - int columnX = mGrid.getColumnX(columnRight); - if (columnX > mGrid.layout.getBounds().x) { - columnMatches.add(new GridMatch(SegmentType.RIGHT, rightDistance, columnX, - columnRight, false, UNDEFINED)); - } - } - } - - /** - * Adds a horizontal match with the center axis of the GridLayout - */ - private void addCenterColumnMatch(Rect bounds, int x1, int y1, int x2, int y2, - List<GridMatch> columnMatches, int max) { - Collection<INode> intersectsRow = mGrid.getIntersectsRow(y1, y2); - if (intersectsRow.size() == 0) { - // Offer centering on this row since there isn't anything there - int matchedLine = bounds.centerX(); - int distance = abs((x1 + x2) / 2 - matchedLine); - if (distance <= 2 * max) { - boolean createCell = false; // always just put in column 0 - columnMatches.add(new GridMatch(SegmentType.CENTER_HORIZONTAL, distance, - matchedLine, 0 /* column */, createCell, UNDEFINED)); - } - } - } - - /** - * Adds a match to align the top edge with some other edge. - */ - private void addTopMatch(int y1, List<GridMatch> rowMatches, int max, int row, int rowY) { - int distance = mGrid.getRowDistance(row, y1); - if (distance <= max) { - rowMatches.add(new GridMatch(SegmentType.TOP, distance, rowY, row, false, - UNDEFINED)); - } - } - - /** - * Adds a match to align the bottom edge with some other edge. - */ - private void addBottomMatch(int y2, List<GridMatch> rowMatches, int max) { - int rowBottom = (mGrid.getViewCount() == 0) ? 0 : mGrid.getClosestRow(y2); - int distance = mGrid.getRowDistance(rowBottom, y2); - if (distance < max) { - int rowY = mGrid.getRowY(rowBottom); - if (rowY > mGrid.layout.getBounds().y) { - rowMatches.add(new GridMatch(SegmentType.BOTTOM, distance, rowY, - rowBottom, false, UNDEFINED)); - } - } - } - - /** - * Adds a baseline match, if applicable. - */ - private void addBaselineMatch(int dragBaseline, int y1, List<GridMatch> rowMatches, int max, - int row, int rowY) { - int dragBaselineY = y1 + dragBaseline; - int rowBaseline = mGrid.getBaseline(row); - if (rowBaseline != -1) { - int rowBaselineY = rowY + rowBaseline; - int distance = abs(dragBaselineY - rowBaselineY); - if (distance < max) { - rowMatches.add(new GridMatch(SegmentType.BASELINE, distance, rowBaselineY, row, - false, UNDEFINED)); - } - } - } - - /** - * Computes a horizontal "gap" match - a preferred distance from the nearest edge, - * including margin edges - */ - private void addColumnGapMatch(Rect bounds, int x1, int x2, List<GridMatch> columnMatches, - int max) { - if (x1 < bounds.x + MARGIN_SIZE + max) { - int matchedLine = bounds.x + MARGIN_SIZE; - int distance = abs(matchedLine - x1); - if (distance <= max) { - boolean createCell = mGrid.getColumnX(mGrid.getColumn(matchedLine)) != matchedLine; - columnMatches.add(new GridMatch(SegmentType.LEFT, distance, matchedLine, - 0, createCell, MARGIN_SIZE)); - } - } else if (x2 > bounds.x2() - MARGIN_SIZE - max) { - int matchedLine = bounds.x2() - MARGIN_SIZE; - int distance = abs(matchedLine - x2); - if (distance <= max) { - // This does not yet work properly; we need to use columnWeights to achieve this - //boolean createCell = mGrid.getColumnX(mGrid.getColumn(matchedLine)) != matchedLine; - //columnMatches.add(new GridMatch(SegmentType.RIGHT, distance, matchedLine, - // mGrid.actualColumnCount - 1, createCell, MARGIN_SIZE)); - } - } else { - int columnRight = mGrid.getColumn(x1 - SHORT_GAP_DP); - int columnX = mGrid.getColumnMaxX(columnRight); - int matchedLine = columnX + SHORT_GAP_DP; - int distance = abs(matchedLine - x1); - if (distance <= max) { - boolean createCell = mGrid.getColumnX(mGrid.getColumn(matchedLine)) != matchedLine; - columnMatches.add(new GridMatch(SegmentType.LEFT, distance, matchedLine, - columnRight, createCell, SHORT_GAP_DP)); - } - - // Add a column directly adjacent (no gap) - columnRight = mGrid.getColumn(x1); - columnX = mGrid.getColumnMaxX(columnRight); - matchedLine = columnX; - distance = abs(matchedLine - x1); - - // Let's say you have this arrangement: - // [button1][button2] - // This is two columns, where the right hand side edge of column 1 is - // flush with the left side edge of column 2, because in fact the width of - // button1 is what defines the width of column 1, and that in turn is what - // defines the left side position of column 2. - // - // In this case we don't want to consider inserting a new column at the - // right hand side of button1 a better match than matching left on column 2. - // Therefore, to ensure that this doesn't happen, we "penalize" right column - // matches such that they don't get preferential treatment when the matching - // line is on the left side of the column. - distance += 2; - - if (distance <= max) { - boolean createCell = mGrid.getColumnX(mGrid.getColumn(matchedLine)) != matchedLine; - columnMatches.add(new GridMatch(SegmentType.LEFT, distance, matchedLine, - columnRight, createCell, 0)); - } - } - } - - /** - * Computes a vertical "gap" match - a preferred distance from the nearest edge, - * including margin edges - */ - private void addRowGapMatch(Rect bounds, int y1, int y2, List<GridMatch> rowMatches, int max) { - if (y1 < bounds.y + MARGIN_SIZE + max) { - int matchedLine = bounds.y + MARGIN_SIZE; - int distance = abs(matchedLine - y1); - if (distance <= max) { - boolean createCell = mGrid.getRowY(mGrid.getRow(matchedLine)) != matchedLine; - rowMatches.add(new GridMatch(SegmentType.TOP, distance, matchedLine, - 0, createCell, MARGIN_SIZE)); - } - } else if (y2 > bounds.y2() - MARGIN_SIZE - max) { - int matchedLine = bounds.y2() - MARGIN_SIZE; - int distance = abs(matchedLine - y2); - if (distance <= max) { - // This does not yet work properly; we need to use columnWeights to achieve this - //boolean createCell = mGrid.getRowY(mGrid.getRow(matchedLine)) != matchedLine; - //rowMatches.add(new GridMatch(SegmentType.BOTTOM, distance, matchedLine, - // mGrid.actualRowCount - 1, createCell, MARGIN_SIZE)); - } - } else { - int rowBottom = mGrid.getRow(y1 - SHORT_GAP_DP); - int rowY = mGrid.getRowMaxY(rowBottom); - int matchedLine = rowY + SHORT_GAP_DP; - int distance = abs(matchedLine - y1); - if (distance <= max) { - boolean createCell = mGrid.getRowY(mGrid.getRow(matchedLine)) != matchedLine; - rowMatches.add(new GridMatch(SegmentType.TOP, distance, matchedLine, - rowBottom, createCell, SHORT_GAP_DP)); - } - - // Add a row directly adjacent (no gap) - rowBottom = mGrid.getRow(y1); - rowY = mGrid.getRowMaxY(rowBottom); - matchedLine = rowY; - distance = abs(matchedLine - y1); - distance += 2; // See explanation in addColumnGapMatch - if (distance <= max) { - boolean createCell = mGrid.getRowY(mGrid.getRow(matchedLine)) != matchedLine; - rowMatches.add(new GridMatch(SegmentType.TOP, distance, matchedLine, - rowBottom, createCell, 0)); - } - - } - } - - /** - * Called when a node is dropped in free-form mode. This will insert the dragged - * element into the grid and returns the newly created node. - * - * @param targetNode the GridLayout node - * @param element the dragged element - * @return the newly created {@link INode} - */ - public INode handleFreeFormDrop(INode targetNode, IDragElement element) { - assert mRowMatch != null; - assert mColumnMatch != null; - - String fqcn = element.getFqcn(); - - INode newChild = null; - - Rect bounds = element.getBounds(); - int row = mRowMatch.cellIndex; - int column = mColumnMatch.cellIndex; - - if (targetNode.getChildren().length == 0) { - // - // Set up the initial structure: - // - // - // Fixed Fixed - // Size Size - // Column Expanding Column Column - // +-----+-------------------------------+-----+ - // | | | | - // | 0,0 | 0,1 | 0,2 | Fixed Size Row - // | | | | - // +-----+-------------------------------+-----+ - // | | | | - // | | | | - // | | | | - // | 1,0 | 1,1 | 1,2 | Expanding Row - // | | | | - // | | | | - // | | | | - // +-----+-------------------------------+-----+ - // | | | | - // | 2,0 | 2,1 | 2,2 | Fixed Size Row - // | | | | - // +-----+-------------------------------+-----+ - // - // This is implemented in GridLayout by the following grid, where - // SC1 has columnWeight=1 and SR1 has rowWeight=1. - // (SC=Space for Column, SR=Space for Row) - // - // +------+-------------------------------+------+ - // | | | | - // | SCR0 | SC1 | SC2 | - // | | | | - // +------+-------------------------------+------+ - // | | | | - // | | | | - // | | | | - // | SR1 | | | - // | | | | - // | | | | - // | | | | - // +------+-------------------------------+------+ - // | | | | - // | SR2 | | | - // | | | | - // +------+-------------------------------+------+ - // - // Note that when we split columns and rows here, if splitting the expanding - // row or column then the row or column weight should be moved to the right or - // bottom half! - - - //int columnX = mGrid.getColumnX(column); - //int rowY = mGrid.getRowY(row); - - mGrid.setGridAttribute(targetNode, ATTR_COLUMN_COUNT, 2); - //mGrid.setGridAttribute(targetNode, ATTR_COLUMN_COUNT, 3); - //INode scr0 = addSpacer(targetNode, -1, 0, 0, 1, 1); - //INode sc1 = addSpacer(targetNode, -1, 0, 1, 0, 0); - //INode sc2 = addSpacer(targetNode, -1, 0, 2, 1, 0); - //INode sr1 = addSpacer(targetNode, -1, 1, 0, 0, 0); - //INode sr2 = addSpacer(targetNode, -1, 2, 0, 0, 1); - //mGrid.setGridAttribute(sc1, ATTR_LAYOUT_GRAVITY, VALUE_FILL_HORIZONTAL); - //mGrid.setGridAttribute(sr1, ATTR_LAYOUT_GRAVITY, VALUE_FILL_VERTICAL); - // - //mGrid.loadFromXml(); - //column = mGrid.getColumn(columnX); - //row = mGrid.getRow(rowY); - } - - int startX, endX; - if (mColumnMatch.type == SegmentType.RIGHT) { - endX = mColumnMatch.matchedLine - 1; - startX = endX - bounds.w; - column = mGrid.getColumn(startX); - } else { - startX = mColumnMatch.matchedLine; // TODO: What happens on type=RIGHT? - endX = startX + bounds.w; - } - int startY, endY; - if (mRowMatch.type == SegmentType.BOTTOM) { - endY = mRowMatch.matchedLine - 1; - startY = endY - bounds.h; - row = mGrid.getRow(startY); - } else if (mRowMatch.type == SegmentType.BASELINE) { - // TODO: The rowSpan should always be 1 for baseline alignments, since - // otherwise the alignment won't work! - startY = endY = mRowMatch.matchedLine; - } else { - startY = mRowMatch.matchedLine; - endY = startY + bounds.h; - } - int endColumn = mGrid.getColumn(endX); - int endRow = mGrid.getRow(endY); - int columnSpan = endColumn - column + 1; - int rowSpan = endRow - row + 1; - - // Make sure my math was right: - assert mRowMatch.type != SegmentType.BASELINE || rowSpan == 1 : rowSpan; - - // If the item almost fits into the row (at most N % bigger) then just enlarge - // the row; don't add a rowspan since that will defeat baseline alignment etc - if (!mRowMatch.createCell && bounds.h <= MAX_CELL_DIFFERENCE * mGrid.getRowHeight( - mRowMatch.type == SegmentType.BOTTOM ? endRow : row, 1)) { - if (mRowMatch.type == SegmentType.BOTTOM) { - row += rowSpan - 1; - } - rowSpan = 1; - } - if (!mColumnMatch.createCell && bounds.w <= MAX_CELL_DIFFERENCE * mGrid.getColumnWidth( - mColumnMatch.type == SegmentType.RIGHT ? endColumn : column, 1)) { - if (mColumnMatch.type == SegmentType.RIGHT) { - column += columnSpan - 1; - } - columnSpan = 1; - } - - if (mColumnMatch.type == SegmentType.CENTER_HORIZONTAL) { - column = 0; - columnSpan = mGrid.actualColumnCount; - } - - // Temporary: Ensure we don't get in trouble with implicit positions - mGrid.applyPositionAttributes(); - - // Split cells to make a new column - if (mColumnMatch.createCell) { - int columnWidthPx = mGrid.getColumnDistance(column, mColumnMatch.matchedLine); - //assert columnWidthPx == columnMatch.distance; // TBD? IF so simplify - int columnWidthDp = mRule.getRulesEngine().pxToDp(columnWidthPx); - - int maxX = mGrid.getColumnMaxX(column); - boolean insertMarginColumn = false; - if (mColumnMatch.margin == 0) { - columnWidthDp = 0; - } else if (mColumnMatch.margin != UNDEFINED) { - int distance = abs(mColumnMatch.matchedLine - (maxX + mColumnMatch.margin)); - insertMarginColumn = column > 0 && distance < 2; - if (insertMarginColumn) { - int margin = mColumnMatch.margin; - if (ViewMetadataRepository.INSETS_SUPPORTED) { - IViewMetadata metadata = mRule.getRulesEngine().getMetadata(fqcn); - if (metadata != null) { - Margins insets = metadata.getInsets(); - if (insets != null) { - // TODO: - // Consider left or right side attachment - // TODO: Also consider inset of element on cell to the left - margin -= insets.left; - } - } - } - - columnWidthDp = mRule.getRulesEngine().pxToDp(margin); - } - } - - column++; - mGrid.splitColumn(column, insertMarginColumn, columnWidthDp, mColumnMatch.matchedLine); - if (insertMarginColumn) { - column++; - } - } - - // Split cells to make a new row - if (mRowMatch.createCell) { - int rowHeightPx = mGrid.getRowDistance(row, mRowMatch.matchedLine); - //assert rowHeightPx == rowMatch.distance; // TBD? If so simplify - int rowHeightDp = mRule.getRulesEngine().pxToDp(rowHeightPx); - - int maxY = mGrid.getRowMaxY(row); - boolean insertMarginRow = false; - if (mRowMatch.margin == 0) { - rowHeightDp = 0; - } else if (mRowMatch.margin != UNDEFINED) { - int distance = abs(mRowMatch.matchedLine - (maxY + mRowMatch.margin)); - insertMarginRow = row > 0 && distance < 2; - if (insertMarginRow) { - int margin = mRowMatch.margin; - IViewMetadata metadata = mRule.getRulesEngine().getMetadata(element.getFqcn()); - if (metadata != null) { - Margins insets = metadata.getInsets(); - if (insets != null) { - // TODO: - // Consider left or right side attachment - // TODO: Also consider inset of element on cell to the left - margin -= insets.top; - } - } - - rowHeightDp = mRule.getRulesEngine().pxToDp(margin); - } - } - - row++; - mGrid.splitRow(row, insertMarginRow, rowHeightDp, mRowMatch.matchedLine); - if (insertMarginRow) { - row++; - } - } - - // Figure out where to insert the new child - - int index = mGrid.getInsertIndex(row, column); - if (index == -1) { - // Couldn't find a later place to insert - newChild = targetNode.appendChild(fqcn); - } else { - GridModel.ViewData next = mGrid.getView(index); - - newChild = targetNode.insertChildAt(fqcn, index); - - // Must also apply positions to the following child to ensure - // that the new child doesn't affect the implicit numbering! - // TODO: We can later check whether the implied number is equal to - // what it already is such that we don't need this - next.applyPositionAttributes(); - } - - // Set the cell position (gravity) of the new widget - int gravity = 0; - if (mColumnMatch.type == SegmentType.RIGHT) { - gravity |= GravityHelper.GRAVITY_RIGHT; - } else if (mColumnMatch.type == SegmentType.CENTER_HORIZONTAL) { - gravity |= GravityHelper.GRAVITY_CENTER_HORIZ; - } - mGrid.setGridAttribute(newChild, ATTR_LAYOUT_COLUMN, column); - if (mRowMatch.type == SegmentType.BASELINE) { - // There *is* no baseline gravity constant, instead, leave the - // vertical gravity unspecified and GridLayout will treat it as - // baseline alignment - //gravity |= GravityHelper.GRAVITY_BASELINE; - } else if (mRowMatch.type == SegmentType.BOTTOM) { - gravity |= GravityHelper.GRAVITY_BOTTOM; - } else if (mRowMatch.type == SegmentType.CENTER_VERTICAL) { - gravity |= GravityHelper.GRAVITY_CENTER_VERT; - } - // Ensure that we have at least one horizontal and vertical constraint, otherwise - // the new item will be fixed. As an example, if we have a single button in the - // table which we inserted *without* a gravity, and we then insert a button - // above it with a vertical gravity, then only the top column would be considered - // stretchable, and it will fill all available vertical space and the previous - // button will jump to the bottom. - if (!GravityHelper.isConstrainedHorizontally(gravity)) { - gravity |= GravityHelper.GRAVITY_LEFT; - } - /* This causes problems: Try placing two buttons vertically from the top of the layout. - We need to solve the free column/free row problem first. - if (!GravityHelper.isConstrainedVertically(gravity) - // There is no baseline constant, so we have to leave it unconstrained instead - && mRowMatch.type != SegmentType.BASELINE - // You also can't baseline align one element with another that has vertical - // alignment top or bottom, so when we first "freely" place views (e.g. - // at a particular y location), also place it freely (no constraint). - && !mRowMatch.createCell) { - gravity |= GravityHelper.GRAVITY_TOP; - } - */ - mGrid.setGridAttribute(newChild, ATTR_LAYOUT_GRAVITY, getGravity(gravity)); - - mGrid.setGridAttribute(newChild, ATTR_LAYOUT_ROW, row); - - // Apply spans to ensure that the widget can fit without pushing columns - if (columnSpan > 1) { - mGrid.setGridAttribute(newChild, ATTR_LAYOUT_COLUMN_SPAN, columnSpan); - } - if (rowSpan > 1) { - mGrid.setGridAttribute(newChild, ATTR_LAYOUT_ROW_SPAN, rowSpan); - } - - // Ensure that we don't store columnCount=0 - if (mGrid.actualColumnCount == 0) { - mGrid.setGridAttribute(mGrid.layout, ATTR_COLUMN_COUNT, Math.max(1, column + 1)); - } - - return newChild; - } - - /** - * Called when a drop is completed and we're in grid-editing mode. This will insert - * the dragged element into the target cell. - * - * @param targetNode the GridLayout node - * @param element the dragged element - * @return the newly created node - */ - public INode handleGridModeDrop(INode targetNode, IDragElement element) { - String fqcn = element.getFqcn(); - INode newChild = targetNode.appendChild(fqcn); - - int column = mColumnMatch.cellIndex; - if (mColumnMatch.createCell) { - mGrid.addColumn(column, - newChild, UNDEFINED, false, UNDEFINED, UNDEFINED); - } - int row = mRowMatch.cellIndex; - if (mRowMatch.createCell) { - mGrid.addRow(row, newChild, UNDEFINED, false, UNDEFINED, UNDEFINED); - } - - mGrid.setGridAttribute(newChild, ATTR_LAYOUT_COLUMN, column); - mGrid.setGridAttribute(newChild, ATTR_LAYOUT_ROW, row); - - int gravity = 0; - if (mColumnMatch.type == SegmentType.RIGHT) { - gravity |= GravityHelper.GRAVITY_RIGHT; - } else if (mColumnMatch.type == SegmentType.CENTER_HORIZONTAL) { - gravity |= GravityHelper.GRAVITY_CENTER_HORIZ; - } - if (mRowMatch.type == SegmentType.BASELINE) { - // There *is* no baseline gravity constant, instead, leave the - // vertical gravity unspecified and GridLayout will treat it as - // baseline alignment - //gravity |= GravityHelper.GRAVITY_BASELINE; - } else if (mRowMatch.type == SegmentType.BOTTOM) { - gravity |= GravityHelper.GRAVITY_BOTTOM; - } else if (mRowMatch.type == SegmentType.CENTER_VERTICAL) { - gravity |= GravityHelper.GRAVITY_CENTER_VERT; - } - if (!GravityHelper.isConstrainedHorizontally(gravity)) { - gravity |= GravityHelper.GRAVITY_LEFT; - } - if (!GravityHelper.isConstrainedVertically(gravity)) { - gravity |= GravityHelper.GRAVITY_TOP; - } - mGrid.setGridAttribute(newChild, ATTR_LAYOUT_GRAVITY, getGravity(gravity)); - - if (mGrid.declaredColumnCount == UNDEFINED || mGrid.declaredColumnCount < column + 1) { - mGrid.setGridAttribute(mGrid.layout, ATTR_COLUMN_COUNT, column + 1); - } - - return newChild; - } - - /** - * Returns the best horizontal match - * - * @return the best horizontal match, or null if there is no match - */ - public GridMatch getColumnMatch() { - return mColumnMatch; - } - - /** - * Returns the best vertical match - * - * @return the best vertical match, or null if there is no match - */ - public GridMatch getRowMatch() { - return mRowMatch; - } - - /** - * Returns the grid used by the drop handler - * - * @return the grid used by the drop handler, never null - */ - public GridModel getGrid() { - return mGrid; - } -} |