Merge branch 'master' into feature-backup-manager

This commit is contained in:
ChrisTerBeke 2018-05-14 09:00:00 +02:00
commit 0a75a2b332
13 changed files with 229 additions and 272 deletions

View File

@ -97,6 +97,7 @@ class CuraPackageManager(QObject):
def _removeAllScheduledPackages(self) -> None: def _removeAllScheduledPackages(self) -> None:
for package_id in self._to_remove_package_set: for package_id in self._to_remove_package_set:
self._purgePackage(package_id) self._purgePackage(package_id)
del self._installed_package_dict[package_id]
self._to_remove_package_set.clear() self._to_remove_package_set.clear()
self._saveManagementData() self._saveManagementData()
@ -130,7 +131,6 @@ class CuraPackageManager(QObject):
return None return None
def getAllInstalledPackagesInfo(self) -> dict: def getAllInstalledPackagesInfo(self) -> dict:
# Add bundled, installed, and to-install packages to the set of installed package IDs # Add bundled, installed, and to-install packages to the set of installed package IDs
all_installed_ids = set() all_installed_ids = set()
@ -150,6 +150,7 @@ class CuraPackageManager(QObject):
if package_id in Application.getInstance().getRequiredPlugins(): if package_id in Application.getInstance().getRequiredPlugins():
continue continue
package_info = None
# Add bundled plugins # Add bundled plugins
if package_id in self._bundled_package_dict: if package_id in self._bundled_package_dict:
package_info = self._bundled_package_dict[package_id]["package_info"] package_info = self._bundled_package_dict[package_id]["package_info"]
@ -162,17 +163,14 @@ class CuraPackageManager(QObject):
if package_id in self._to_install_package_dict: if package_id in self._to_install_package_dict:
package_info = self._to_install_package_dict[package_id]["package_info"] package_info = self._to_install_package_dict[package_id]["package_info"]
if package_info is None:
continue
# We also need to get information from the plugin registry such as if a plugin is active # We also need to get information from the plugin registry such as if a plugin is active
if package_info["package_type"] == "plugin":
package_info["is_active"] = self._plugin_registry.isActivePlugin(package_id)
else:
package_info["is_active"] = self._plugin_registry.isActivePlugin(package_id) package_info["is_active"] = self._plugin_registry.isActivePlugin(package_id)
# If the package ID is in bundled, label it as such # If the package ID is in bundled, label it as such
if package_info["package_id"] in self._bundled_package_dict.keys(): package_info["is_bundled"] = package_info["package_id"] in self._bundled_package_dict.keys()
package_info["is_bundled"] = True
else:
package_info["is_bundled"] = False
# If there is not a section in the dict for this type, add it # If there is not a section in the dict for this type, add it
if package_info["package_type"] not in installed_packages_dict: if package_info["package_type"] not in installed_packages_dict:
@ -183,26 +181,6 @@ class CuraPackageManager(QObject):
return installed_packages_dict return installed_packages_dict
def __convertPluginMetadataToPackageMetadata(self, plugin_metadata: dict) -> dict:
package_metadata = {
"package_id": plugin_metadata["id"],
"package_type": "plugin",
"display_name": plugin_metadata["plugin"]["name"],
"description": plugin_metadata["plugin"].get("description"),
"package_version": plugin_metadata["plugin"]["version"],
"cura_version": int(plugin_metadata["plugin"]["api"]),
"website": "",
"author_id": plugin_metadata["plugin"].get("author", "UnknownID"),
"author": {
"author_id": plugin_metadata["plugin"].get("author", "UnknownID"),
"display_name": plugin_metadata["plugin"].get("author", ""),
"email": "",
"website": "",
},
"tags": ["plugin"]
}
return package_metadata
# Checks if the given package is installed. # Checks if the given package is installed.
def isPackageInstalled(self, package_id: str) -> bool: def isPackageInstalled(self, package_id: str) -> bool:
return self.getInstalledPackageInfo(package_id) is not None return self.getInstalledPackageInfo(package_id) is not None

