bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h | 9 kit/ChildSession.cpp | 3 kit/KitHelper.hpp | 2 loleaflet/Makefile.am | 1 loleaflet/build/deps.js | 3 loleaflet/css/loleaflet.css | 20 + loleaflet/images/table-column-resize-marker.svg | 10 loleaflet/images/table-row-resize-marker.svg | 10 loleaflet/src/layer/tile/TileLayer.TableOverlay.js | 191 +++++++++++++++++++ loleaflet/src/layer/tile/TileLayer.js | 5 tools/KitClient.cpp | 1 11 files changed, 254 insertions(+), 1 deletion(-)
New commits: commit cc7060293945a6d45bf83376a456c57165a10f2f Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Wed Aug 14 18:13:40 2019 +0900 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Thu Aug 15 05:16:04 2019 +0200 tdf#122529 Support for table overlay - column/row change markers This adds table markers for resizing rows and columns if the user has the table selected or the cursor is in the table. The code reacts to the callback "tableselected:", where the markers are created for each column and row, if the payload (json) of course has any data. When the marker is dragged, a uno command to resize the table column or row border is send to the core. Change-Id: I9b21d09639c1b2be70a1a897f9e3340b453d847e Reviewed-on: https://gerrit.libreoffice.org/77360 Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> Tested-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h b/bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h index 4277adbe6..0c8e5938f 100644 --- a/bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h +++ b/bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h @@ -665,6 +665,15 @@ typedef enum * Rectangle format is the same as LOK_CALLBACK_INVALIDATE_TILES. */ LOK_CALLBACK_CELL_AUTO_FILL_AREA = 43, + + /** + * When the cursor is in a table or a table is selected in the + * document, this sends the table's column and row border positions + * to the client. If the payload is empty (empty JSON object), then + * no table is currently selected or the cursor is not inside a table + * cell. + */ + LOK_CALLBACK_TABLE_SELECTED = 44, } LibreOfficeKitCallbackType; diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp index 9684553e9..428808835 100644 --- a/kit/ChildSession.cpp +++ b/kit/ChildSession.cpp @@ -2296,6 +2296,9 @@ void ChildSession::loKitCallback(const int type, const std::string& payload) case LOK_CALLBACK_CELL_AUTO_FILL_AREA: sendTextFrame("cellautofillarea: " + payload); break; + case LOK_CALLBACK_TABLE_SELECTED: + sendTextFrame("tableselected: " + payload); + break; #if !ENABLE_DEBUG // we want a compilation-time failure in the debug builds; but ERR in the diff --git a/kit/KitHelper.hpp b/kit/KitHelper.hpp index 9f51fe528..8a32cb2dd 100644 --- a/kit/KitHelper.hpp +++ b/kit/KitHelper.hpp @@ -137,6 +137,8 @@ namespace LOKitHelper return "CELL_SELECTION_AREA"; case LOK_CALLBACK_CELL_AUTO_FILL_AREA: return "CELL_AUTO_FILL_AREA"; + case LOK_CALLBACK_TABLE_SELECTED: + return "TABLE_SELECTED"; } assert(!"Missing LOK_CALLBACK type"); diff --git a/loleaflet/Makefile.am b/loleaflet/Makefile.am index 00cfdc083..cb8522a6b 100644 --- a/loleaflet/Makefile.am +++ b/loleaflet/Makefile.am @@ -340,6 +340,7 @@ pot: src/errormessages.js \ src/layer/marker/Annotation.js \ src/layer/tile/TileLayer.js \ + src/layer/tile/TileLayer.TableOverlay.js \ src/map/Map.js \ src/map/Clipboard.js \ src/map/handler/Map.FileInserter.js \ diff --git a/loleaflet/build/deps.js b/loleaflet/build/deps.js index 45feef2b5..52a71fd24 100644 --- a/loleaflet/build/deps.js +++ b/loleaflet/build/deps.js @@ -36,7 +36,8 @@ var deps = { }, TileLayer: { - src: ['layer/tile/TileLayer.js'], + src: ['layer/tile/TileLayer.js', + 'layer/tile/TileLayer.TableOverlay.js'], desc: 'The base class for displaying tile layers on the map.', deps: ['GridLayer'] }, diff --git a/loleaflet/css/loleaflet.css b/loleaflet/css/loleaflet.css index 576931f8d..62cecafa9 100644 --- a/loleaflet/css/loleaflet.css +++ b/loleaflet/css/loleaflet.css @@ -41,6 +41,26 @@ -ms-filter: "alpha(opacity=100)" !important; } +.table-column-resize-marker { + margin-left: 0px; + margin-top: 0px; + width: 24px; + height: 24px; + background-image: url('images/table-column-resize-marker.svg'); + background-size: 100% 100%; + background-repeat: no-repeat; +} + +.table-row-resize-marker { + margin-left: 0px; + margin-top: 0px; + width: 24px; + height: 24px; + background-image: url('images/table-row-resize-marker.svg'); + background-size: 100% 100%; + background-repeat: no-repeat; +} + body { margin: 0; overflow: hidden; diff --git a/loleaflet/images/table-column-resize-marker.svg b/loleaflet/images/table-column-resize-marker.svg new file mode 100644 index 000000000..2eefb752c --- /dev/null +++ b/loleaflet/images/table-column-resize-marker.svg @@ -0,0 +1,10 @@ +<svg version="1.1" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"> + <g transform="matrix(0 -.70331 .70329 0 4.7475 27.253)" fill="#fff" fill-opacity=".86275" stroke="#000" stroke-linecap="round"> + <rect x="2.5185" y="2.5185" width="26.963" height="26.963" rx="4.4235" ry="4.4236" stroke-width="1.4745"/> + <g stroke-width="1.4219"> + <rect x="8.5" y="8.5" width="15" height="1"/> + <rect x="8.5" y="15.5" width="15" height="1"/> + <rect x="8.5" y="22.5" width="15" height="1"/> + </g> + </g> +</svg> diff --git a/loleaflet/images/table-row-resize-marker.svg b/loleaflet/images/table-row-resize-marker.svg new file mode 100644 index 000000000..812a38d43 --- /dev/null +++ b/loleaflet/images/table-row-resize-marker.svg @@ -0,0 +1,10 @@ +<svg version="1.1" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"> + <g transform="matrix(.70331 0 0 .70329 4.7472 4.7474)" fill="#fff" fill-opacity=".86275" stroke="#000" stroke-linecap="round"> + <rect x="2.5185" y="2.5185" width="26.963" height="26.963" rx="4.4235" ry="4.4236" stroke-width="1.4745"/> + <g stroke-width="1.4219"> + <rect x="8.5" y="8.5" width="15" height="1"/> + <rect x="8.5" y="15.5" width="15" height="1"/> + <rect x="8.5" y="22.5" width="15" height="1"/> + </g> + </g> +</svg> diff --git a/loleaflet/src/layer/tile/TileLayer.TableOverlay.js b/loleaflet/src/layer/tile/TileLayer.TableOverlay.js new file mode 100644 index 000000000..169af9d8e --- /dev/null +++ b/loleaflet/src/layer/tile/TileLayer.TableOverlay.js @@ -0,0 +1,191 @@ +/* -*- js-indent-level: 8 -*- */ +/* + * Table Overlay + */ + +L.TileLayer.include({ + _initializeTableOverlay: function () { + this._tableColumnMarkers = []; + this._tableRowMarkers = []; + this._tableMarkersDragged = false; + }, + _setMarkerPosition: function(marker) { + var point = this._twipsToLatLng(marker._pointTwips, this._map.getZoom()); + point = this._map.project(point); + var markerRect = marker._icon.getBoundingClientRect(); + if (marker._type.startsWith('column')) + point = point.subtract(new L.Point(markerRect.width / 2, markerRect.height)); + else + point = point.subtract(new L.Point(markerRect.width, markerRect.height / 2)); + point = this._map.unproject(point); + marker.setLatLng(point); + }, + _createMarker: function(markerType, entry, left, right) { + var className; + if (markerType === 'column') + className = 'table-column-resize-marker'; + else + className = 'table-row-resize-marker'; + + var marker = L.marker(new L.LatLng(0, 0), { + icon: L.divIcon({ + className: className, + iconSize: null + }), + draggable: true + }); + this._map.addLayer(marker); + marker._type = markerType + '-' + entry.type; + marker._position = parseInt(entry.position); + marker._min = parseInt(entry.min); + marker._max = parseInt(entry.max); + marker._index = parseInt(entry.index); + if (markerType === 'column') { + marker._pointTwips = new L.Point(this._tablePositionColumnOffset + marker._position, left); + marker._pointTop = new L.Point(this._tablePositionColumnOffset + marker._position, left); + marker._pointTop = this._twipsToLatLng(marker._pointTop, this._map.getZoom()); + marker._pointBottom = new L.Point(this._tablePositionColumnOffset + marker._position, right); + marker._pointBottom = this._twipsToLatLng(marker._pointBottom, this._map.getZoom()); + } + else { + marker._pointTwips = new L.Point(left, this._tablePositionRowOffset + marker._position); + marker._pointTop = new L.Point(left, this._tablePositionRowOffset + marker._position); + marker._pointTop = this._twipsToLatLng(marker._pointTop, this._map.getZoom()); + marker._pointBottom = new L.Point(right, this._tablePositionRowOffset + marker._position); + marker._pointBottom = this._twipsToLatLng(marker._pointBottom, this._map.getZoom()); + } + this._setMarkerPosition(marker); + marker.on('dragstart drag dragend', this._onTableResizeMarkerDrag, this); + return marker; + }, + _onTableSelectedMsg: function (textMsg) { + if (this._tableMarkersDragged == true) { + return; + } + + // Clean-up first + var markerIndex; + for (markerIndex = 0; markerIndex < this._tableColumnMarkers.length; markerIndex++) { + this._map.removeLayer(this._tableColumnMarkers[markerIndex]); + } + this._tableColumnMarkers = []; + + for (markerIndex = 0; markerIndex < this._tableRowMarkers.length; markerIndex++) { + this._map.removeLayer(this._tableRowMarkers[markerIndex]); + } + this._tableRowMarkers = []; + + // Parse the message + textMsg = textMsg.substring('tableselected:'.length + 1); + var message = JSON.parse(textMsg); + + // Create markers + if (message.rows && message.rows.entries.length > 0 && message.columns && message.columns.entries.length > 0) { + this._tablePositionColumnOffset = parseInt(message.columns.tableOffset); + this._tablePositionRowOffset = parseInt(message.rows.tableOffset); + var firstRowPosition = parseInt(message.rows.left) + this._tablePositionRowOffset; + var lastRowPosition = parseInt(message.rows.right) + this._tablePositionRowOffset; + var firstColumnPosition = parseInt(message.columns.left) + this._tablePositionColumnOffset; + var lastColumnPosition = parseInt(message.columns.right) + this._tablePositionColumnOffset; + var markerX, i, entry; + + entry = { type: 'left', position: message.columns.left, index: 0 }; + markerX = this._createMarker('column', entry, firstRowPosition, lastRowPosition); + this._tableColumnMarkers.push(markerX); + + for (i = 0; i < message.columns.entries.length; i++) { + entry = message.columns.entries[i]; + entry.type = 'middle'; + entry.index = i; + markerX = this._createMarker('column', entry, firstRowPosition, lastRowPosition); + this._tableColumnMarkers.push(markerX); + } + + entry = { type: 'right', position: message.columns.right, index: 0 }; + markerX = this._createMarker('column', entry, firstRowPosition, lastRowPosition); + this._tableColumnMarkers.push(markerX); + + for (i = 0; i < message.rows.entries.length; i++) { + entry = message.rows.entries[i]; + entry.type = 'middle'; + entry.index = i; + markerX = this._createMarker('row', entry, firstColumnPosition, lastColumnPosition); + this._tableRowMarkers.push(markerX); + } + + entry = { type: 'right', position: message.rows.right }; + markerX = this._createMarker('row', entry, firstColumnPosition, lastColumnPosition); + this._tableRowMarkers.push(markerX); + } + }, + + // Update dragged text selection. + _onTableResizeMarkerDrag: function (e) { + if (e.type === 'dragstart') { + e.target.isDragged = true; + this._tableMarkersDragged = true; + } + else if (e.type === 'dragend') { + e.target.isDragged = false; + this._tableMarkersDragged = false; + } + + // modify the mouse position - move to center of the marker + var aMousePosition = e.target.getLatLng(); + aMousePosition = this._map.project(aMousePosition); + var size = e.target._icon.getBoundingClientRect(); + aMousePosition = aMousePosition.add(new L.Point(size.width / 2, size.height / 2)); + aMousePosition = this._map.unproject(aMousePosition); + var aLatLonPosition = aMousePosition; + aMousePosition = this._latLngToTwips(aMousePosition); + + var newPosition; + if (e.target._type.startsWith('column')) { + newPosition = aMousePosition.x - this._tablePositionColumnOffset; + e.target._pointTop.lng = aLatLonPosition.lng; + e.target._pointBottom.lng = aLatLonPosition.lng; + } + else { + newPosition = aMousePosition.y - this._tablePositionRowOffset; + e.target._pointTop.lat = aLatLonPosition.lat; + e.target._pointBottom.lat = aLatLonPosition.lat; + } + + e.target._position = newPosition; + + var bounds = new L.LatLngBounds(e.target._pointTop, e.target._pointBottom); + + if (e.type === 'dragstart') { + this._rectangle = new L.Rectangle(bounds); + this._map.addLayer(this._rectangle); + } + else if (e.type === 'drag') { + this._rectangle.setBounds(bounds); + } + else if (e.type === 'dragend') { + this._map.removeLayer(this._rectangle); + this._rectangle = null; + + var params = { + BorderType: { + type : 'string', + value : e.target._type + }, + Index: { + type : 'uint16', + value : e.target._index + }, + NewPosition: { + type : 'int32', + value : e.target._position + } + } + + this._map.sendUnoCommand('.uno:TableChangeCurrentBorderPosition', params); + } + + if (e.originalEvent) + e.originalEvent.preventDefault(); + } +}); + diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js index 72b1c6558..87cf380f4 100644 --- a/loleaflet/src/layer/tile/TileLayer.js +++ b/loleaflet/src/layer/tile/TileLayer.js @@ -162,6 +162,8 @@ L.TileLayer = L.GridLayer.extend({ draggable: true }); + this._initializeTableOverlay(); + this._emptyTilesCount = 0; this._msgQueue = []; this._toolbarCommandValues = {}; @@ -510,6 +512,9 @@ L.TileLayer = L.GridLayer.extend({ else if (textMsg.startsWith('graphicviewselection:')) { this._onGraphicViewSelectionMsg(textMsg); } + else if (textMsg.startsWith('tableselected:')) { + this._onTableSelectedMsg(textMsg); + } else if (textMsg.startsWith('editor:')) { this._updateEditor(textMsg); } diff --git a/tools/KitClient.cpp b/tools/KitClient.cpp index c68de9adf..a4419a3e3 100644 --- a/tools/KitClient.cpp +++ b/tools/KitClient.cpp @@ -87,6 +87,7 @@ extern "C" CASE(PROFILE_FRAME); CASE(CELL_SELECTION_AREA); CASE(CELL_AUTO_FILL_AREA); + CASE(TABLE_SELECTED); #undef CASE } std::cout << " payload: " << payload << std::endl; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits