| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // The callback method type invoked when the selection changes. | 5 // The callback method type invoked when the selection changes. |
| 6 typedef void SelectionCallback(); | 6 typedef void SelectionCallback(); |
| 7 | 7 |
| 8 // The method type for the SelectionManager.applyToSelectedCells method. | 8 // The method type for the SelectionManager.applyToSelectedCells method. |
| 9 typedef void SelectionApply(CellLocation location); | 9 typedef void SelectionApply(CellLocation location); |
| 10 | 10 |
| 11 class BoundingBox { | 11 class BoundingBox { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 Spreadsheet get spreadsheet() => _spreadsheet; | 48 Spreadsheet get spreadsheet() => _spreadsheet; |
| 49 | 49 |
| 50 SelectionManager(this._spreadsheet, SpreadsheetPresenter presenter, Window win
dow, this._table) | 50 SelectionManager(this._spreadsheet, SpreadsheetPresenter presenter, Window win
dow, this._table) |
| 51 : _selectedCell = null, _selectionCorner = null, _originRow = 0, _originCo
lumn = 0 { | 51 : _selectedCell = null, _selectionCorner = null, _originRow = 0, _originCo
lumn = 0 { |
| 52 Document doc = window.document; | 52 Document doc = window.document; |
| 53 | 53 |
| 54 Element spreadsheetElement = presenter.spreadsheetElement; | 54 Element spreadsheetElement = presenter.spreadsheetElement; |
| 55 _selectionDiv = new Element.tag("div"); | 55 _selectionDiv = new Element.tag("div"); |
| 56 _selectionDiv.id = "selection-${_spreadsheet.name}"; | 56 _selectionDiv.id = "selection-${_spreadsheet.name}"; |
| 57 _selectionDiv.attributes["class"] = "selection"; | 57 _selectionDiv.attributes["class"] = "selection"; |
| 58 _selectionDiv.style.setProperty("display", "none"); | 58 _selectionDiv.style.display = "none"; |
| 59 spreadsheetElement.nodes.add(_selectionDiv); | 59 spreadsheetElement.nodes.add(_selectionDiv); |
| 60 | 60 |
| 61 Element thumb = new Element.tag("div"); | 61 Element thumb = new Element.tag("div"); |
| 62 thumb.id = "selection-thumb-${_spreadsheet.name}"; | 62 thumb.id = "selection-thumb-${_spreadsheet.name}"; |
| 63 thumb.attributes["class"] = "selection-thumb"; | 63 thumb.attributes["class"] = "selection-thumb"; |
| 64 _selectionDiv.nodes.add(thumb); | 64 _selectionDiv.nodes.add(thumb); |
| 65 | 65 |
| 66 // Update selection after changing zoom factor, to reduce problems with posi
tion precision | 66 // Update selection after changing zoom factor, to reduce problems with posi
tion precision |
| 67 // Only create a single tracker per page | 67 // Only create a single tracker per page |
| 68 if (_zoomTracker == null) { | 68 if (_zoomTracker == null) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 88 CellRange range = _getSelectionRange(_selectedCell, _selectionCorner); | 88 CellRange range = _getSelectionRange(_selectedCell, _selectionCorner); |
| 89 if (range == null) { | 89 if (range == null) { |
| 90 return; | 90 return; |
| 91 } | 91 } |
| 92 | 92 |
| 93 range.forEach(apply); | 93 range.forEach(apply); |
| 94 } | 94 } |
| 95 | 95 |
| 96 // Hide the selection marquee and empty the selection range | 96 // Hide the selection marquee and empty the selection range |
| 97 void clearSelection() { | 97 void clearSelection() { |
| 98 _selectionDiv.style.setProperty("display", "none"); | 98 _selectionDiv.style.display = "none"; |
| 99 _selectedCell = _selectionCorner = null; | 99 _selectedCell = _selectionCorner = null; |
| 100 selectionChanged(); | 100 selectionChanged(); |
| 101 } | 101 } |
| 102 | 102 |
| 103 // Return a BoundingBox for the given CellRange, clipped to the visible region
of the table | 103 // Return a BoundingBox for the given CellRange, clipped to the visible region
of the table |
| 104 // TODO: deal with full row and/or column selection | 104 // TODO: deal with full row and/or column selection |
| 105 Future<BoundingBox> getBoundingBoxForRange(CellRange r) { | 105 BoundingBox getBoundingBoxForRange(CellRange r) { |
| 106 assert(window.inMeasurementFrame); |
| 106 // Modify the overlay for entire row/column selection | 107 // Modify the overlay for entire row/column selection |
| 107 int minRow = r.minCorner.row; | 108 int minRow = r.minCorner.row; |
| 108 int maxRow = r.maxCorner.row; | 109 int maxRow = r.maxCorner.row; |
| 109 int minCol = r.minCorner.col; | 110 int minCol = r.minCorner.col; |
| 110 int maxCol = r.maxCorner.col; | 111 int maxCol = r.maxCorner.col; |
| 111 | 112 |
| 112 // FIXME - provide the table size to this class in a better way | 113 // FIXME - provide the table size to this class in a better way |
| 113 int maxVisibleRow = _table.numRows() - 1; | 114 int maxVisibleRow = _table.numRows() - 1; |
| 114 TableRowElement tableRow = _table.getRowElement(0); | 115 TableRowElement tableRow = _table.getRowElement(0); |
| 115 int maxVisibleCol = tableRow.cells.length - 1; | 116 int maxVisibleCol = tableRow.cells.length - 1; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 144 TableRowElement minRowElmt = _table.getRowElement(minPinned); | 145 TableRowElement minRowElmt = _table.getRowElement(minPinned); |
| 145 TableCellElement minCellElmt = | 146 TableCellElement minCellElmt = |
| 146 minRowElmt.cells[_pin(minCol - _originColumn, 1, maxVisibleCol)]; | 147 minRowElmt.cells[_pin(minCol - _originColumn, 1, maxVisibleCol)]; |
| 147 int maxPinned = _pin(maxRow - _originRow, 1, maxVisibleRow); | 148 int maxPinned = _pin(maxRow - _originRow, 1, maxVisibleRow); |
| 148 TableRowElement maxRowElmt = _table.getRowElement(maxPinned); | 149 TableRowElement maxRowElmt = _table.getRowElement(maxPinned); |
| 149 TableCellElement maxCellElmt = | 150 TableCellElement maxCellElmt = |
| 150 maxRowElmt.cells[_pin(maxCol - _originColumn, 1, maxVisibleCol)]; | 151 maxRowElmt.cells[_pin(maxCol - _originColumn, 1, maxVisibleCol)]; |
| 151 | 152 |
| 152 // We need bounding box relative to the container which will be offset by | 153 // We need bounding box relative to the container which will be offset by |
| 153 // css. | 154 // css. |
| 154 final tableRect = _table.rect; | |
| 155 final minCellElmtRect = minCellElmt.rect; | |
| 156 final maxCellElmtRect = maxCellElmt.rect; | |
| 157 | 155 |
| 158 window.requestLayoutFrame(() { | 156 final orgP = _table.rect.bounding; |
| 159 ClientRect orgP = tableRect.value.bounding; | 157 final minP = minCellElmt.rect.bounding; |
| 160 ClientRect minP = minCellElmtRect.value.bounding; | 158 final maxP = maxCellElmt.rect.bounding; |
| 161 ClientRect maxP = maxCellElmtRect.value.bounding; | 159 return new BoundingBox( |
| 162 completer.complete(new BoundingBox( | 160 (minP.left - orgP.left).toInt(), |
| 163 (minP.left - orgP.left).toInt(), | 161 (minP.top - orgP.top).toInt(), |
| 164 (minP.top - orgP.top).toInt(), | 162 (maxP.left - minP.left + maxCellElmt.rect.client.width).toInt(), |
| 165 (maxP.left - minP.left + maxCellElmtRect.value.client.width).toInt(), | 163 (maxP.top - minP.top + maxCellElmt.rect.client.height).toInt()); |
| 166 (maxP.top - minP.top + maxCellElmtRect.value.client.height).toInt())); | |
| 167 }); | |
| 168 return completer.future; | |
| 169 } | 164 } |
| 170 | 165 |
| 171 CellRange getSelectionRange() => _getSelectionRange(_selectedCell, _selectionC
orner); | 166 CellRange getSelectionRange() => _getSelectionRange(_selectedCell, _selectionC
orner); |
| 172 | 167 |
| 173 bool isColumnSelected(int column) { | 168 bool isColumnSelected(int column) { |
| 174 CellRange r = _getSelectionRange(_selectedCell, _selectionCorner); | 169 CellRange r = _getSelectionRange(_selectedCell, _selectionCorner); |
| 175 if (r == null) { | 170 if (r == null) { |
| 176 return false; | 171 return false; |
| 177 } | 172 } |
| 178 return r.minCorner.col <= column && r.maxCorner.col >= column; | 173 return r.minCorner.col <= column && r.maxCorner.col >= column; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 } | 215 } |
| 221 | 216 |
| 222 // Draw or hide the selection marquee using current cell metrics | 217 // Draw or hide the selection marquee using current cell metrics |
| 223 void updateSelection() { | 218 void updateSelection() { |
| 224 CellRange r = _getSelectionRange(_selectedCell, _selectionCorner); | 219 CellRange r = _getSelectionRange(_selectedCell, _selectionCorner); |
| 225 if (r == null) { | 220 if (r == null) { |
| 226 clearSelection(); | 221 clearSelection(); |
| 227 return; | 222 return; |
| 228 } | 223 } |
| 229 | 224 |
| 230 getBoundingBoxForRange(r).then((BoundingBox box) { | 225 window.requestMeasurementFrame(() { |
| 231 if (box != null) { | 226 final box = getBoundingBoxForRange(r); |
| 232 _selectionDiv.style.setProperty("left", HtmlUtils.toPx(box.left)); | 227 return () { |
| 233 _selectionDiv.style.setProperty("top", HtmlUtils.toPx(box.top)); | 228 if (box != null) { |
| 234 _selectionDiv.style.setProperty("width", HtmlUtils.toPx(box.width)); | 229 _selectionDiv.style.left = HtmlUtils.toPx(box.left); |
| 235 _selectionDiv.style.setProperty("height", HtmlUtils.toPx(box.height)); | 230 _selectionDiv.style.top = HtmlUtils.toPx(box.top); |
| 236 _selectionDiv.style.removeProperty("display"); | 231 _selectionDiv.style.width = HtmlUtils.toPx(box.width); |
| 237 } else { | 232 _selectionDiv.style.height = HtmlUtils.toPx(box.height); |
| 238 _selectionDiv.style.setProperty("display", "none"); | 233 _selectionDiv.style.removeProperty("display"); |
| 239 } | 234 } else { |
| 235 _selectionDiv.style.display = "none"; |
| 236 } |
| 237 }; |
| 240 }); | 238 }); |
| 241 } | 239 } |
| 242 | 240 |
| 243 // Return the selection range for the given corners. | 241 // Return the selection range for the given corners. |
| 244 // If the first corner is on a row header, it is assumed that the entire | 242 // If the first corner is on a row header, it is assumed that the entire |
| 245 // row is selected, and the returned range has min.col == 0 and max.col == 0. | 243 // row is selected, and the returned range has min.col == 0 and max.col == 0. |
| 246 // If the first corner is on a column header, it is assumed that the entire | 244 // If the first corner is on a column header, it is assumed that the entire |
| 247 // column is selected, and the returned range has min.row == 0 and max.row ==
0. | 245 // column is selected, and the returned range has min.row == 0 and max.row ==
0. |
| 248 CellRange _getSelectionRange(CellLocation corner1, CellLocation corner2) { | 246 CellRange _getSelectionRange(CellLocation corner1, CellLocation corner2) { |
| 249 if (corner1 == null || corner2 == null) { | 247 if (corner1 == null || corner2 == null) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 269 return new CellRange.columns(corner1.spreadsheet, minCol, maxCol); | 267 return new CellRange.columns(corner1.spreadsheet, minCol, maxCol); |
| 270 } | 268 } |
| 271 | 269 |
| 272 return new CellRange(corner1.spreadsheet, new RowCol(minRow, minCol), | 270 return new CellRange(corner1.spreadsheet, new RowCol(minRow, minCol), |
| 273 new RowCol(maxRow, maxCol)); | 271 new RowCol(maxRow, maxCol)); |
| 274 } | 272 } |
| 275 | 273 |
| 276 // Return the value closest to x in the range [min, max] | 274 // Return the value closest to x in the range [min, max] |
| 277 int _pin(int x, int min, int max) => Math.max(Math.min(x, max), min); | 275 int _pin(int x, int min, int max) => Math.max(Math.min(x, max), min); |
| 278 } | 276 } |
| OLD | NEW |