View File

@ -66,8 +66,8 @@ Generate a cube mesh to prevent support material generation in specific areas of
*Real bridging - smartavionics *Real bridging - smartavionics
New experimental feature that detects bridges, adjusting the print speed, slow and fan speed to enhance print quality on bridging parts. New experimental feature that detects bridges, adjusting the print speed, slow and fan speed to enhance print quality on bridging parts.
*Updated CuraEngine executable - thopiekar *Updated CuraEngine executable - thopiekar & Ultimaker B.V. ❤️
The CuraEngine executable now contains a dedicated icon, author information and a license. The CuraEngine executable contains a dedicated icon, author and license info on Windows now. The icon has been designed by Ultimaker B.V.
*Use RapidJSON and ClipperLib from system libraries *Use RapidJSON and ClipperLib from system libraries
Application updated to use verified copies of libraries, reducing maintenance time keeping them up to date (the operating system is now responsible), as well as reducing the amount of code shipped (as necessary code is already on the users system). Application updated to use verified copies of libraries, reducing maintenance time keeping them up to date (the operating system is now responsible), as well as reducing the amount of code shipped (as necessary code is already on the users system).

View File

@ -78,7 +78,7 @@ Window
{ {
id: footer id: footer
visible: toolbox.restartRequired visible: toolbox.restartRequired
height: toolbox.restartRequired ? UM.Theme.getSize("toolbox_footer").height : 0 height: visible ? UM.Theme.getSize("toolbox_footer").height : 0
} }
// TODO: Clean this up: // TODO: Clean this up:
Connections Connections

View File

@ -115,7 +115,7 @@ Item
text: text:
{ {
var date = new Date(details.last_updated) var date = new Date(details.last_updated)
return date.toLocaleString(Qt.locale()) return date.toLocaleString(UM.Preferences.getValue("general/language"))
} }
font: UM.Theme.getFont("very_small") font: UM.Theme.getFont("very_small")
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")

View File

@ -14,8 +14,7 @@ Item
height: visible ? Math.floor(UM.Theme.getSize("toolbox_footer").height) : 0 height: visible ? Math.floor(UM.Theme.getSize("toolbox_footer").height) : 0
Label Label
{ {
visible: toolbox.restartRequired text: catalog.i18nc("@info", "You will need to restart Cura before changes in packages have effect.")
text: catalog.i18nc("@info", "You will need to restart Cura before changes in plugins have effect.")
height: Math.floor(UM.Theme.getSize("toolbox_footer_button").height) height: Math.floor(UM.Theme.getSize("toolbox_footer_button").height)
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
anchors anchors
@ -38,7 +37,6 @@ Item
right: parent.right right: parent.right
rightMargin: UM.Theme.getSize("wide_margin").width rightMargin: UM.Theme.getSize("wide_margin").width
} }
visible: toolbox.restartRequired
iconName: "dialog-restart" iconName: "dialog-restart"
onClicked: toolbox.restart() onClicked: toolbox.restart()
style: ButtonStyle style: ButtonStyle
@ -61,7 +59,7 @@ Item
} }
ToolboxShadow ToolboxShadow
{ {
visible: toolbox.restartRequired visible: footer.visible
anchors.bottom: footer.top anchors.bottom: footer.top
reversed: true reversed: true
} }

View File

