diff --git a/Migration.md b/Migration.md index 7d5d01111..a41cb56c6 100644 --- a/Migration.md +++ b/Migration.md @@ -26,6 +26,8 @@ release will remove the deprecated code. * CMake `-config` files * Paths that depend on the project name +* QML `import ignition.gui 1.0` is deprecated, use `import gz.gui 1.0` instead. + ## Gazebo GUI 6.2 to 6.3 * New QML dependencies, only needed for the NavSatMap plugin: `qml-module-qtlocation`, `qml-module-qtpositioning` diff --git a/examples/config/plugin_params.config b/examples/config/plugin_params.config index 4e68df600..aa11951d5 100644 --- a/examples/config/plugin_params.config +++ b/examples/config/plugin_params.config @@ -16,7 +16,7 @@ Properties passed directly to the QML card. It includes: * All Pane properties: https://doc.qt.io/qt-5/qml-qtquick-controls2-pane-members.html - * All custom properties within IgnCard.qml + * All custom properties within GzCard.qml --> false 350 diff --git a/examples/plugin/gz_components/GzComponents.qml b/examples/plugin/gz_components/GzComponents.qml index 8e516d93b..d1d921be9 100644 --- a/examples/plugin/gz_components/GzComponents.qml +++ b/examples/plugin/gz_components/GzComponents.qml @@ -16,7 +16,7 @@ */ import QtQuick 2.9 import QtQuick.Controls 2.0 -import "qrc:/qml" +import gz.gui 1.0 Column { anchors.fill: parent @@ -40,4 +40,13 @@ Column { value: 5.8 width: 300 } + + // Deprecated spin box + IgnSpinBox { + minimumValue: -2 + maximumValue: 19 + decimals: 0 + stepSize: 3 + value: 5 + } } diff --git a/include/gz/gui/qml/qmldir b/include/gz/gui/qml/qmldir index 486b6c7aa..ff97d847b 100644 --- a/include/gz/gui/qml/qmldir +++ b/include/gz/gui/qml/qmldir @@ -1,3 +1,8 @@ module gz.gui +GzSnackBar 1.0 GzSnackBar.qml GzSpinBox 1.0 GzSpinBox.qml + +# Deprecated components, remove on tock +IgnSnackBar 1.0 GzSnackBar.qml +IgnSpinBox 1.0 GzSpinBox.qml diff --git a/include/gz/gui/qml/qmldir_deprecated b/include/gz/gui/qml/qmldir_deprecated new file mode 100644 index 000000000..4bd7fa37b --- /dev/null +++ b/include/gz/gui/qml/qmldir_deprecated @@ -0,0 +1,8 @@ +# Deprecated module, remove on tock +module ignition.gui + +GzSnackBar 1.0 GzSnackBar.qml +GzSpinBox 1.0 GzSpinBox.qml + +IgnSnackBar 1.0 GzSnackBar.qml +IgnSpinBox 1.0 GzSpinBox.qml diff --git a/include/gz/gui/resources.qrc b/include/gz/gui/resources.qrc index 325a5485f..eaebd40a6 100644 --- a/include/gz/gui/resources.qrc +++ b/include/gz/gui/resources.qrc @@ -23,25 +23,21 @@ qml/images/menu.png qml/images/export_icon.png qml/images/search.svg - - qml/GzCard.qml - qml/GzCardSettings.qml - qml/GzHelpers.qml - qml/GzRulers.qml - qml/GzSnackBar.qml - qml/GzSortFilterModel.qml - qml/GzSpinBox.qml - qml/GzSplit.qml - qml/GzSnackBar.qml - qml/GzSpinBox.qml + qml/qmldir + qml/GzSnackBar.qml qml/GzSpinBox.qml - qml/GzSnackBar.qml - qml/GzSpinBox.qml + + + + + qml/qmldir_deprecated + qml/GzSnackBar.qml + qml/GzSpinBox.qml diff --git a/include/ignition/gui/qml/Chart.qml b/include/ignition/gui/qml/Chart.qml deleted file mode 100644 index cd3a259d7..000000000 --- a/include/ignition/gui/qml/Chart.qml +++ /dev/null @@ -1,740 +0,0 @@ -/* - * Copyright (C) 2020 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ -import QtQuick 2.9 -import QtCharts 2.2 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Styles 1.4 -import QtQuick.Controls.Material 2.1 -import QtQuick.Layouts 1.3 - -Rectangle { - id: main - - /** - subscribe to a field || register the chart to the subscribed field - */ - signal subscribe(real Id, string topic, string path); - /** - unsubscribe from a field || unregister the chart from the subscribed field - */ - signal unSubscribe(real Id, string topic, string path); - /** - register the chart to the component attribute - */ - signal componentSubscribe(string entity, string typeId, string type, string attribute, real Id); - /** - unregister the chart from the component attribute - */ - signal componentUnSubscribe(string entity, string typeId, string attribute, real Id); - /** - chart is clicked to swap the chart mode - from small chart to the main chart in multi charts mode - Id: chartID - */ - signal clicked(real Id); - - /** - Points Limitation: max points of each series - When points exceed that limit, some points from begining are deleted - */ - property int maxPoints: 10000 - /** - Chart ID - */ - property int chartID: -1 - /** - True if the chart is a small chart in the multi charts mode - */ - property bool multiChartsMode: false - - /** - add point to a field graph - _fieldID field key or path - _x x coordinate of the point - _y y coordinate of the point - */ - function appendPoint(_fieldID, _x, _y) - { - chart.appendPoint(_fieldID, _x, _y); - } - /** - set the chart opacity - _opacity opacity value - */ - function setChartOpacity(_opacity) - { - chart.opacity = _opacity; - } - /** - move chart to the right - */ - function moveChart() - { - chart.scrollRight(chart.width * shiftAmount.value); - } - /** - change the PlotArea size to fill the chart or the reverse case - */ - function fillPlotInOrOut() - { - if (multiChartsMode) - { - chart.legend.visible = false - chart.margins.top = 0 - chart.margins.bottom = 0 - chart.margins.right = 0 - chart.margins.left = 0 - } - else - { - chart.legend.visible = true - chart.margins.top = 20 - chart.margins.bottom = 20 - chart.margins.right = 20 - chart.margins.left = 20 - } - } - - /** - get the chart object - */ - function getChart() - { - return chart; - } - - /** - fix OpenGL Disappear problem when the plugin is docked - */ - function fixOpenGL() - { - lineSeries.useOpenGL = false; - lineSeries.useOpenGL = true; - } - - - color: "transparent" - - // =============== Fields info Rectangle ================ - Rectangle { - id: infoRect - - /** - Handle Dropping Plot Data (Fields or Components) - text dropped text of the dragged item - */ - function onDrop(text) - { - // topic and path is separated with ',' - if (text.search(",") === -1) - return; - - // check if the dropped item is component - if (infoRect.isComponentDrop(text)) - { - var textList = text.split(","); - var entity = textList[1]; - var typeId = textList[2]; - var type = textList[3]; - var attribute = textList[4]; - var typeName = textList[5]; - - var componentID = entity + "," + typeId + "," + attribute; - var displayText = entity + "," + typeName + "," + attribute; - - componentSubscribe(entity, typeId, type, attribute, chartID); - - // if the field is already attached - if (componentID in chart.serieses) - return; - - chart.addSeries(componentID, displayText); - infoRect.addComponent(entity, typeId, type, attribute, typeName, displayText); - } - // the dropped item is a field - else - { - var topic_path = text.split(","); - var topic = topic_path[0]; - var path = topic_path[1]; - - // Field Full Path ID - var ID = topic + "-" + path; - - // attach the chart to the subscribed field - subscribe(chartID, topic, path); - - // if the field is already attached - if (ID in chart.serieses) - return; - - // add axis series to plot the field - chart.addSeries(ID, ""); - - // add field info component - infoRect.addField(ID, topic, path); - } - guideText.visible = false; - } - - /** - add field to the fields layout - ID Chart ID - topic topic name - path field key or path - */ - function addField(ID, topic, path) - { - var field = fieldInfo.createObject(row); - field.width = 150; - field.height = Qt.binding( function() {return infoRect.height * 0.8} ); - field.y = Qt.binding( function() - { - if (infoRect.height) - return (infoRect.height - field.height)/2; - else - return 0; - } - ); - - // update field data - field.topic = topic; - field.path = path; - field.type = "Field" - } - /** - add component to the chart - entity entity ID - typeId type ID - type type of the component attribute (Pose3d, Vector3d .. etc) - */ - function addComponent(entity, typeId, type, attribute, typeName, displayText) - { - var _component = fieldInfo.createObject(row); - _component.width = 150; - _component.height = Qt.binding( function() {return infoRect.height * 0.8} ); - _component.y = Qt.binding( function() - { - if (infoRect.height) - return (infoRect.height - _component.height)/2; - else - return 0; - } - ); - - _component.entity = entity; - _component.typeId = typeId; - _component.componentType = type; - _component.attribute = attribute; - _component.typeName = typeName; - _component.displayText = displayText; - - _component.type = "Component"; - } - - /** - True if the dropped text has the component format - dropText the text dropped in the field info rect - */ - function isComponentDrop(dropText) - { - var textList = dropText.split(","); - if (textList.length < 6) - return false; - if (textList[0] !== "Component") - return false; - - return true; - } - - width: parent.width - height: (multiChartsMode) ? 0 : 50 - color: (Material.theme == Material.Light) ? Material.color(Material.Grey,Material.Shade200) - : Material.color(Material.BlueGrey, Material.Shade800) - - Text { - id: guideText - text: qsTr("Drag & Drop Plottable Fields | Components") - anchors.centerIn: parent - color: (Material.theme == Material.Light) ? "gray" : "white" - opacity: 0.3 - visible: (multiChartsMode) ? false : true - } - - // make it scrolable - ScrollView { - anchors.fill: parent - ScrollBar.horizontal.policy: ScrollBar.AsNeeded - ScrollBar.vertical.policy: ScrollBar.AlwaysOff - clip: true - // Horizontal Layout for the fields - Row { - anchors.fill: parent - id:row - spacing: 10 - } - } - - DropArea { - anchors.fill: parent - onDropped: - { - var text = drop.getDataAsString("text/plain"); - infoRect.onDrop(text); - } - } - } - - // ================ Field / Component ==================== - Component { - id: fieldInfo - Rectangle { - id: component - - /** - Field or Component - */ - property string type: "" - - /** - field data: - topic name - path field key - */ - property string topic: "" - property string path: "" - - /** - component data: - entity entity ID - typeId type ID - type type of the component attribute (Pose3d, Vector3d .. etc) - attribute (X, Y, Z, Roll, ... etc) - */ - property string entity: "" - property string typeId: "" - property string componentType: "" - property string attribute: "" - property string typeName: "" - property string componentId: entity + "," + typeId + "," + attribute; - property string displayText: "" - - /** - set the field name text - */ - function setText(text) { - fieldname.text = text; - } - signal unsubscribe(string topic, string path); - - radius: width/4 - Rectangle { - height: parent.height - width: parent.width - radius: width/4 - color: Material.accentColor - clip: true - - MouseArea { - id : fieldInfoMouse - anchors.fill: parent - hoverEnabled: true - onEntered: enterAnimation.start(); - onExited: exitAnimation.start(); - } - - Text { - id: fieldname - text: (component.type === "Field") ? component.topic + "/"+ component.path : - (component.type === "Component") ? component.entity + "," + component.typeName - + "," + component.attribute : "" - color: "white" - elide: Text.ElideRight - width: parent.width * 0.9 - anchors.verticalCenter: parent.verticalCenter - leftPadding: 20; - } - - ToolTip { - delay: 1000 - timeout: 2000 - text: (component.type === "Field" ) ? component.topic + "-"+ component.path : - (component.type === "Component") ? "entity: " + component.entity + "\n" + - "typeId: " + component.typeId + "\n" + - "typeName: " + component.typeName + "\n" + - "dataType: " + component.componentType + "\n" + - "attribute: " + component.attribute : "" - visible: fieldInfoMouse.containsMouse - y: fieldInfoMouse.mouseY - x: fieldInfoMouse.mouseX - enter: null - exit: null - } - } - - Rectangle { - id: exitBtn - radius: width / 2 - height: parent.height * 0.8; - width: height - color: "red" - opacity: 0 - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.rightMargin: parent.width * 0.05 - Text { anchors.centerIn: parent; text: "x"; color: "white"} - - MouseArea { - anchors.fill: parent - onClicked: { - exitAnimation.start(); - - // unSubscribe from the transport / Component - if (component.type === "Field") - main.unSubscribe(main.chartID, component.topic, component.path); - - else if (component.type === "Component") - main.componentUnSubscribe(component.entity, component.typeId, - component.attribute, main.chartID) - - - // delete the series points and deattache it from the chart - if (component.type === "Field") - chart.deleteSeries(component.topic + "-" + component.path) - - else if (component.type === "Component") - chart.deleteSeries(component.componentId); - - // delete the field info component - component.destroy(); - } - } - NumberAnimation { - id: enterAnimation - target: exitBtn; property: "opacity"; duration: 100 - easing.type: Easing.InOutQuad; from: 0; to: 1; - } - NumberAnimation { - id: exitAnimation - target: exitBtn; property: "opacity"; duration: 100; - easing.type: Easing.InOutQuad; from: 0.85; to: 0; - } - } - } - } - - // ================== Chart ============================ - ChartView { - id : chart - /** - all serieses, field path is the key, series is the value - */ - property var serieses: ({}) - /** - colors to give the fields different colors - */ - property var colors: (Material.theme == Material.Light) ? - ["red", "#004c6d", "#FF5D8C","#903f5c", "#7ec92a", "#a88f31", "#ff7c43" , "#62efff"] : - ["#ffa600", "#7aa6c2", "#f04c6d", "#bc5090", "#a88f31", "#7a5195", "#ffbcc3", "#7ec92a"]; - /** - current index of colors array - */ - property int indexColor: 0 - - /** - get sereieses - return: map of serieses - */ - function getAllSerieses() - { - return serieses; - } - - /** - update the text that shows the hover point value (x,y) on the mouse cursor - */ - function updateHoverText() - { - if (!hoverText.visible) - return; - - var axisWidth = xAxis.max - xAxis.min; - var axisHeight = yAxis.max - yAxis.min; - var xPos = xAxis.min + ( (chartMouse.mouseX - chart.plotArea.x) / chart.plotArea.width ) * axisWidth; - var yPos = yAxis.max - ( (chartMouse.mouseY - chart.plotArea.y) / chart.plotArea.height) * axisHeight; - hoverText.text = "(" + xPos.toFixed(2).toString() + ", " + yPos.toFixed(2).toString() + ")"; - hoverText.x = chartMouse.mouseX + 12; - hoverText.y = chartMouse.mouseY; - } - - /** - add new series - ID key of the series: path of the field of the series - */ - function addSeries(ID, seriesDisplayText) { - var seriesName = (seriesDisplayText) ? seriesDisplayText : ID - var newSeries = createSeries(ChartView.SeriesTypeLine, seriesName, xAxis, yAxis); - newSeries.useOpenGL = true; - newSeries.width = 2; - newSeries.color = chart.colors[chart.indexColor % chart.colors.length] - serieses[ID] = newSeries; - - chart.indexColor = (chart.indexColor + 1) % chart.colors.length; - } - - /** - delete a field series by its ID - ID field path - */ - function deleteSeries(ID) { - // remove the points of the series from the chart - removeSeries(serieses[ID]); - // remove the series key from the serieses map - delete serieses[ID]; - } - - /** - add point to a specific TextField - _fieldID field ID or Path - _x x of the point - _y y of the point - */ - function appendPoint(_fieldID, _x, _y) - { - if (!chart.serieses[_fieldID]) - return; - - // if this is the first point (if the chart is empty): - // set the min/max according to that point's coordinates - // note: count == 2: because chart has 1 series by default to show plotting grid - if (chart.count === 2 && chart.serieses[_fieldID].count === 0) - { - xAxis.min = _x; - xAxis.max = _x + 10; - chart.serieses[_fieldID].append(_x, _y); - return; - } - - // expand the chart boundries if needed - if (xAxis.max < _x) - { - xAxis.max = _x; - chart.scrollRight(chart.width * 0.0012); - } - - if (yAxis.max < _y) - yAxis.max = _y ; - if (yAxis.min > _y) - yAxis.min = _y ; - if (xAxis.min > _x) - xAxis.min = _x ; - - // add the point - chart.serieses[_fieldID].append(_x, _y); - - // delete the oldest point to limit the points size - if (chart.serieses[_fieldID].count > maxPoints) - chart.serieses[_fieldID].removePoints(0,1) - - chart.updateHoverText(); - } - - width: parent.width - anchors.bottom: parent.bottom - anchors.top: infoRect.bottom - - // animations - antialiasing: true - opacity: 1 - backgroundRoundness: 10 - animationOptions: ChartView.NoAnimation - - theme: (Material.theme == Material.Light) ? ChartView.ChartThemeLight: ChartView.ChartThemeDark - - Text { - id:hoverText - visible: (chartMouse.flag && !multiChartsMode && chartMouse.containsMouse) ? true : false - color: (Material.theme == Material.Light) ? "black" : Material.color(Material.Grey,Material.Shade200) - } - - MouseArea { - id:chartMouse - /** - flag to show the hover text - True if the user clicked on the CheckBox - */ - property bool flag: (hoverCheckBox.checkState === Qt.Checked) ? true : false - /** - xHold is the value of x when the user press and hold the mouse to move the plot view - */ - property double xHold: 0 - /** - xHold is the value of y when the user press and hold the mouse to move the plot view - */ - property double yHold: 0 - - anchors.fill:parent - hoverEnabled: true - cursorShape: (multiChartsMode) ? Qt.PointingHandCursor : Qt.ArrowCursor - - onEntered: { - if (multiChartsMode) - chart.opacity = 0.7; - } - onExited: { - if (multiChartsMode) - chart.opacity = 1; - } - onPressed: { - xHold = mouseX; - yHold = mouseY; - } - - /** - Drag/Move the plot view - */ - onPositionChanged: { - if (multiChartsMode) - return - - if (pressed) - { - chart.scrollLeft(mouseX - xHold) - chart.scrollUp(mouseY - yHold) - - xHold = mouseX - yHold = mouseY - } - else - chart.updateHoverText(); - - } - - onClicked: { - main.clicked(chartID); - } - - /** - zoom shift amount - */ - property double shift: 15 - - /** - Zoom - */ - onWheel:{ - if (multiChartsMode) - return - - // the center of the plot - var centerX = chart.plotArea.x + chart.plotArea.width/2 - var centerY = chart.plotArea.y + chart.plotArea.height/2 - - // the percentage of the mouseX = how it moves far away from the plot center - // ex: if the the plot width = 100 & mouseX = 75, so it moves the 50% away from the center (75-50)/50 - var factorX = (wheel.x - centerX) / (chart.plotArea.width/2); // % - // same for y but with mouseY, centerY and Height - var factorY = (wheel.y - centerY) / (chart.plotArea.height/2); // % - - - var zoomType; - if( wheel.angleDelta.y > 0) - // zoomIn - zoomType = 1; - else - // zoomOut - zoomType = -1; - - - // plot size (width & height) will always increase/decrese by 2*shift - // (imagine the size is centered with shift distance at both sides of width (same of height) ) - - // the location of zooming is determine by changing the x,y (top left corner) of the zoom rect - // x,y increase/decrease - var rect = Qt.rect(chart.plotArea.x + (factorX + 1) * shift * zoomType, - chart.plotArea.y + (factorY + 1) * shift * zoomType, - chart.plotArea.width - 2 * shift * zoomType, - chart.plotArea.height - 2 * shift * zoomType - ); - - chart.zoomIn(rect); - } - } - - DropArea { - anchors.fill: parent - onDropped: - { - var text = drop.getDataAsString("text/plain"); - infoRect.onDrop(text); - } - } - - ValueAxis { - id : yAxis - min: 0; - max: 3; - tickCount: 9 - } - - ValueAxis { - id : xAxis - min: 0 - max: 3 - tickCount: 9 - } - - // to just show the plot at begining - LineSeries { - id: lineSeries - axisX: xAxis - axisY: yAxis - visible: false - useOpenGL: true - } - - Text { - id: plotName - text: "Plot " + chartID.toString() - font.pointSize: 15 - anchors.left: parent.left - anchors.top: parent.top - anchors.margins: 20 - color: Material.color(Material.Grey, Material.Shade500) - visible: (multiChartsMode) ? false : true - } - - Text { - id: hoverName - anchors.centerIn: parent - visible: (multiChartsMode && chartMouse.containsMouse) - text: plotName.text - color: plotName.color - font.pointSize: plotName.font.pointSize - } - } - - CheckBox { - id: hoverCheckBox; - visible: (main.multiChartsMode) ? false : true - checkState: Qt.Unchecked - anchors.right: chart.right - anchors.top: chart.top - anchors.margins: 20 - text: "hover" - } -} diff --git a/include/ignition/gui/qml/IgnCard.qml b/include/ignition/gui/qml/IgnCard.qml deleted file mode 100644 index c9b5031fa..000000000 --- a/include/ignition/gui/qml/IgnCard.qml +++ /dev/null @@ -1,704 +0,0 @@ -/* - * Copyright (C) 2018 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ -import QtQuick 2.9 -import QtQuick.Controls 1.4 as QQC1 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.1 -import QtQuick.Layouts 1.3 -import QtQuick.Window 2.2 -import "qrc:/qml" - -// TODO: don't use "parent" -Pane { - /** - * Minimum length of each dimension - */ - property int minSize: 50 - - /** - * True to have a dock button - */ - property bool showDockButton: true - - /** - * True to have a close button - */ - property bool showCloseButton: true - - /** - * True to have a collapse button - */ - property bool showCollapseButton: true - - /** - * True to have a title bar - */ - property bool showTitleBar: true - - /** - * True to have draggable rulers for resizing - */ - property bool resizable: true - - /** - * True if plugin is in a standalone dialog - */ - property bool standalone: false - - /** - * The plugin name, which goes on the toolbar - */ - property alias pluginName: titleLabel.text - - /** - * ▁ - */ - property string dockIcon: "\u2581" - - /** - * ▼ - */ - property string collapseIcon: "\u25B4" - - /** - * ▲ - */ - property string expandIcon: "\u25BE" - - /** - * □ - */ - property string floatIcon: "\u25A1" - - /** - * ✕ - */ - property string closeIcon: "\u2715" - - /** - * The plugin backgroung color. Default: transparent - */ - property string cardBackground: "#00000000" - - /** - * - */ - property var backgroundItem: null - - /** - * Stores last height of plugin to expand to. - */ - property int lastHeight: 50 - - /** - * True if there's at least one anchor set for the card. - * There's no way to check the anchors themselves, so we need - * to keep track of this ourselves. - */ - property bool anchored: false - - /** - * Minimum width of the card pane - */ - property int cardMinimumWidth: 250; - - /** - * Minimum height of the card pane - */ - property int cardMinimumHeight: 250; - - /** - * Tool bar background color - */ - property string pluginToolBarColor: - typeof MainWindow === "undefined" || - MainWindow.pluginToolBarColorLight === "" || - MainWindow.pluginToolBarColorDark === "" ? - Material.accent : - (Material.theme === Material.Light) ? - MainWindow.pluginToolBarColorLight : MainWindow.pluginToolBarColorDark - - /** - * Tool bar text color - */ - property string pluginToolBarTextColor: - typeof MainWindow === "undefined" || - MainWindow.pluginToolBarTextColorLight === "" || - MainWindow.pluginToolBarTextColorDark === "" ? - Material.background : - (Material.theme === Material.Light) ? - MainWindow.pluginToolBarTextColorLight : MainWindow.pluginToolBarTextColorDark - - /** - * Close signal - */ - signal close() - - /** - * ID within QML - */ - id: cardPane - - /** - * Object name accessible from C++ - */ - objectName: "plugin" + Math.floor(Math.random() * 100000); - - // Stop scroll propagation to widgets below - MouseArea { - anchors.fill: parent - onWheel: { - wheel.accepted = true - } - } - - /** - * Callback when the parent has changed. - */ - onParentChanged: { - if (undefined === parent || null === parent) - return; - - // Bind anchors - anchors.fill = Qt.binding(function() {return parent}) - parent.height = Qt.binding(function() {return height}) - parent.width = Qt.binding(function() {return width}) - - // Keep a reference to the background - // TODO(louise) This feels hacky, the card shouldn't care about the background, - // but I haven't figured out yet how the card can tell IgnSplit to create - // a new split and add the card to it. There must be a way using signals, events - // or global functions...? - var bgItemTemp = helpers.ancestorByName(cardPane, "background") - if (bgItemTemp) - backgroundItem = bgItemTemp; - - this.syncTheFamily(); - } - - /** - * Forward the child content's size preferences to the parent split's layout - * TODO(louise) This looks really clunky, ideally the card shouldn't need - * any knowledge of splits - */ - function syncTheFamily() { - var parentSplit = helpers.ancestorByName(cardPane, /^split_item/); - - if (undefined == parentSplit) - return; - - if (content.children.length != 1) - return; - - parentSplit.Layout.minimumWidth = content.children[0].Layout.minimumWidth; - parentSplit.Layout.minimumHeight = content.children[0].Layout.minimumHeight; - } - - /** - * Clear all anchors - */ - function clearAnchors() { - cardPane.anchors.right = undefined - cardPane.anchors.left = undefined - cardPane.anchors.top = undefined - cardPane.anchors.bottom = undefined - cardPane.anchors.fill = undefined - cardPane.anchors.horizontalCenter = undefined - cardPane.anchors.verticalCenter = undefined - cardPane.anchors.baseline = undefined - - anchored = false - } - - IgnHelpers { - id: helpers - } - - // TODO(louise) Support choosing between: - // * a transparent background - // * a custom color, in which case there will be elevation - // Elevation only works if background is not transparent. -// Material.elevation: 6 - background: Rectangle { - color: "transparent" - } - - padding: 0 - - state: "docked" - - states: [ -// State { -// name: "cardWindow" -// ParentChange { -// target: cardPane; -// parent: cardWindowContent; -// x: 0 -// y: 0 -// width: cardWindowContent.width -// height: cardWindowContent.height -// } -// }, - // Floating and Docked state are the expanded states - State { - name: "docked" - }, - State { - name: "floating" - }, - // Docked collapsed state - State { - name: "docked_collapsed" - }, - // Floating collapsed state - State { - name: "floating_collapsed" - } - ] - - transitions: [ - Transition { - from: "docked" - to: "floating" - SequentialAnimation { - ScriptAction {script: leaveDockedState()} - ScriptAction {script: enterFloatingState()} - } - }, - Transition { - from: "floating" - to: "docked" - SequentialAnimation { - ScriptAction {script: leaveFloatingState()} - ScriptAction {script: enterDockedState()} - } - }, - Transition { - from: "floating" - to: "floating_collapsed" - NumberAnimation { - target: cardPane - property: "height" - duration: 200 - easing.type: Easing.OutCubic - from: cardPane.height - to: 50 - } - }, - Transition { - from: "floating_collapsed" - to: "floating" - NumberAnimation { - target: cardPane - property: "height" - duration: 200 - easing.type: Easing.InCubic - from: 50 - to: lastHeight - } - }, - Transition { - from: "floating_collapsed" - to: "docked" - SequentialAnimation { - ScriptAction {script: leaveFloatingState()} - ScriptAction {script: enterDockedState()} - } - }, - Transition { - from: "docked" - to: "docked_collapsed" - SequentialAnimation { - NumberAnimation { - target: cardPane - property: "parent.Layout.maximumHeight" - duration: 200 - easing.type: Easing.OutCubic - from: cardPane.height - to: 50 - } - ScriptAction {script: recalculateSplitSizes()} - } - }, - Transition { - from: "docked_collapsed" - to: "docked" - SequentialAnimation { - NumberAnimation { - target: cardPane - property: "parent.Layout.maximumHeight" - duration: 200 - easing.type: Easing.InCubic - from: 50 - to: backgroundItem.height - } - ScriptAction {script: recalculateSplitSizes()} - } - }, - Transition { - from: "docked_collapsed" - to: "floating" - SequentialAnimation { - ScriptAction {script: leaveDockedState()} - ScriptAction {script: enterFloatingState()} - } - }, - Transition { - from: "docked" - to: "floating_collapsed" - SequentialAnimation { - ScriptAction {script: leaveDockedState()} - ScriptAction {script: enterFloatingState()} - NumberAnimation { - target: cardPane - property: "height" - duration: 200 - easing.type: Easing.OutCubic - from: cardPane.height - to: 50 - } - } - }, - Transition { - from: "docked_collapsed" - to: "floating_collapsed" - SequentialAnimation { - ScriptAction {script: leaveDockedState()} - ScriptAction {script: enterFloatingState()} - } - }, - Transition { - from: "floating_collapsed" - to: "docked_collapsed" - SequentialAnimation { - ScriptAction {script: leaveFloatingState()} - ScriptAction {script: enterDockedState()} - } - } - ] - - /** - * Called when the docked state is entered. - */ - function enterDockedState() - { - // Add new split - var splitName = backgroundItem.addSplitItem(); - var splitItem = backgroundItem.childItems[splitName]; - - const collapsed = cardPane.height === 50 - - // Reparent to split - cardPane.parent = splitItem; - - // Retain collapsed or expanded state - cardPane.parent.Layout.minimumHeight = collapsed ? 50 : content.children[0].Layout.minimumHeight; - } - - /** - * Called when the floating state is entered. - */ - function enterFloatingState() - { - const collapsed = cardPane.parent.Layout.minimumHeight === 50; - // Reparent to main window's background - cardPane.parent = backgroundItem - - // Resize to minimum size - cardPane.clearAnchors(); - cardPane.width = content.children[0].Layout.minimumWidth; - - // Retain collapsed or expanded state - cardPane.height = collapsed ? 50 : content.children[0].Layout.minimumHeight; - lastHeight = content.children[0].Layout.minimumHeight; - } - - /** - * Called when the docked state is left. - */ - function leaveDockedState() - { - // Remove from split (delete split if needed) - backgroundItem.removeSplitItem(helpers.ancestorByName(cardPane, - /^split_item/).objectName) - } - - /** - * Called when the floating state is left. - */ - function leaveFloatingState() - { - // Do nothing - } - - /** - * Recalculate split sizes - */ - function recalculateSplitSizes() - { - backgroundItem.recalculateMinimumSizes(); - } - -// TODO(louise): re-enable window state support -// /** -// * Window for undocking -// */ -// Window { -// // TODO: resize -// width: cardPane.width; -// height: cardPane.height; -// visible: false; -// id: cardWindow -// -// Rectangle { -// id: cardWindowContent -// anchors.fill: parent -// } -// -// onClosing: { -// cardPane.state = "docked" -// } -// } - - /** - * Top toolbar - */ - ToolBar { - id: cardToolbar - objectName: "cardToolbar" - visible: cardPane.showTitleBar - Material.foreground: Material.foreground - Material.background: pluginToolBarColor - width: cardPane.width - height: cardPane.showTitleBar ? 50 : 0 - x: 0 - z: 100 - - // For drag - MouseArea { - anchors.fill: parent - drag { - target: cardPane - minimumX: 0 - minimumY: 0 - maximumX: cardPane.parent ? cardPane.parent.width - cardPane.width : cardPane.width - maximumY: cardPane.parent ? cardPane.parent.height - cardPane.height : cardPane.height - smoothed: true - } - } - - /** - * The toolbar contents - */ - RowLayout { - spacing: 0 - anchors.fill: parent - anchors.leftMargin: 10 - - Label { - id: titleLabel - font.pixelSize: 16 - color: pluginToolBarTextColor - elide: Label.ElideRight - horizontalAlignment: Qt.AlignHLeft - verticalAlignment: Qt.AlignVCenter - Layout.fillWidth: true - } - - // Dock / floating button - // TODO(louise) support window state - ToolButton { - id: dockButton - text: (cardPane.state === "docked" || cardPane.state === "docked_collapsed") ? floatIcon : dockIcon - contentItem: Text { - text: dockButton.text - font: dockButton.font - opacity: enabled ? 1.0 : 0.3 - color: cardPane.Material.background - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - visible: cardPane.showDockButton && !cardPane.standalone - onClicked: { - switch(cardPane.state) { - case "floating_collapsed": { - cardPane.state = "docked_collapsed" - break; - } - case "floating": { - cardPane.state = "docked" - break; - } - case "docked": { - cardPane.state = "floating" - break; - } - case "docked_collapsed": { - cardPane.state = "floating_collapsed" - break; - } - } - } - } - - // Collapse button - ToolButton { - id: collapseButton - visible: cardPane.showCollapseButton && !cardPane.standalone - text: cardPane.height <= 50.5 ? expandIcon : collapseIcon; - contentItem: Text { - text: collapseButton.text - font: collapseButton.font - opacity: enabled ? 1.0 : 0.3 - color: cardPane.Material.background - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - onClicked: { - switch(cardPane.state) { - case "floating_collapsed": { - cardPane.state = "floating" - break; - } - case "floating": { - // When user manually minimized the plugin using resize - if(cardPane.height === 50) { - // Handles the case when a floating plugin is loaded using config - if(lastHeight === 50) { - lastHeight = content.children[0].Layout.minimumHeight; - } - // Set state to floating collapsed and then expand for animation - cardPane.state = "floating_collapsed" - cardPane.state = "floating" - } else { - lastHeight = cardPane.height - // Set card state to collapsed - cardPane.state = "floating_collapsed" - } - break; - } - case "docked": { - cardPane.state = "docked_collapsed" - break; - } - case "docked_collapsed": { - cardPane.state = "docked" - break; - } - } - } - } - - // Close button - ToolButton { - id: closeButton - visible: cardPane.showCloseButton && !cardPane.standalone - text: closeIcon - contentItem: Text { - text: closeButton.text - font: closeButton.font - opacity: enabled ? 1.0 : 0.3 - color: cardPane.Material.background - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - onClicked: { - cardPane.close(); - } - } - } - } - - // For context menu - MouseArea { - anchors.fill: content - acceptedButtons: Qt.RightButton - onClicked: { - contextMenu.x = mouseX - contextMenu.y = mouseY - contextMenu.open() - } - } - - Menu { - id: contextMenu - transformOrigin: Menu.TopRight - MenuItem { - text: "Settings" - onTriggered: cardPane.showSettingsDialog(); - } - MenuItem { - text: "Close" - onTriggered: cardPane.close(); - } - } - - /** - * Show settings dialog - */ - function showSettingsDialog() { - settingsDialog.open() - } - - IgnCardSettings { - id: settingsDialog - modal: false - focus: true - title: pluginName + " settings" - parent: cardPane.parent - x: parent ? (parent.width - width) / 2 : 0 - y: parent ? (parent.height - height) / 2 : 0 - } - - /** - * Card contents - */ - Rectangle { - objectName: "content" - id: content - anchors.fill: parent - anchors.topMargin: cardPane.showTitleBar ? 50 : 0 - clip: true - color: cardBackground - - onChildrenChanged: { - // Set the height and width of the cardPane when child plugin is attached - if (children.length > 0) { - cardMinimumWidth = content.children[0].Layout.minimumWidth; - cardMinimumHeight = content.children[0].Layout.minimumHeight; - cardPane.width = cardMinimumWidth - cardPane.height = cardMinimumHeight - } - - cardPane.syncTheFamily() - } - - /** - * Conveniently expose card to children - */ - function card() { - return cardPane; - } - } - - IgnRulers { - anchors.fill: parent - enabled: cardPane.state === "floating" && resizable - minSize: cardPane.minSize - target: cardPane - } -} diff --git a/include/ignition/gui/qml/IgnCardSettings.qml b/include/ignition/gui/qml/IgnCardSettings.qml deleted file mode 100644 index 313fcf82e..000000000 --- a/include/ignition/gui/qml/IgnCardSettings.qml +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2018 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Window 2.2 -import QtQuick.Dialogs 1.0 -import "qrc:/qml" - -Dialog { - id: settingsDialog - - Column { - id: settingsColumn - anchors.horizontalCenter: settingsDialog.horizontalCenter - width: settingsDialog.width * 0.6 - - Switch { - id: titleSwitch - text: "Show title bar" - checked: cardPane.showTitleBar - onToggled: { - cardPane.showTitleBar = checked - // why is binding not working? - closeSwitch.enabled = checked - dockSwitch.enabled = checked - } - } - - Switch { - id: closeSwitch - text: "Show close button" - visible: !cardPane.standalone - enabled: cardPane.showTitleBar - checked: cardPane.showCloseButton - onToggled: { - cardPane.showCloseButton = checked - } - } - - Switch { - id: dockSwitch - text: "Show dock button" - visible: !cardPane.standalone - enabled: cardPane.showTitleBar - checked: cardPane.showDockButton - onToggled: { - cardPane.showDockButton = checked - } - } - - Switch { - id: collapseSwitch - text: "Show collapse button" - visible: !cardPane.standalone - enabled: cardPane.showTitleBar - checked: cardPane.showCollapseButton - onToggled: { - cardPane.showCollapseButton = checked - } - } - - Switch { - id: resizableSwitch - text: "Resizable" - visible: cardPane.state === "floating" - checked: cardPane.resizable - onToggled: { - cardPane.resizable = checked - } - } - - GridLayout { - width: parent.width - columns: 3 - visible: !cardPane.standalone - - Label { - text: "Background Color " - } - - Button { - Layout.preferredWidth: parent.width * 0.4 - onClicked: colorDialog.open() - background: Rectangle { - y: 8 - width: 50 - height: 30 - id: "bgColor" - color: cardBackground - border.color: "#000000" - border.width: 2 - } - } - } - - - GridLayout { - width: parent.width - columns: 2 - visible: cardPane.state === "floating" - - Label { - text: "Position" - font.weight: Font.DemiBold - } - - Text { - text: "" - } - - // TODO(louise) Support setting anchors from the dialog - Button { - visible: cardPane.anchored - text: "Clear anchors" - Layout.columnSpan: 2 - onClicked: { - cardPane.clearAnchors() - } - } - - IgnSpinBox { - visible: !cardPane.anchored - maximumValue: cardPane.parent ? cardPane.parent.width - cardPane.width : minSize - onVisibleChanged: value = cardPane.x - onValueChanged: { - cardPane.x = value; - } - } - Label { - visible: !cardPane.anchored - text: "X" - } - IgnSpinBox { - visible: !cardPane.anchored - maximumValue: cardPane.parent ? cardPane.parent.height - cardPane.height : minSize - onVisibleChanged: value = cardPane.y - onValueChanged: { - cardPane.y = value; - } - } - Label { - visible: !cardPane.anchored - text: "Y" - } - IgnSpinBox { - visible: !cardPane.anchored - maximumValue: 10000 - onVisibleChanged: value = cardPane.z - onValueChanged: { - cardPane.z = value; - } - } - Label { - visible: !cardPane.anchored - text: "Z" - } - Label { - text: "Size" - font.weight: Font.DemiBold - } - Text { - text: "" - } - IgnSpinBox { - maximumValue: cardPane.parent ? cardPane.parent.width : minSize - onVisibleChanged: { - if (cardPane) - value = cardPane.width - } - onValueChanged: { - cardPane.width = value; - } - } - Label { - text: "Width" - } - IgnSpinBox { - maximumValue: cardPane.parent ? cardPane.parent.height : minSize - onVisibleChanged: { - if (cardPane) - value = cardPane.height - } - onValueChanged: { - cardPane.height = value; - } - } - Label { - text: "Height" - } - } - } - - ColorDialog { - id: colorDialog - title: "Please choose a color" - showAlphaChannel : true - onAccepted: { - content.color = colorDialog.color - bgColor.color = colorDialog.color - cardBackground = colorDialog.color - } - onRejected: { - console.log("Canceled") - } - Component.onCompleted: visible = false - } -} diff --git a/include/ignition/gui/qml/IgnHelpers.qml b/include/ignition/gui/qml/IgnHelpers.qml deleted file mode 100644 index 57c0619b3..000000000 --- a/include/ignition/gui/qml/IgnHelpers.qml +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2018 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ -import QtQuick 2.9 - -Item { - /** - * Helper function to get an item's ancestor by name. - * @param _item Item whose parent we're looking for. - * @param _name Name to look for, accepts regex. - * @returns The ancestor, or undefined if not found. - */ - function ancestorByName(_item, _name) - { - if (_item === undefined) - return undefined; - - var result = _item.parent; - while (result) - { - if (result.objectName.match(_name) !== null) - break; - - result = result.parent; - } - - return result; - } -} diff --git a/include/ignition/gui/qml/IgnRulers.qml b/include/ignition/gui/qml/IgnRulers.qml deleted file mode 100644 index 1595389cd..000000000 --- a/include/ignition/gui/qml/IgnRulers.qml +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2018 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ -import QtQuick 2.9 -import QtQuick.Controls 2.2 - -/** - * Rulers which can be dragged to resize a target. - */ -Rectangle { - id: rulersRect - color: "transparent" - - /** - * Thickness of rulers - */ - property int rulersThickness: 25 - - /** - * Set to false so rulers disappear. - */ - property bool enabled: true - - /** - * Minimum length of each dimension - */ - property int minSize: 50 - - /** - * Target item to be resized by the rulers. - */ - property var target: null - - // Left ruler - Rectangle { - width: rulersThickness - height: parent.height - 20 - visible: rulersRect.enabled - color: "transparent" - anchors.horizontalCenter: parent.left - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - cursorShape: Qt.SplitHCursor - drag { target: parent; axis: Drag.XAxis } - onMouseXChanged: { - if (drag.active) - { - resizeLeft(target, mouseX); - } - } - } - } - - // Right ruler - Rectangle { - width: rulersThickness - height: parent.height - 20 - visible: rulersRect.enabled - color: "transparent" - anchors.horizontalCenter: parent.right - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - cursorShape: Qt.SplitHCursor - drag { target: parent; axis: Drag.XAxis } - onMouseXChanged: { - if (drag.active) - { - resizeRight(target, mouseX); - } - } - } - } - - // Top ruler - Rectangle { - width: parent.width - 20 - height: rulersThickness - visible: rulersRect.enabled - color: "transparent" - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.top - - MouseArea { - anchors.fill: parent - cursorShape: Qt.SplitVCursor - drag { target: parent; axis: Drag.YAxis } - onMouseYChanged: { - if (drag.active) - { - resizeTop(target, mouseY); - } - } - } - } - - // Bottom ruler - Rectangle { - width: parent.width - 20 - height: rulersThickness - visible: rulersRect.enabled - color: "transparent" - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.bottom - - MouseArea { - anchors.fill: parent - cursorShape: Qt.SplitVCursor - drag { target: parent; axis: Drag.YAxis } - onMouseYChanged: { - if (drag.active) - { - resizeBottom(target, mouseY); - } - } - } - } - - // Top-Left Ruler - Rectangle { - width: 25 - height: 25 - visible: rulersRect.enabled - color: "transparent" - anchors.horizontalCenter: parent.left - anchors.verticalCenter: parent.top - - MouseArea { - anchors.fill: parent - cursorShape: Qt.SizeFDiagCursor - drag { target: parent; axis: Drag.XAndYAxis } - onMouseYChanged: { - if (drag.active) - { - resizeTop(target, mouseY); - resizeLeft(target, mouseX); - } - } - } - } - - // Top-Right Ruler - Rectangle { - width: 25 - height: 25 - visible: rulersRect.enabled - color: "transparent" - anchors.horizontalCenter: parent.right - anchors.verticalCenter: parent.top - - MouseArea { - anchors.fill: parent - cursorShape: Qt.SizeBDiagCursor - drag { target: parent; axis: Drag.XAndYAxis } - onMouseYChanged: { - if (drag.active) - { - resizeTop(target, mouseY); - resizeRight(target, mouseX); - } - } - } - } - - // Bottom-Left Ruler - Rectangle { - width: 25 - height: 25 - visible: rulersRect.enabled - color: "transparent" - anchors.horizontalCenter: parent.left - anchors.verticalCenter: parent.bottom - - MouseArea { - anchors.fill: parent - cursorShape: Qt.SizeBDiagCursor - drag { target: parent; axis: Drag.XAndYAxis } - onMouseYChanged: { - if (drag.active) - { - resizeBottom(target, mouseY); - resizeLeft(target, mouseX); - } - } - } - } - - // Bottom-Right Ruler - Rectangle { - width: 25 - height: 25 - visible: rulersRect.enabled - color: "transparent" - anchors.horizontalCenter: parent.right - anchors.verticalCenter: parent.bottom - - MouseArea { - anchors.fill: parent - cursorShape: Qt.SizeFDiagCursor - drag { target: parent; axis: Drag.XAndYAxis } - onMouseYChanged: { - if (drag.active) - { - resizeBottom(target, mouseY); - resizeRight(target, mouseX); - } - } - } - } - - function resizeLeft(target, mouseX) - { - var newCardX = Math.max(target.x + mouseX, 0) - var newCardWidth = Math.max(target.width + (target.x - newCardX), - rulersRect.minSize, target.cardMinimumWidth) - - if (newCardWidth === target.width) - return; - - target.x = newCardX - target.width = newCardWidth - } - - function resizeRight(target, mouseX) - { - target.width = Math.max(target.width + mouseX, rulersRect.minSize, - target.cardMinimumWidth) - - if (target.width + target.x > target.parent.width) - target.width = target.parent.width - target.x - } - - function resizeTop(target, mouseY) - { - var newCardY = Math.max(target.y + mouseY, 0) - var newCardHeight = Math.max(target.height + (target.y - newCardY), - rulersRect.minSize, target.cardMinimumHeight) - - if (newCardHeight === target.height) - return; - - target.y = newCardY - target.height = newCardHeight - } - - function resizeBottom(target, mouseY) - { - target.height = Math.max(target.height + mouseY, rulersRect.minSize, - target.cardMinimumHeight) - - if (target.height + target.y > target.parent.height) - target.height = target.parent.height - target.y - } -} diff --git a/include/ignition/gui/qml/IgnSnackBar.qml b/include/ignition/gui/qml/IgnSnackBar.qml deleted file mode 100644 index f4f2dc3c8..000000000 --- a/include/ignition/gui/qml/IgnSnackBar.qml +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2022 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ - -import QtGraphicalEffects 1.0 -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.2 -import QtQuick.Dialogs 1.0 -import QtQuick.Layouts 1.3 -import QtQuick.Window 2.2 - -/* - To use the snackbar you need to call the methods in the MainWindow class: - - notify(message) - - notifyWithDuration(message, duration) - -For example: - // This code will show the message "Message" during one second - App()->findChild()->notifyWithDuration("Message", 1000); - - // This code will show the message "Message2" but the dialog will be there - // until you press the button "Dismiss" - App()->findChild()->notifyWithDuration("Message2"); -*/ - -Popup { - id: snackbar - modal: duration == 0 - focus: duration == 0 - x: (window.width - width) / 2 - y: window.height - window.height / 6 - width: window.width - window.width / 6 - contentHeight: Math.max(dismissButton.height, notificationText.height) - padding: 10 - - // If the popup has a Dismiss button, only close by pressing that. - // Otherwise, use the default behavior. - closePolicy: duration == 0 ? Popup.NoAutoClose : - Popup.CloseOnEscape | Popup.CloseOnPressOutside - - // Array that contains a dictionary with two keys "text" and "duration" - // This structure keeps the message to show using FIFO - property var popupArray: [] - - // Duration of the snackbar. If duration is equal to zero then - // you should click on the button "Dismiss" to close the dialog", - // otherwise you need to wait the duration defined. - property int duration: 0 - - // This method is called when the dialog is closed - onClosed: { - timer.stop() - checkArray(); - } - - background: Rectangle { - color: Material.background - layer.enabled: true - layer.effect: DropShadow { - color: "#aa000000" - samples: 9 - spread: 0 - radius: 8.0 - } - } - - // this function is called when notify() or notifyWithDuration() are called - function setTextDuration(_message, _duration) { - popupArray.push({"text": _message, "duration": _duration}) - checkArray(); - } - - // This method check if the popupArray has remaining messages to show. - function checkArray() - { - if (popupArray.length == 0) - { - return - } - - if(!timer.running) - { - if (popupArray.length > 0) - { - var values = popupArray[0] - notificationText.text = values.text - duration = values.duration - snackbar.open() - - // Note that objects cannot be individually added to or removed from - // the list once created; to modify the contents of a list, it must be - // reassigned to a new list. - var newpopupArray = [] - for (var i = 1; i < popupArray.length; i++) - { - newpopupArray.push(popupArray[i]) - } - - if (newpopupArray != undefined) - { - popupArray = newpopupArray - } - else - { - popupArray = [] - } - if (duration > 0) - { - timer.restart() - } - } - } - } - - contentItem: RowLayout { - id: contentLayout - height: dismissButton.height - anchors.verticalCenter: snackbar.verticalCenter - - Text { - id: notificationText - color: Material.theme == Material.Light ? "black" : "white" - wrapMode: Text.Wrap - font.pixelSize: 15 - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - } - Button { - id: dismissButton - visible: duration == 0 - flat: true - Layout.margins: 0 - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - background: Rectangle { - color: parent.down ? Material.color(Material.accent, Material.Shade400) : - (parent.hovered ? Material.color(Material.accent, Material.Shade200) : - "transparent") - } - font.pixelSize: 12 - text: "Dismiss" - onClicked: snackbar.close() - } - } - Timer { - id: timer - interval: snackbar.duration - onTriggered: { - if (!running) { - snackbar.close(); - } - checkArray(); - } - } - -} diff --git a/include/ignition/gui/qml/IgnSortFilterModel.qml b/include/ignition/gui/qml/IgnSortFilterModel.qml deleted file mode 100644 index f127d27ab..000000000 --- a/include/ignition/gui/qml/IgnSortFilterModel.qml +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2021 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ - -// Borrowed from -// https://martin.rpdev.net/2019/01/15/using-delegatemodel-in-qml-for-sorting-and-filtering.html - -import QtQuick 2.9 -import QtQml.Models 2.3 - -DelegateModel { - /** - * Used by sorting. Override it to create custom sort behaviour. - */ - property var lessThan: function(_left, _right) - { - return true; - } - - /** - * Override this function to define what items should be accepted or not. - */ - property var filterAcceptsItem: function(_item) - { - return true; - } - - /** - * Update the item list - */ - function update() { - if (items.count > 0) { - items.setGroups(0, items.count, "items"); - } - - // Step 1: Filter items - var visible = []; - for (var i = 0; i < items.count; ++i) { - var item = items.get(i); - if (filterAcceptsItem(item.model)) { - visible.push(item); - } - } - - // Step 2: Sort the list of visible items - visible.sort(function(_a, _b) { - return lessThan(_a.model, _b.model) ? -1 : 1; - }); - - // Step 3: Add all items to the visible group: - for (i = 0; i < visible.length; ++i) { - item = visible[i]; - item.inVisible = true; - if (item.visibleIndex !== i) { - visibleItems.move(item.visibleIndex, i, 1); - } - } - } - - items.onChanged: update() - onLessThanChanged: update() - onFilterAcceptsItemChanged: update() - - groups: DelegateModelGroup { - id: visibleItems - - name: "visible" - includeByDefault: false - } - - filterOnGroup: "visible" -} - diff --git a/include/ignition/gui/qml/IgnSpinBox.qml b/include/ignition/gui/qml/IgnSpinBox.qml deleted file mode 100644 index 800db5e11..000000000 --- a/include/ignition/gui/qml/IgnSpinBox.qml +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2018 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ -import QtQuick 2.9 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - -SpinBox { - style: SpinBoxStyle{ - background: Rectangle { - implicitWidth: 70 - implicitHeight: 40 - border.color: "gray" - } - } -} diff --git a/include/ignition/gui/qml/IgnSplit.qml b/include/ignition/gui/qml/IgnSplit.qml deleted file mode 100644 index d41ca0a45..000000000 --- a/include/ignition/gui/qml/IgnSplit.qml +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (C) 2018 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ -import QtQuick 2.9 -import QtQuick.Controls 1.1 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.1 -import QtQuick.Layouts 1.3 - -/** - * Main split view, which provides functions to add and remove child items - * and splits. - */ -SplitView { - - id: background - objectName: "background" - - IgnHelpers { - id: helpers - } - - /** - * Dictionary of all split items contained in this split. - */ - property variant childItems: new Object() - - /** - * Dictionary of all splits nested into this split. - */ - property variant childSplits: new Object() - - /** - * Callback when the height changed. - */ - onHeightChanged: - { - background.recalculateMinimumSizes(); - } - - Rectangle { - id: startLabel; - visible: MainWindow.pluginCount === 0 - anchors.fill: parent - color: Material.background - Label { - text: "Insert plugins to start!" - anchors.fill: parent - font.pointSize: 24 - horizontalAlignment: Label.AlignHCenter - verticalAlignment: Label.AlignVCenter - wrapMode: Label.Wrap - } - } - - /** - * Recalculate minimum size for all splits - */ - function recalculateMinimumSizes() - { - for (var name in childSplits) - { - childSplits[name].split.recalculateMinimumSize() - } - } - - /** - * This function will appropriately create new items and splits according to - * the current main window state. - * @return Name of added item, which is prefixed by `split_item_`. The item - * is empty, so the caller can add content to it. - * TODO(louise) Accept configuration, so we know how to add the item - * (orientation, size) - * TODO(louise) Make this more flexible so we can have different window - * arrangements - */ - function addSplitItem() - { - var itemName = ""; - - // First section goes in the top level SplitView, which is Qt.Horizontal - // 2 for helpers and startLabel - if (background.__items.length <= 2) - { - itemName = _addNewItem(background); - } - // The next one adds a Qt.Vertical split to the right - else if (Object.keys(childSplits).length === 0) - { - // Add the split - var split = _addNewSplit(background); - split.split.orientation = Qt.Vertical; - - // Then add a new item to the newly created split - itemName = _addNewItem(split); - } - // All subsequent ones are added to the vertical child split on the right - else - { - // Get desired split (for now we have only one) - var firstChildSplit = childSplits[Object.keys(childSplits)[0]]; - - // Then add a new item to it - itemName = _addNewItem(firstChildSplit); - } - - return itemName - } - - /** - * Remove a split item according to its name. - * @param Name of item, which must start with `split_item_`. - */ - function removeSplitItem(_name) - { - // Remove from split - _removeFromSplits(childItems[_name]); - - // Remove from dictionary and destroy - delete childItems[_name]; - } - - /** - * Create a new item and add it to a split. - * Meant for internal use. - * @param _split Split to add item to - * @return Unique name of newly created item; starts with `split_item_`. - */ - function _addNewItem(_split) - { - // Create item - var item = newItem.createObject(_split); - - // Unique name - var itemName = "split_item_" + Math.floor(Math.random() * 100000) - item.objectName = itemName; - - // Add to dictionary - childItems[itemName] = item; - - // Add to parent - if (_split === background) - { - _split.addItem(item); - } - else - { - _split.split.addItem(item); - - // Make sure that changes to the item's minimum size get propagated to the - // split. - item.minimumSizeChanged.connect(function(){ - _split.split.recalculateMinimumSize() - }); - } - - return itemName; - } - - /** - * Create a new split and add it to the parent split. - * Meant for internal use. - * @param _parentSplit Parent split. - * @returns Newly created split. - */ - function _addNewSplit(_parentSplit) - { - // Create split - var splitWrapper = newSplit.createObject(_parentSplit); - - // Unique name - var splitName = "split_" + Math.floor(Math.random() * 100000) - splitWrapper.objectName = splitName; - - // Add to dictionary - childSplits[splitName] = splitWrapper; - - // Add to parent - _parentSplit.addItem(splitWrapper); - - return splitWrapper; - } - - /** - * Removes item from its parent split and removes the split if that was - * the last item in it. - * Meant for internal use. - * @param _item Item who is supposed to be removed from its parent split. - */ - function _removeFromSplits(_item) - { - if (_item === undefined) - return; - - var split = helpers.ancestorByName(_item, /^split_|^background$/); - - if (!split) - { - console.error("Failed to find parent split for [", _item.objectName, "]") - return; - } - - if (split === background) - { - split.removeItem(_item); - } - else - { - split.split.removeItem(_item); - - // If split is now empty, remove split - if (split.split.__items.length === 0) - { - // Remove from array - delete childSplits[split.objectName] - - // Remove from parent split - _removeFromSplits(split); - - // Destroy - split.destroy(); - } - else - { - split.split.recalculateMinimumSize(); - } - } - } - - /** - * Component for creating new items - */ - Component { - id: newItem - - Rectangle { - Layout.minimumWidth: 100 - Layout.minimumHeight: 100 - Layout.fillHeight: false - Layout.fillWidth: true - color: Material.background - - /** - * Notifies that its minimum size has changed. - */ - signal minimumSizeChanged(); - - /** - * Callback when the layout's minimum width changes. - */ - Layout.onMinimumWidthChanged: { - minimumSizeChanged(); - } - - /** - * Callback when the layout's minimum height changes. - */ - Layout.onMinimumHeightChanged: { - minimumSizeChanged(); - } - - /** - * Callback when the children array has been changed. - */ - onChildrenChanged: { - // Propagate child's minimum size changes to the item. - newItem.Layout.minimumWidth = Qt.binding(function() { - if (children.length === 0 || children[0] === undefined) - return 0; - return children[0].Layout.minimumWidth - }); - newItem.Layout.minimumHeight = Qt.binding(function() { - if (children.length === 0 || children[0] === undefined) - return 0; - return children[0].Layout.minimumHeight - }); - } - } - } - - /** - * Component for creating new splits - */ - Component { - id: newSplit - - /** - * For some reason, the scroll view doesn't work well within a split view, - * so we wrap it in a rectangle. - */ - Rectangle { - id: splitWrapper - color: "transparent" - - /** - * Expose the split view. - */ - property var split: split - - /** - * Offset of 17 to accommodate for ScrollView scroll bar - */ - property var scrollBarWidth: 17 - - Layout.minimumWidth: split.Layout.minimumWidth + scrollBarWidth - Layout.minimumHeight: split.Layout.minimumHeight - - ScrollView { - contentHeight: split.height - contentWidth: split.width + scrollBarWidth - - ScrollBar.vertical.policy: ScrollBar.AlwaysOn - - // TODO(louise) This only works for a very specific split - height: window.height - window.header.height - - SplitView { - id: split - width: splitWrapper.width - scrollBarWidth - height: Math.max(childItems[Object.keys(childItems)[0]].height, - split.Layout.minimumHeight) - - /** - * Iterate over all current child items and update the split's minimum - * width accordingly. - */ - function recalculateMinimumSize() - { - // TODO(louise): generalize to support horizontal splits - if (orientation === Qt.Horizontal) - { - return; - } - - // Sync minimum sizes - var heightSum = 0; - var minHeightSum = 0; - for (var i = 0; i < __items.length; i++) - { - var child = __items[i]; - - // Minimum width matches the largest minimum width among children - if (child.Layout.minimumWidth > Layout.minimumWidth) - { - Layout.minimumWidth = child.Layout.minimumWidth; - } - heightSum += child.height; - - var collapsed = child.Layout.maximumHeight == 50 - minHeightSum += collapsed ? child.height : child.Layout.minimumHeight - } - - // Minimum height to show all children - Layout.minimumHeight = minHeightSum; - split.height = Math.max(minHeightSum, background.height); - - // Squish all children if there's no slack - if (heightSum > background.height) - { - for (var i = 0; i < __items.length; i++) - { - var child = __items[i]; - child.height = child.Layout.minimumHeight; - } - } - } - } - } - } - } -} - diff --git a/include/ignition/gui/qml/Main.qml b/include/ignition/gui/qml/Main.qml deleted file mode 100644 index 15d5ba89e..000000000 --- a/include/ignition/gui/qml/Main.qml +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (C) 2018 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.1 -import QtQuick.Dialogs 1.0 -import QtQuick.Layouts 1.3 -import ExitAction 1.0 -import "qrc:/qml" - -ApplicationWindow -{ - title: qsTr("Gazebo GUI") - width: 1200 - height: 1000 - minimumWidth: 300 - minimumHeight: 300 - visible: true - id: window - objectName: "window" - font.family: "Roboto" - - // Expose material properties to C++ - property string materialTheme: window.Material.theme - property string materialPrimary: window.Material.primary - property string materialAccent: window.Material.accent - property string toolBarColorLight: MainWindow.toolBarColorLight - property string toolBarTextColorLight: MainWindow.toolBarTextColorLight - property string toolBarColorDark: MainWindow.toolBarColorDark - property string toolBarTextColorDark: MainWindow.toolBarTextColorDark - property string pluginToolBarColorLight: MainWindow.pluginToolBarColorLight - property string pluginToolBarTextColorLight: MainWindow.pluginToolBarTextColorLight - property string pluginToolBarColorDark: MainWindow.pluginToolBarColorDark - property string pluginToolBarTextColorDark: MainWindow.pluginToolBarTextColorDark - // Expose config properties to C++ - property int defaultExitAction: MainWindow.defaultExitAction - property bool showDialogOnExit: MainWindow.showDialogOnExit - property string dialogOnExitText: MainWindow.dialogOnExitText - property bool exitDialogShowShutdown: MainWindow.exitDialogShowShutdown - property bool exitDialogShowCloseGui: MainWindow.exitDialogShowCloseGui - property string exitDialogShutdownText: MainWindow.exitDialogShutdownText - property string exitDialogCloseGuiText: MainWindow.exitDialogCloseGuiText - /** - * Flag to indicate if the close event was triggered by the close dialog. - */ - property bool closingFromDialog: false - - /** - * Tool bar background color - */ - property string toolBarColor: - MainWindow.toolBarColorLight === "" || - MainWindow.toolBarColorDark === "" ? - Material.primary : - (Material.theme === Material.Light) ? - MainWindow.toolBarColorLight : MainWindow.toolBarColorDark - - /** - * Tool bar text color - */ - property string toolBarTextColor: - MainWindow.toolBarTextColorLight === "" || - MainWindow.toolBarTextColorDark === "" ? - Material.background : - (Material.theme === Material.Light) ? - MainWindow.toolBarTextColorLight : MainWindow.toolBarTextColorDark - - // Not sure why the binding doesn't take care of this - onTitleChanged: { - titleLabel.text = window.title - } - - // Handler for window closing - onClosing: { - close.accepted = !showDialogOnExit - if(showDialogOnExit){ - if (closingFromDialog) { - close.accepted = true; - } else { - confirmationDialogOnExit.open() - } - } else if (defaultExitAction == ExitAction.SHUTDOWN_SERVER) { - MainWindow.OnStopServer() - } - } - - // C++ signals to QML slots - Connections { - target: MainWindow - onNotify: { - notificationDialog.setTextDuration(_message, 0) - } - onNotifyWithDuration: { - notificationDialog.setTextDuration(_message, _duration) - } - } - - /** - * Load a configuration file - */ - function loadConfig() { - loadFileDialog.open() - } - - /** - * Save a configuration file - */ - function saveConfig() { - MainWindow.OnSaveConfig() - } - - /** - * Save a configuration file to a given file - */ - function saveConfigAs() { - saveFileDialog.open() - } - - // Shortcuts (why not working on menu?) - Shortcut { - sequence: "Ctrl+O" - onActivated: loadConfig() - } - - Shortcut { - sequence: "Ctrl+S" - onActivated: saveConfig() - } - - Shortcut { - sequence: "Ctrl+Shift+S" - onActivated: saveConfigAs() - } - - Shortcut { - sequence: "Ctrl+Q" - onActivated: close() - } - - /** - * Top toolbar - */ - header: ToolBar { - Material.background: toolBarColor - Material.foreground: Material.foreground - - MouseArea { - anchors.fill: parent; - property variant clickPos: "1,1" - onPressed: { - clickPos = Qt.point(mouse.x,mouse.y) - } - onPositionChanged: { - var delta = Qt.point(mouse.x-clickPos.x, mouse.y-clickPos.y) - window.x += delta.x; - window.y += delta.y; - } - onDoubleClicked: { - window.showMaximized() - } - } - - RowLayout { - spacing: 20 - anchors.fill: parent - - ToolButton { - highlighted: true - visible: MainWindow.showDrawer - contentItem: Image { - fillMode: Image.Pad - horizontalAlignment: Image.AlignHCenter - verticalAlignment: Image.AlignVCenter - source: "images/drawer.png" - } - onClicked: drawer.open() - } - - // Padding for title - Rectangle { - height: 1 - width: 1 - visible: !MainWindow.showDrawer - color: "transparent" - } - - Label { - id: titleLabel - text: window.title - font.pixelSize: 18 - color: toolBarTextColor - elide: Label.ElideRight - horizontalAlignment: Qt.AlignHLeft - verticalAlignment: Qt.AlignVCenter - Layout.fillWidth: true - } - - ToolButton { - highlighted: true - visible: MainWindow.showPluginMenu - contentItem: Image { - fillMode: Image.Pad - horizontalAlignment: Image.AlignHCenter - verticalAlignment: Image.AlignVCenter - source: "images/menu.png" - } - onClicked: pluginMenu.open() - - PluginMenu { - id: pluginMenu - width: 200 - x: parent.width - width - height: window.height * 0.3 - transformOrigin: Popup.TopRight - } - } - } - } - - /** - * Background - */ - IgnSplit { - anchors.fill: parent - } - - /** - * Left menu - */ - SideDrawer { - id: drawer - interactive: MainWindow.showDrawer - width: Math.min(window.width * 0.3, 500) - height: window.height - } - - /** - * About dialog - */ - Dialog { - id: aboutDialog - modal: true - focus: true - title: "Gazebo GUI" - x: (window.width - width) / 2 - y: window.height / 6 - width: Math.min(window.width, window.height) / 3 * 2 - contentHeight: aboutColumn.height - - Column { - id: aboutColumn - spacing: 20 - - Label { - width: aboutDialog.availableWidth - text: "Gorgeous robotic interfaces since 2018." - wrapMode: Label.Wrap - font.pixelSize: 12 - } - } - } - - /** - * Style dialog - */ - StyleDialog { - id: styleDialog - x: (window.width - width) / 2 - y: window.height / 6 - width: Math.min(window.width, window.height) * 0.5 - } - - /** - * Load file dialog - */ - FileDialog { - id: loadFileDialog - title: "Load configuration" - folder: shortcuts.home - nameFilters: [ "Config files (*.config)" ] - selectMultiple: false - selectExisting: true - onAccepted: { - MainWindow.OnLoadConfig(fileUrl) - } - } - - /** - * Save file dialog - */ - FileDialog { - id: saveFileDialog - title: "Save configuration" - folder: shortcuts.home - nameFilters: [ "Config files (*.config)" ] - selectMultiple: false - selectExisting: false - onAccepted: { - var selected = fileUrl.toString(); - - if (!selected.endsWith(".config")) - { - selected += ".config"; - } - - MainWindow.OnSaveConfigAs(selected); - } - } - - IgnSnackBar { - id: notificationDialog - } - - Timer { - id: timer - } - - /** - * Confirmation dialog on close button - */ - Dialog { - id: confirmationDialogOnExit - title: (dialogOnExitText ? dialogOnExitText : "Do you really want to exit?") - objectName: "confirmationDialogOnExit" - - modal: true - focus: true - parent: ApplicationWindow.overlay - width: 500 - x: (parent.width - width) / 2 - y: (parent.height - height) / 2 - closePolicy: Popup.CloseOnEscape - standardButtons: - (exitDialogShowCloseGui ? Dialog.Ok : Dialog.NoButton) | - (exitDialogShowShutdown ? Dialog.Discard : Dialog.NoButton) | - Dialog.Cancel - - // The button texts need to be changed later than in onCompleted as standardButtons change later - onAboutToShow: function () { - if (exitDialogShowCloseGui && exitDialogCloseGuiText) - footer.standardButton(Dialog.Ok).text = exitDialogCloseGuiText - if (exitDialogShowShutdown) - footer.standardButton(Dialog.Discard).text = - (exitDialogShutdownText ? exitDialogShutdownText : "Shutdown server and GUI") - } - - footer: - DialogButtonBox { - onClicked: function (btn) { - if (btn == this.standardButton(Dialog.Ok)) { - closingFromDialog = true; - window.close(); - } - else if (btn == this.standardButton(Dialog.Discard)) { - MainWindow.OnStopServer() - // if GUI and server run in the same process, give server opportunity to kill the GUI - timer.interval = 100; - timer.repeat = false; - timer.triggered.connect(function() { - closingFromDialog = true; - window.close(); - }); - timer.start(); - } - } - } - } -} diff --git a/include/ignition/gui/qml/PlottingInterface.qml b/include/ignition/gui/qml/PlottingInterface.qml deleted file mode 100644 index 168d3a862..000000000 --- a/include/ignition/gui/qml/PlottingInterface.qml +++ /dev/null @@ -1,625 +0,0 @@ -/* - * Copyright (C) 2020 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ -import QtQuick 2.9 -import QtCharts 2.2 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Styles 1.4 -import QtQuick.Controls.Material 2.1 -import QtQuick.Layouts 1.3 -import Qt.labs.platform 1.0 -import "qrc:/qml" - -Rectangle -{ - id : main - /** - charts map < chart id, chart object> - */ - property var charts: ({}) - /** - id of the main chart of the view (the one with biggest size) - */ - property int mainChartID: 1 - - /** - variable to create thd IDs of the charts - */ - property int idIncrementor: 0 - - /** - True if the user has many charts (more than 2) - False if it has one chart or 2 - used to customize some UI features based on the mode - */ - property bool multiChartsMode: false - /** - export window - */ - property var window: null - - /** - add new chart to the view - */ - function addChart() - { - main.idIncrementor++; - - var chartComponent = Qt.createComponent("Chart.qml"); - var chartObject; - // if the mode is many charts that are organized in horizontal layout - if (multiChartsMode) - { - // add it to the horizontal layout - chartObject = chartComponent.createObject(rowChartsLayout); - chartObject.width = 200; - chartObject.height = Qt.binding( function() {return rowCharts.height * 0.9} ); - chartObject.y = Qt.binding( function() {return (rowCharts.height - chartObject.height)/2} ); - chartObject.multiChartsMode = true; - chartObject.fillPlotInOrOut() - } - else - { - // if normal mode, add the chart to the normal vertical layout - chartObject = chartComponent.createObject(chartsLayout); - chartObject.height = Qt.binding( function() {return chartsLayout.height / chartsLayout.heightFactor}); - chartObject.width = Qt.binding( function() {return chartsLayout.width}); - // to change the height of each vertical chart - chartsLayout.heightFactor ++ ; - } - - // Chart ID - chartObject.chartID = main.idIncrementor; - charts[idIncrementor] = chartObject; - // Signals and Slots - chartObject.subscribe.connect(main.onSubscribe); - chartObject.unSubscribe.connect(main.onUnSubscribe); - chartObject.componentSubscribe.connect(main.onComponentSubscribe); - chartObject.componentUnSubscribe.connect(main.onComponentUnSubscribe); - chartObject.clicked.connect(main.onClicked); - } - - /** - reallocate charts position, called at moving to multi charts mode - */ - function reallocateChart(_chart) - { - // new attributes to fit in the horizontal layout - _chart.width = 200; - _chart.height = Qt.binding( function() {return rowCharts.height * 0.9} ); - _chart.y = Qt.binding( function() {return (rowCharts.height - _chart.height)/2} ); - // enable that to enable the some UI features in the chart - _chart.multiChartsMode = true; - _chart.fillPlotInOrOut(); - - // change the layout from the vertical layout to the top horizontal one - _chart.parent = rowChartsLayout; - } - - function onSubscribe(_Id, _topic, _path) - { - PlottingIface.subscribe(_Id, _topic, _path); - } - function onUnSubscribe(_Id, _topic, _path) - { - PlottingIface.unsubscribe(_Id, _topic, _path); - } - function onComponentSubscribe(entity, typeId, type, attribute, Id) - { - PlottingIface.onComponentSubscribe(entity, typeId, type, attribute, Id); - } - function onComponentUnSubscribe(entity, typeId, attribute, Id) - { - PlottingIface.onComponentUnSubscribe(entity, typeId, attribute, Id); - } - - /** - on chart onClicked: - change the main chart to be the clicked chart - and swap it with the prev main chart - Id: id of the clicked chart - */ - function onClicked(Id) - { - // if many charts mode & the selected chart is in the horizontal layout - if (multiChartsMode && charts[Id].multiChartsMode) - { - // ======= main chart ========= - // change the main charts properties to fit in the horizontal layout - charts[mainChartID].width = 200; - charts[mainChartID].height = Qt.binding( function() {return rowCharts.height * 0.9} ); - charts[mainChartID].y = (rowCharts.height - charts[mainChartID].height)/2; - charts[mainChartID].multiChartsMode = true; - charts[mainChartID].fillPlotInOrOut(); - - // swap the main chart with the position of the clicked chart - charts[mainChartID].parent = rowChartsLayout; - - // ======= swapped chart ======= - charts[Id].parent = chartsLayout; - charts[Id].x = charts[mainChartID].x; - charts[Id].y = 0; - charts[Id].height = Qt.binding( function() {return chartsLayout.height / chartsLayout.heightFactor}); - charts[Id].width = Qt.binding( function() {return chartsLayout.width}); - charts[Id].multiChartsMode = false; - charts[Id].fillPlotInOrOut(); - charts[Id].setChartOpacity(1); - - mainChartID = Id; - } - } - - /** - fix the OpenGL disappear problem when the plugin is docked - */ - function fixOpenGL() - { - Object.keys(main.charts).forEach(function(key) { - main.charts[key].fixOpenGL(); - }); - } - - /** - plot point to a chart - _chart: chart id - _fieldID: field path or id - _x: x coordinates of the point - _y: y coordinates of the point - */ - function handlePlot(_chart, _fieldID, _x, _y) - { - charts[_chart].appendPoint(_fieldID, _x, _y); - } - - Connections { - target: PlottingIface - onPlot : handlePlot(_chart, _fieldID, _x, _y); - } - - - Layout.minimumWidth: 600 - Layout.minimumHeight: 600 - anchors.fill: parent - color: (Material.theme == Material.Light) ? Material.color(Material.Grey,Material.Shade100) : Material.background - - // when the chart is docked fix the OpenGL Disappear problem - onWidthChanged: { - main.fixOpenGL(); - } - - // Horizonal Layout to hold multi charts (small charts) - Rectangle { - id: rowCharts - width: parent.width - height: (multiChartsMode) ? 150 : 0 - color: (Material.theme == Material.Light) ? Material.color(Material.Grey,Material.Shade200) - : Material.color(Material.BlueGrey, Material.Shade800) - // Make it Scrolable - ScrollView { - anchors.fill: parent - ScrollBar.horizontal.policy: ScrollBar.AsNeeded - ScrollBar.vertical.policy: ScrollBar.AlwaysOff - clip: true - // Horizontal Layout for the Charts - Row { - id:rowChartsLayout - anchors.fill: parent - spacing: 10 - } - } - } - - // Vertical Layout to hold Main Charts (1 or 2 charts) - Column { - id : chartsLayout - - /** - factor to customize the height of the Charts based on their number - */ - property int heightFactor: 0 - - width: parent.width - anchors.topMargin: 10 - anchors.top: rowCharts.bottom - anchors.bottom: parent.bottom - } - - Rectangle { - id : addBtn - - anchors.right: openExport.left - anchors.top: parent.top - anchors.margins: 15 - - width: 40 - height: 40 - radius: width/2 - color: Material.accentColor - Text { - text: "+" - font.weight: Font.Bold - font.pixelSize: parent.width/2 - color: "white" - anchors.centerIn: parent - } - - MouseArea { - id: mouseAddBtn - anchors.fill: parent - hoverEnabled: true - onEntered: { addBtn.opacity = 0.8; cursorShape = Qt.PointingHandCursor; } - onExited: { addBtn.opacity = 1; cursorShape = Qt.ArrowCursor; } - - onClicked: { - if (Object.keys(charts).length == 2) - { - multiChartsMode = true; - var firstChart = true; - for (var i = 0; i < chartsLayout.children.length; i++) - { - // skip the first one - if (firstChart) - { - firstChart = false; - // make that chart has a full size - chartsLayout.heightFactor = 1 - continue; - } - var chart = chartsLayout.children[i]; - reallocateChart(chart); - } - } // end if - - addChart(); - } - } - - ToolTip.text: "Add Chart" - ToolTip.delay: 500 - ToolTip.timeout: 1000 - ToolTip.visible: mouseAddBtn.containsMouse - } - - Component.onCompleted: { - addChart(); - } - - ToolButton { - id: openExport - width: 40; - height: 40; - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: 15 - onHoveredChanged: (opacity === 1) ? opacity = 0.8 : opacity = 1; - - background: Rectangle{ - id: background - anchors.fill: parent - radius: width/2 // circle - - color: "transparent" - border.width: 1 - border.color: Material.color(Material.Grey, Material.Shade500) - } - - Image { - id: exportIcon - /** - size factor - */ - property double factor: 0.65 - width: background.width * factor; - height: background.height * factor; - anchors.centerIn: background - sourceSize.width: background.width * factor; - sourceSize.height: background.height * factor; - source: "images/export_icon.png" - } - - ToolTip.text: "Export"; - ToolTip.visible: openExport.hovered - ToolTip.delay: 500 - ToolTip.timeout: 1000 - - onClicked: { - if (main.window) - main.window.destroy() - - main.window = exportWindow.createObject(); - main.window.setCharts(main.charts); - main.window.setBackgroundColor(main.color); - main.window.setPrimaryColor(Material.primaryColor) - main.window.show(); - } - } - - Component { - id : exportWindow - ApplicationWindow { - id: exportApp - - /** - flag indicated if the chart is in small mode - */ - property bool isSmallChart: false - /** - charts objects that is loaded in the export window - */ - property var charts: [] - /** - index of the selected chart - */ - property int index: 0 - - /** - charts images that is displayed in the export window - */ - property var chartImages: [] - - /** - add chart copy/image to the export window - */ - function addChartCopy(result) - { - var imageObject = chartCopy.createObject(grid); - imageObject.setSource(result.url); - - imageObject.setChartName("Plot" + charts[index].chartID.toString()); - imageObject.chartIndex = index; - - chartImages.push(imageObject); - - index++; - continueCopy(); - } - - /** - set/add all the charts in the PlottingInterface to the export window - */ - function setCharts(_charts) - { - // clear - charts = [] - chartImages = [] - - Object.keys(_charts).forEach(function(key) { - charts.push(_charts[key]); - }); - - continueCopy(); - } - - /** - continue the process of the copy - Grabbing image takes time and we should continue after the image callback - */ - function continueCopy() - { - if (index < charts.length) - charts[index].getChart().grabToImage(addChartCopy); - } - - /** - export all selected charts in the export window to that path - */ - function exportCSV(path) - { - for (var i = 0; i < chartImages.length; i++) - { - if (!chartImages[i].isSelected()) - continue; - - var chart = charts[chartImages[i].chartIndex]; - var serieses = chart.getChart().getAllSerieses(); - var chart_id = chart.chartID; - - if (Object.keys(serieses).length === 0) - continue; - - - // convert Serieses to Map of {series_name : points list} - // slots in cpp accepts QMap - // QVariant could be a list instead of series object - - var chartSerieses = {}; - var seriesArray = []; - Object.keys(serieses).forEach(function(key) { - - seriesArray = [] - - // convert Series to QList - for (var j =0; j < serieses[key].count; j++) - seriesArray.push(serieses[key].at(j)); - - // add series - chartSerieses[key] = seriesArray; - }); - - return PlottingIface.exportCSV(path, chart_id, chartSerieses); - } - } - - /** - set the background color of the export widget - */ - function setBackgroundColor(_color) - { - exportWidget.color = _color; - } - - /** - set color of the export button - */ - function setPrimaryColor(_color) - { - exportBtn.color = _color; - } - - width: 1000; height: 600 - title: "Plotting Export" - - Rectangle { - color: (Material.theme === Material.Light) ? Material.color(Material.Grey, Material.Shade200) : - Material.color(Material.Grey, Material.Shade900) - anchors.fill: parent - id: exportWidget - - // make it scrolable - ScrollView { - width: parent.width - height: parent.height - exportBtn.height * 1.5 - ScrollBar.vertical.policy: ScrollBar.AlwaysOn - clip: true - - Grid { - id: grid - anchors.fill: parent - spacing: 10 - padding: 30 - columns: (exportWidget.width)/ 300 - } - } - - ComboBox { - id: exportBtn - - property string color: Material.primaryColor - - displayText: "Export to" - model: ["CSV"] - - background: Rectangle { - implicitWidth: 120 - implicitHeight: 40 - radius: 10 - color: parent.color; - } - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.margins: 10 - - onActivated: { - fileDialog.open(); - } - } - Rectangle { - id: cancelBtn - color: Material.color(Material.Grey, Material.Shade600); - implicitWidth: 120 - implicitHeight: 40 - radius: 10 - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.margins: 10 - Text { - text: "Cancel" - anchors.centerIn: parent - color: "white" - } - MouseArea { - anchors.fill: parent - hoverEnabled: true - onEntered: parent.opacity = 0.9; cursorShape: Qt.PointingHandCursor - onExited: parent.opacity = 1; - onClicked: exportApp.close() - } - } - } - - FolderDialog { - id: fileDialog - title: "Choose a folder" - visible: false - options: FolderDialog.ShowDirsOnly - - onAccepted: { - if (exportBtn.currentText == "CSV") - { - var success = exportApp.exportCSV(folder); - if (success) - exportApp.close(); - } - } - onRejected: fileDialog.close(); - } - - /** - Image/Copy of the Chart - */ - Component { - id: chartCopy - Column - { - /** - set the image source - */ - function setSource(url) - { - image.source = url; - } - /** - get the source of the grapped image - */ - function getSource() - { - return image.source - } - /** - set displayed name of the chart - */ - function setChartName(name) - { - checkboxText.text = name; - } - /** - check if the chart is selected to export - True if selected - */ - function isSelected() - { - return checkbox.checked; - } - - /** - index of the assosiated chart object in the charts array - */ - property int chartIndex: 0 - - width: 300 - height: 250 - Image { - id: image - width: parent.width - height: parent.height - 50 - } - CheckBox { - id: checkbox - x: image.width / 2 - 50 - checkState: Qt.Unchecked - Text { - id: checkboxText - anchors.left: parent.right - anchors.verticalCenter: parent.verticalCenter - color: Material.color(Material.Grey, Material.Shade500) - leftPadding: 5 - } - } - } - } - } - } -} diff --git a/include/ignition/gui/qml/PluginMenu.qml b/include/ignition/gui/qml/PluginMenu.qml deleted file mode 100644 index 68de63a7c..000000000 --- a/include/ignition/gui/qml/PluginMenu.qml +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2018 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.2 -import QtQuick.Controls.Material.impl 2.2 -import QtQuick.Layouts 1.3 - -Popup { - id: pluginMenu - padding: 0 - - Connections { - target: MainWindow - onConfigChanged: { - filteredModel.model = MainWindow.PluginListModel() - } - } - - /** - * Color for search bar - */ - property color searchColor: (Material.theme == Material.Light) ? - Material.color(Material.Grey, Material.Shade200): - Material.color(Material.Grey, Material.Shade900); - - onOpened: searchField.forceActiveFocus() - - ColumnLayout { - anchors.fill: parent - spacing: 0 - - Rectangle { - id: searchSortBar - color: searchColor - height: 50 - width: parent.width - RowLayout { - id: rowLayout - anchors.fill: parent - spacing: 0 - Rectangle { - color: "transparent" - height: 25 - width: 25 - Layout.leftMargin: 5 - Image { - id: searchIcon - source: "images/search.svg" - anchors.verticalCenter: parent.verticalCenter - } - } - TextField { - id: searchField - Layout.fillHeight: true - Layout.preferredWidth: parent.width - 50 - selectByMouse: true - onTextEdited: { - filteredModel.update(); - } - } - } - } - - ListView { - id: pluginMenuListView - Layout.fillHeight: true - width: parent.width - clip: true - - model: filteredModel - - ScrollBar.vertical: ScrollBar { - active: true - width: 8 - policy: ScrollBar.AlwaysOn - } - } - } - - IgnSortFilterModel { - id: filteredModel - - filterAcceptsItem: function(item) { - var itemStr = item.modelData.toLowerCase(); - var filterStr = searchField.text.toLowerCase(); - return itemStr.includes(filterStr); - } - - model: MainWindow.PluginListModel() - - delegate: ItemDelegate { - width: parent.width - text: modelData - highlighted: ListView.isCurrentItem - onClicked: { - MainWindow.OnAddPlugin(modelData); - drawer.close() - pluginMenu.close() - } - } - } -} - diff --git a/include/ignition/gui/qml/SideDrawer.qml b/include/ignition/gui/qml/SideDrawer.qml deleted file mode 100644 index 3b6c63c9f..000000000 --- a/include/ignition/gui/qml/SideDrawer.qml +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2018 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.1 - -/** - * Side menu - */ -Drawer { - - Rectangle { - objectName: "sideDrawer" - id: sideDrawer - anchors.fill: parent - color: Material.background - - function closeDrawer() { - drawer.close(); - } - - function onAction(action) { - switch(action) { - case "loadConfig": - loadConfig() - break - case "saveConfig": - saveConfig() - break - case "saveConfigAs": - saveConfigAs() - break - case "styleSettings": - styleDialog.open() - break - case "aboutDialog": - aboutDialog.open() - break - case "close": - window.close() - break - default: - break - } - } - - ListModel { - id: drawerModel - - ListElement { - title: "Load configuration" - actionElement: "loadConfig" - } - ListElement { - title: "Save configuration" - actionElement: "saveConfig" - } - ListElement { - title: "Save configuration as" - actionElement: "saveConfigAs" - } - ListElement { - title: "Style settings" - actionElement: "styleSettings" - } - ListElement { - title: "About" - actionElement: "aboutDialog" - } - ListElement { - title: "Quit" - actionElement: "close" - } - } - - ListView { - id: listView - anchors.fill: parent - visible: MainWindow.showDefaultDrawerOpts - - delegate: ItemDelegate { - width: parent.width - text: title - highlighted: ListView.isCurrentItem - onClicked: { - sideDrawer.onAction(actionElement) - sideDrawer.closeDrawer(); - } - } - - model: drawerModel - - ScrollIndicator.vertical: ScrollIndicator { } - } - } -} diff --git a/include/ignition/gui/qml/StandaloneDialog.qml b/include/ignition/gui/qml/StandaloneDialog.qml deleted file mode 100644 index a55864499..000000000 --- a/include/ignition/gui/qml/StandaloneDialog.qml +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2018 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ -import QtQuick 2.3 -import QtQuick.Controls 1.2 - -ApplicationWindow { - id: dialog - visible: true -} diff --git a/include/ignition/gui/qml/StyleDialog.qml b/include/ignition/gui/qml/StyleDialog.qml deleted file mode 100644 index 7845f2ed2..000000000 --- a/include/ignition/gui/qml/StyleDialog.qml +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright (C) 2018 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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. - * -*/ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.1 -import QtQuick.Dialogs 1.0 - -/** - * Style dialog - */ -Dialog { - - // Inherited properties - id: styleDialog - modal: false - focus: true - title: "Style settings" - contentHeight: styleColumn.height - - // Custom properties - property int initialPrimary: -1 - property int initialAccent: -1 - property int initialTheme: -1 - property int foregroundShade: Material.Shade500 - - /** - * ✎ - */ - property string editIcon: "\u270E" - - /** - * Array with all pre-defined material colors. - * Must match materialColorEnums - */ - property var materialColorStrs: [ - "Red", - "Pink", - "Purple", - "DeepPurple", - "Indigo", - "Blue", - "LightBlue", - "Cyan", - "Teal", - "Green", - "LightGreen", - "Lime", - "Yellow", - "Amber", - "Orange", - "DeepOrange", - "Brown", - "Grey", - "BlueGrey", - ] - - /** - * Array with all pre-defined material colors - * Must match materialColorStrs - */ - property var materialColorEnums: [ - Material.Red, - Material.Pink, - Material.Purple, - Material.DeepPurple, - Material.Indigo, - Material.Blue, - Material.LightBlue, - Material.Cyan, - Material.Teal, - Material.Green, - Material.LightGreen, - Material.Lime, - Material.Yellow, - Material.Amber, - Material.Orange, - Material.DeepOrange, - Material.Brown, - Material.Grey, - Material.BlueGrey, - ] - - // Connections (C++ signal to QML slot) - Connections { - target: MainWindow - onMaterialThemeChanged: { - updateTheme(MainWindow.materialTheme); - } - } - - Connections { - target: MainWindow - onMaterialPrimaryChanged: { - updatePrimary(MainWindow.materialPrimary); - } - } - - Connections { - target: MainWindow - onMaterialAccentChanged: { - updateAccent(MainWindow.materialAccent); - } - } - - /** - * Convert a color component (R/G/B/A) to hex - * @param type:int _c Color in the 0~1 range - */ - function componentToHex(_c) { - _c = (_c * 255) | 0; - var hex = _c.toString(16); - return hex.length == 1 ? "0" + hex : hex; - } - - /** - * Convert a color object to a hex string - * @param type:color _color Color object - */ - function colorToHex(_color) { - return "#" + componentToHex(_color.r) - + componentToHex(_color.g) - + componentToHex(_color.b); - } - - /** - * Update primary color - * @param type:string _primary Optional color name - */ - function updatePrimary(_primary) { - - var index = -1; - - // When setting from MainWindow / ColorDialog - if (typeof _primary === "string") - { - index = materialColorStrs.indexOf(_primary) - } - // When setting from combo box - else if (materialPrimaryCombo.currentIndex !== -1) - { - index = materialPrimaryCombo.currentIndex - } - else - { - return; - } - - var c; - - // One of the material colors - if (index !== -1) - { - c = Material.color(materialColorEnums[index], foregroundShade); - materialPrimaryCombo.currentIndex = index; - } - // Custom color - else if (_primary.length !== 0) - { - c = _primary; - materialPrimaryCombo.currentIndex = -1; - materialPrimaryCombo.editText = _primary; - } - else - { - return; - } - window.Material.primary = c - } - - /** - * Update accent color - * @param type:string _accent Optional color name - */ - function updateAccent(_accent) { - - var index = -1; - - // When setting from MainWindow / ColorDialog - if (typeof _accent === "string") - { - index = materialColorStrs.indexOf(_accent) - } - // When setting from combo box - else if (materialAccentCombo.currentIndex !== -1) - { - index = materialAccentCombo.currentIndex - } - else - { - return; - } - - var c; - - // One of the material colors - if (index !== -1) - { - c = Material.color(materialColorEnums[index], foregroundShade); - materialAccentCombo.currentIndex = index; - } - // Custom color - else if (_accent.length !== 0) - { - c = _accent; - materialAccentCombo.currentIndex = -1; - materialAccentCombo.editText = _accent; - } - else - { - return; - } - window.Material.accent = c - } - - /** - * Update theme - * @param type:string _theme Optional theme name - */ - function updateTheme(_theme) { - - // Change theme - if (typeof _theme === "string" && _theme.length !== 0) - { - - materialThemeCombo.currentIndex = _theme === "Light" ? 0 : 1; - } - else if (materialThemeCombo.currentIndex !== -1) - { - _theme = materialThemeCombo.currentText - } - else - return; - - if (_theme === "Light") - { - window.Material.theme = Material.Light - foregroundShade = Material.Shade500 - } - else - { - window.Material.theme = Material.Dark - foregroundShade = Material.Shade200 - } - - // Update all colors according to new shade - updatePrimary(); - updateAccent(); - } - - /** - * Lifecycle hook - */ - Component.onCompleted: { - - // Get initial values - for (var i = 0; i < materialColorEnums.length; ++i) - { - var hex = colorToHex(Material.color(materialColorEnums[i])) - if (hex == window.Material.primary) - { - initialPrimary = i; - } - if (hex == window.Material.accent) - { - initialAccent = i; - } - } - - initialTheme = window.Material.theme - } - - Column { - id: styleColumn - anchors.horizontalCenter: styleDialog.horizontalCenter - width: styleDialog.width * 0.6 - - // TODO(anyone) extend to universal / default styles, beware that - // changing style at runtime doesn't seem to be supported, but we could save - // and prompt the user to restart - Label { - text: "Material style" - font.weight: Font.Bold - } - - Label { - text: "Theme" - } - - ComboBox { - id: materialThemeCombo - width: styleColumn.width - currentIndex: initialTheme - model: ["Light", "Dark"] - delegate: ItemDelegate { - text: modelData - width: parent.width - } - onCurrentTextChanged: { - updateTheme(); - } - } - - Label { - text: "Primary" - } - - ColorDialog { - id: materialPrimaryDialog - title: "Primary color" - // options: ColorDialog.NoButtons - onCurrentColorChanged: { - - // Avoiding pure black because for some reason it is set to that as the - // dialog opens - if (currentColor == "#000000") - return; - - updatePrimary(colorToHex(currentColor)) - } - } - - Row { - ComboBox { - id: materialPrimaryCombo - width: styleColumn.width - editable: true - // selectByMouse: true - currentIndex: initialPrimary - displayText: currentText - model: materialColorStrs - delegate: ItemDelegate { - text: materialColorStrs[index] - width: parent.width - } - onCurrentTextChanged: { - updatePrimary() - } - } - - ToolButton { - text: "\u270E" - font.pixelSize: 20 - onClicked: { - materialPrimaryDialog.open() - } - } - } - - Label { - text: "Accent" - } - - ColorDialog { - id: materialAccentDialog - title: "Accent color" - // options: ColorDialog.NoButtons - onCurrentColorChanged: { - - // Avoiding pure black because for some reason it is set to that as the - // dialog opens - if (currentColor == "#000000") - return; - - updateAccent(colorToHex(currentColor)) - } - } - - Row { - ComboBox { - id: materialAccentCombo - width: styleColumn.width - editable: true - // selectByMouse: true - currentIndex: initialAccent - displayText: currentText - model: materialColorStrs - delegate: ItemDelegate { - text: materialColorStrs[index] - width: parent.width - } - onCurrentIndexChanged: { - updateAccent() - } - } - - ToolButton { - text: "\u270E" - font.pixelSize: 20 - onClicked: { - materialAccentDialog.open() - } - } - } - } -} diff --git a/include/ignition/gui/qml/images/drawer.png b/include/ignition/gui/qml/images/drawer.png deleted file mode 100644 index bb1cd2fe4..000000000 Binary files a/include/ignition/gui/qml/images/drawer.png and /dev/null differ diff --git a/include/ignition/gui/qml/images/export_icon.png b/include/ignition/gui/qml/images/export_icon.png deleted file mode 100644 index 50ef4e445..000000000 Binary files a/include/ignition/gui/qml/images/export_icon.png and /dev/null differ diff --git a/include/ignition/gui/qml/images/menu.png b/include/ignition/gui/qml/images/menu.png deleted file mode 100644 index a10473d9e..000000000 Binary files a/include/ignition/gui/qml/images/menu.png and /dev/null differ diff --git a/include/ignition/gui/qml/images/search.svg b/include/ignition/gui/qml/images/search.svg deleted file mode 100644 index 40ab947b2..000000000 --- a/include/ignition/gui/qml/images/search.svg +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/include/ignition/gui/qml/qmldir b/include/ignition/gui/qml/qmldir deleted file mode 100644 index f4f66ebc1..000000000 --- a/include/ignition/gui/qml/qmldir +++ /dev/null @@ -1,3 +0,0 @@ -module ignition.gui - -IgnSpinBox 1.0 IgnSpinBox.qml \ No newline at end of file diff --git a/include/ignition/gui/qtquickcontrols2.conf b/include/ignition/gui/qtquickcontrols2.conf deleted file mode 100644 index 7fc23bec9..000000000 --- a/include/ignition/gui/qtquickcontrols2.conf +++ /dev/null @@ -1,7 +0,0 @@ -[Controls] -Style=Material - -[Material] -Theme=Light -Accent=LightBlue -Primary=DeepOrange diff --git a/include/ignition/gui/resources.qrc b/include/ignition/gui/resources.qrc deleted file mode 100644 index cb9fb5683..000000000 --- a/include/ignition/gui/resources.qrc +++ /dev/null @@ -1,47 +0,0 @@ - - - qtquickcontrols2.conf - - qml/Chart.qml - qml/IgnCard.qml - qml/IgnCardSettings.qml - qml/IgnHelpers.qml - qml/IgnRulers.qml - qml/IgnSnackBar.qml - qml/IgnSortFilterModel.qml - qml/IgnSpinBox.qml - qml/IgnSplit.qml - qml/Main.qml - qml/PlottingInterface.qml - qml/PluginMenu.qml - qml/SideDrawer.qml - qml/StandaloneDialog.qml - qml/StyleDialog.qml - - qml/images/gazebo_logo.png - qml/images/drawer.png - qml/images/menu.png - qml/images/export_icon.png - qml/images/search.svg - - qml/IgnCard.qml - qml/IgnCardSettings.qml - qml/IgnHelpers.qml - qml/IgnRulers.qml - qml/IgnSnackBar.qml - qml/IgnSortFilterModel.qml - qml/IgnSpinBox.qml - qml/IgnSplit.qml - qml/IgnSnackBar.qml - qml/IgnSpinBox.qml - - - - qml/qmldir - - qml/IgnSnackBar.qml - qml/IgnSpinBox.qml - qml/IgnSnackBar.qml - qml/IgnSpinBox.qml - - diff --git a/src/Plugin.cc b/src/Plugin.cc index 7c9a07ebc..fb53e5b09 100644 --- a/src/Plugin.cc +++ b/src/Plugin.cc @@ -424,7 +424,7 @@ QQuickItem *Plugin::CardItem() const return this->dataPtr->cardItem; // Instantiate a card - std::string qmlFile(":qml/IgnCard.qml"); + std::string qmlFile(":qml/GzCard.qml"); QQmlComponent cardComp(App()->Engine(), QString(QString::fromStdString(qmlFile))); auto cardItem = qobject_cast(cardComp.create());