@ -24,7 +24,8 @@ Item
ToolboxTabButton ToolboxTabButton
{ {
text: catalog.i18nc("@title:tab", "Plugins") text: catalog.i18nc("@title:tab", "Plugins")
active: toolbox.viewCategory == "plugin" active: toolbox.viewCategory == "plugin" && enabled
enabled: toolbox.viewPage != "loading" && toolbox.viewPage != "errored"
onClicked: onClicked:
{ {
toolbox.filterModelByProp("packages", "type", "plugin") toolbox.filterModelByProp("packages", "type", "plugin")
@ -35,7 +36,8 @@ Item
ToolboxTabButton ToolboxTabButton
{ {
text: catalog.i18nc("@title:tab", "Materials") text: catalog.i18nc("@title:tab", "Materials")
active: toolbox.viewCategory == "material" active: toolbox.viewCategory == "material" && enabled
enabled: toolbox.viewPage != "loading" && toolbox.viewPage != "errored"
onClicked: onClicked:
{ {
toolbox.filterModelByProp("authors", "package_types", "material") toolbox.filterModelByProp("authors", "package_types", "material")

View File

@ -1,21 +1,18 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher. // Toolbox is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.7
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4 import QtQuick.Controls.Styles 1.4
import UM 1.1 as UM import UM 1.1 as UM
Item Item
{ {
height: UM.Theme.getSize("toolbox_installed_tile").height
width: parent.width
property bool canUpdate: false property bool canUpdate: false
property bool isEnabled: true property bool isEnabled: true
height: UM.Theme.getSize("toolbox_installed_tile").height
anchors
{
left: parent.left
right: parent.right
}
Rectangle Rectangle
{ {
color: UM.Theme.getColor("lining") color: UM.Theme.getColor("lining")
@ -23,30 +20,40 @@ Item
height: UM.Theme.getSize("default_lining").height height: UM.Theme.getSize("default_lining").height
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
} }
Row
{
id: tileRow
height: parent.height
width: parent.width
spacing: UM.Theme.getSize("default_margin").width
topPadding: UM.Theme.getSize("default_margin").height
CheckBox
{
id: disableButton
checked: isEnabled
visible: model.type == "plugin"
width: visible ? UM.Theme.getSize("checkbox").width : 0
enabled: !toolbox.isDownloading
style: UM.Theme.styles.checkbox
onClicked: toolbox.isEnabled(model.id) ? toolbox.disable(model.id) : toolbox.enable(model.id)
}
Column Column
{ {
id: pluginInfo id: pluginInfo
topPadding: UM.Theme.getSize("default_margin").height / 2
property var color: model.type === "plugin" && !isEnabled ? UM.Theme.getColor("lining") : UM.Theme.getColor("text") property var color: model.type === "plugin" && !isEnabled ? UM.Theme.getColor("lining") : UM.Theme.getColor("text")
height: parent.height width: tileRow.width - (authorInfo.width + pluginActions.width + 2 * tileRow.spacing + ((disableButton.visible) ? disableButton.width + tileRow.spacing : 0))
anchors
{
left: parent.left
top: parent.top
right: authorInfo.left
topMargin: UM.Theme.getSize("default_margin").height
rightMargin: UM.Theme.getSize("default_margin").width
}
Label Label
{ {
text: model.name text: model.name
width: parent.width width: parent.width
height: UM.Theme.getSize("toolbox_property_label").height height: UM.Theme.getSize("toolbox_property_label").height
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
verticalAlignment: Text.AlignVCenter
font: UM.Theme.getFont("default_bold") font: UM.Theme.getFont("default_bold")
color: pluginInfo.color color: pluginInfo.color
} }
Text Label
{ {
text: model.description text: model.description
maximumLineCount: 3 maximumLineCount: 3
@ -59,15 +66,8 @@ Item
Column Column
{ {
id: authorInfo id: authorInfo
height: parent.height
width: Math.floor(UM.Theme.getSize("toolbox_action_button").width * 1.25) width: Math.floor(UM.Theme.getSize("toolbox_action_button").width * 1.25)
anchors
{
top: parent.top
topMargin: UM.Theme.getSize("default_margin").height
right: pluginActions.left
rightMargin: UM.Theme.getSize("default_margin").width
}
Label Label
{ {
text: text:
@ -91,125 +91,9 @@ Item
linkColor: UM.Theme.getColor("text_link") linkColor: UM.Theme.getColor("text_link")
} }
} }
Column ToolboxInstalledTileActions
{ {
id: pluginActions id: pluginActions
width: childrenRect.width
height: childrenRect.height
spacing: UM.Theme.getSize("default_margin").height
anchors
{
top: parent.top
right: parent.right
topMargin: UM.Theme.getSize("default_margin").height
}
Button
{
id: disableButton
text: isEnabled ? catalog.i18nc("@action:button", "Disable") : catalog.i18nc("@action:button", "Enable")
visible: model.type == "plugin"
enabled: !toolbox.isDownloading
style: ButtonStyle
{
background: Rectangle
{
implicitWidth: UM.Theme.getSize("toolbox_action_button").width
implicitHeight: UM.Theme.getSize("toolbox_action_button").height
color: "transparent"
border
{
width: UM.Theme.getSize("default_lining").width
color: UM.Theme.getColor("lining")
}
}
label: Label
{
text: control.text
color: UM.Theme.getColor("text")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
onClicked: toolbox.isEnabled(model.id) ? toolbox.disable(model.id) : toolbox.enable(model.id)
}
Button
{
id: removeButton
text: catalog.i18nc("@action:button", "Uninstall")
visible: !model.is_bundled
enabled: !toolbox.isDownloading
style: ButtonStyle
{
background: Rectangle
{
implicitWidth: UM.Theme.getSize("toolbox_action_button").width
implicitHeight: UM.Theme.getSize("toolbox_action_button").height
color: "transparent"
border
{
width: UM.Theme.getSize("default_lining").width
color: UM.Theme.getColor("lining")
}
}
label: Label
{
text: control.text
color: UM.Theme.getColor("text")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
onClicked: toolbox.uninstall(model.id)
}
Button
{
id: updateButton
text: catalog.i18nc("@action:button", "Update")
visible: canUpdate
style: ButtonStyle
{
background: Rectangle
{
implicitWidth: UM.Theme.getSize("toolbox_action_button").width
implicitHeight: UM.Theme.getSize("toolbox_action_button").height
color: control.hovered ? UM.Theme.getColor("primary_hover") : UM.Theme.getColor("primary")
}
label: Label
{
text: control.text
color: control.hovered ? UM.Theme.getColor("button_text") : UM.Theme.getColor("button_text_hover")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font: UM.Theme.getFont("default_bold")
}
}
onClicked: toolbox.update(model.id)
}
ProgressBar
{
id: progressbar
anchors
{
left: updateButton.left
right: updateButton.right
top: updateButton.bottom
topMargin: Math.floor(UM.Theme.getSize("default_margin") / 4)
}
value: toolbox.isDownloading ? toolbox.downloadProgress : 0
visible: toolbox.isDownloading
style: ProgressBarStyle
{
background: Rectangle
{
color: UM.Theme.getColor("lining")
implicitHeight: Math.floor(UM.Theme.getSize("toolbox_progress_bar").height)
}
progress: Rectangle
{
color: UM.Theme.getColor("primary")
}
}
}
} }
Connections Connections
{ {
@ -218,3 +102,4 @@ Item
onMetadataChanged: canUpdate = toolbox.canUpdate(model.id) onMetadataChanged: canUpdate = toolbox.canUpdate(model.id)
} }
} }
}

View File

@ -0,0 +1,93 @@
// Copyright (c) 2018 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import UM 1.1 as UM
Column
{
width: UM.Theme.getSize("toolbox_action_button").width
spacing: UM.Theme.getSize("narrow_margin").height
Item
{
width: parent.width
height: childrenRect.height
visible: canUpdate
Button
{
id: updateButton
text: catalog.i18nc("@action:button", "Update")
style: ButtonStyle
{
background: Rectangle
{
implicitWidth: UM.Theme.getSize("toolbox_action_button").width
implicitHeight: UM.Theme.getSize("toolbox_action_button").height
color: control.hovered ? UM.Theme.getColor("primary_hover") : UM.Theme.getColor("primary")
}
label: Label
{
text: control.text
color: control.hovered ? UM.Theme.getColor("button_text") : UM.Theme.getColor("button_text_hover")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font: UM.Theme.getFont("default_bold")
}
}
onClicked: toolbox.update(model.id)
}
ProgressBar
{
id: progressbar
width: parent.width
value: toolbox.isDownloading ? toolbox.downloadProgress : 0
visible: toolbox.isDownloading
style: ProgressBarStyle
{
background: Rectangle
{
color: "transparent"
implicitHeight: UM.Theme.getSize("toolbox_action_button").height
}
progress: Rectangle
{
// TODO Define a good color that fits the purpuse
color: "blue"
opacity: 0.5
}
}
}
}
Button
{
id: removeButton
text: catalog.i18nc("@action:button", "Uninstall")
visible: !model.is_bundled
enabled: !toolbox.isDownloading
style: ButtonStyle
{
background: Rectangle
{
implicitWidth: UM.Theme.getSize("toolbox_action_button").width
implicitHeight: UM.Theme.getSize("toolbox_action_button").height
color: "transparent"
border
{
width: UM.Theme.getSize("default_lining").width
color: UM.Theme.getColor("lining")
}
}
label: Label
{
text: control.text
color: UM.Theme.getColor("text")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
onClicked: toolbox.uninstall(model.id)
}
}

View File

@ -43,7 +43,7 @@ Button
return UM.Theme.getColor("topbar_button_text_inactive"); return UM.Theme.getColor("topbar_button_text_inactive");
} }
} }
font: control.active ? UM.Theme.getFont("medium_bold") : UM.Theme.getFont("medium") font: control.enabled ? (control.active ? UM.Theme.getFont("medium_bold") : UM.Theme.getFont("medium")) : UM.Theme.getFont("default_italic")
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }

View File

@ -251,7 +251,6 @@ class Toolbox(QObject, Extension):
@pyqtSlot() @pyqtSlot()
def restart(self): def restart(self):
self._package_manager._removeAllScheduledPackages()
CuraApplication.getInstance().windowClosed() CuraApplication.getInstance().windowClosed()
# Checks # Checks
@ -333,8 +332,8 @@ class Toolbox(QObject, Extension):
# Handlers for Network Events # Handlers for Network Events
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
def _onNetworkAccessibleChanged(self, accessible: int) -> None: def _onNetworkAccessibleChanged(self, network_accessibility: QNetworkAccessManager.NetworkAccessibility) -> None:
if accessible == 0: if network_accessibility == QNetworkAccessManager.NotAccessible:
self.resetDownload() self.resetDownload()
def _onRequestFinished(self, reply: QNetworkReply) -> None: def _onRequestFinished(self, reply: QNetworkReply) -> None:
@ -354,6 +353,7 @@ class Toolbox(QObject, Extension):
if reply.operation() == QNetworkAccessManager.GetOperation: if reply.operation() == QNetworkAccessManager.GetOperation:
for type, url in self._request_urls.items(): for type, url in self._request_urls.items():
if reply.url() == url: if reply.url() == url:
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 200:
try: try:
json_data = json.loads(bytes(reply.readAll()).decode("utf-8")) json_data = json.loads(bytes(reply.readAll()).decode("utf-8"))
@ -398,6 +398,10 @@ class Toolbox(QObject, Extension):
except json.decoder.JSONDecodeError: except json.decoder.JSONDecodeError:
Logger.log("w", "Toolbox: Received invalid JSON for %s.", type) Logger.log("w", "Toolbox: Received invalid JSON for %s.", type)
break break
else:
self.setViewPage("errored")
self.resetDownload()
return
else: else:
# Ignore any operation that is not a get operation # Ignore any operation that is not a get operation

View File

@ -32,7 +32,7 @@
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" }, "machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": { "machine_start_gcode": {
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;home X/Y\nG28 Z0 ;home Z\nG92 E0 ;zero the extruded length\nG29 ;initiate auto bed leveling sequence\nG92 X132.4 Y20 ;correct bed origin (G29 changes it)" "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;home X/Y\nG28 Z0 ;home Z\nG92 E0 ;zero the extruded length\nG29 ;initiate auto bed leveling sequence"
}, },
"machine_end_gcode": { "machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nM106 S0 ;fan off\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit\nG1 Z+1 E-5 F9000 ;move Z up a bit and retract even more\nG28 X0 Y0 ;home X/Y, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning" "default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nM106 S0 ;fan off\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit\nG1 Z+1 E-5 F9000 ;move Z up a bit and retract even more\nG28 X0 Y0 ;home X/Y, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"

View File

@ -3558,7 +3558,7 @@ msgstr "Druckeinrichtung deaktiviert\nG-Code-Dateien können nicht geändert wer
#: /home/ruben/Projects/Cura/resources/qml/Sidebar.qml:380 #: /home/ruben/Projects/Cura/resources/qml/Sidebar.qml:380
msgctxt "@label Hours and minutes" msgctxt "@label Hours and minutes"
msgid "00h 00min" msgid "00h 00min"
msgstr "00 Stunden 00 Minuten" msgstr "00 St. 00 M."
#: /home/ruben/Projects/Cura/resources/qml/Sidebar.qml:398 #: /home/ruben/Projects/Cura/resources/qml/Sidebar.qml:398
msgctxt "@tooltip" msgctxt "@tooltip"
@ -5493,7 +5493,7 @@ msgstr "Cura-Profil-Reader"
#~ msgctxt "@label" #~ msgctxt "@label"
#~ msgid "00h 00min" #~ msgid "00h 00min"
#~ msgstr "00 Stunden 00 Minuten" #~ msgstr "00 St. 00 M."
#~ msgctxt "@tooltip" #~ msgctxt "@tooltip"
#~ msgid "<b>Time information</b>" #~ msgid "<b>Time information</b>"
@ -5517,7 +5517,7 @@ msgstr "Cura-Profil-Reader"
#~ msgctxt "@label" #~ msgctxt "@label"
#~ msgid "<a href='%1'>Check material compatibility</a>" #~ msgid "<a href='%1'>Check material compatibility</a>"
#~ msgstr "<a href='%1>Materialkompatibilität prüfen</a>" #~ msgstr "<a href='%1'>Materialkompatibilität prüfen</a>"
#~ msgctxt "name" #~ msgctxt "name"
#~ msgid "UM3 Network Connection (Cluster)" #~ msgid "UM3 Network Connection (Cluster)"

View File

@ -69,8 +69,6 @@
"colors": { "colors": {
"sidebar": [255, 255, 255, 255], "sidebar": [255, 255, 255, 255],
"lining": [192, 193, 194, 255], "lining": [192, 193, 194, 255],
"viewport_overlay": [0, 0, 0, 192], "viewport_overlay": [0, 0, 0, 192],
@ -458,7 +456,6 @@
"toolbox_property_label": [1.0, 2.0], "toolbox_property_label": [1.0, 2.0],
"toolbox_heading_label": [1.0, 4.0], "toolbox_heading_label": [1.0, 4.0],
"toolbox_header": [1.0, 4.0], "toolbox_header": [1.0, 4.0],
"toolbox_action_button": [8.0, 2.5],
"toolbox_progress_bar": [8.0, 0.5], "toolbox_progress_bar": [8.0, 0.5],
"toolbox_chart_row": [1.0, 2.0], "toolbox_chart_row": [1.0, 2.0],
"toolbox_action_button": [8.0, 2.5] "toolbox_action_button": [8.0, 2.5]