diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 1c9a0708fd..4e55528f5d 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -956,14 +956,14 @@ class BuildVolume(SceneNode): if adhesion_type == "skirt": skirt_distance = self._getSettingFromAdhesionExtruder("skirt_gap") skirt_line_count = self._getSettingFromAdhesionExtruder("skirt_line_count") - bed_adhesion_size = skirt_distance + (skirt_line_count * self._getSettingFromAdhesionExtruder("skirt_brim_line_width")) * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor") / 100.0 + bed_adhesion_size = skirt_distance + (self._getSettingFromAdhesionExtruder("skirt_brim_line_width") * skirt_line_count) * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor") / 100.0 if len(used_extruders) > 1: for extruder_stack in used_extruders: bed_adhesion_size += extruder_stack.getProperty("skirt_brim_line_width", "value") * extruder_stack.getProperty("initial_layer_line_width_factor", "value") / 100.0 #We don't create an additional line for the extruder we're printing the skirt with. bed_adhesion_size -= self._getSettingFromAdhesionExtruder("skirt_brim_line_width", "value") * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor", "value") / 100.0 elif adhesion_type == "brim": - bed_adhesion_size = self._getSettingFromAdhesionExtruder("brim_line_count") * self._getSettingFromAdhesionExtruder("skirt_brim_line_width") * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor") / 100.0 + bed_adhesion_size = self._getSettingFromAdhesionExtruder("skirt_brim_line_width") * self._getSettingFromAdhesionExtruder("brim_line_count") * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor") / 100.0 if self._global_container_stack.getProperty("machine_extruder_count", "value") > 1: for extruder_stack in used_extruders: bed_adhesion_size += extruder_stack.getProperty("skirt_brim_line_width", "value") * extruder_stack.getProperty("initial_layer_line_width_factor", "value") / 100.0 diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index b00c5a632c..dc5594dc7b 100755 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -67,10 +67,18 @@ class PlatformPhysics: # Move it downwards if bottom is above platform move_vector = Vector() - if Preferences.getInstance().getValue("physics/automatic_drop_down") and not (node.getParent() and node.getParent().callDecoration("isGroup")) and node.isEnabled(): #If an object is grouped, don't move it down + + # Check if this is the first time a project file node was loaded (disable auto drop in that case), defaults to True + should_auto_drop = node.getSetting("auto_drop", True) + + # If a node is grouped or it's loaded from a project file (auto-drop disabled), don't move it down + if Preferences.getInstance().getValue("physics/automatic_drop_down") and not (node.getParent() and node.getParent().callDecoration("isGroup")) and node.isEnabled() and should_auto_drop: z_offset = node.callDecoration("getZOffset") if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator) else 0 move_vector = move_vector.set(y=-bbox.bottom + z_offset) + # Enable auto-drop after processing the project file node for the first time + node.setSetting("auto_drop", False) + # If there is no convex hull for the node, start calculating it and continue. if not node.getDecorator(ConvexHullDecorator): node.addDecorator(ConvexHullDecorator()) diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 2b7a35995b..209d95d616 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015 Ultimaker B.V. +# Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty @@ -51,20 +51,7 @@ class PrintInformation(QObject): def __init__(self, parent = None): super().__init__(parent) - self._current_print_time = Duration(None, self) - self._print_times_per_feature = { - "none": Duration(None, self), - "inset_0": Duration(None, self), - "inset_x": Duration(None, self), - "skin": Duration(None, self), - "support": Duration(None, self), - "skirt": Duration(None, self), - "infill": Duration(None, self), - "support_infill": Duration(None, self), - "travel": Duration(None, self), - "retract": Duration(None, self), - "support_interface": Duration(None, self) - } + self.initializeCuraMessagePrintTimeProperties() self._material_lengths = [] self._material_weights = [] @@ -91,6 +78,33 @@ class PrintInformation(QObject): self._material_amounts = [] + + # Crate cura message translations and using translation keys initialize empty time Duration object for total time + # and time for each feature + def initializeCuraMessagePrintTimeProperties(self): + self._current_print_time = Duration(None, self) + + self._print_time_message_translations = { + "inset_0": catalog.i18nc("@tooltip", "Outer Wall"), + "inset_x": catalog.i18nc("@tooltip", "Inner Walls"), + "skin": catalog.i18nc("@tooltip", "Skin"), + "infill": catalog.i18nc("@tooltip", "Infill"), + "support_infill": catalog.i18nc("@tooltip", "Support Infill"), + "support_interface": catalog.i18nc("@tooltip", "Support Interface"), + "support": catalog.i18nc("@tooltip", "Support"), + "skirt": catalog.i18nc("@tooltip", "Skirt"), + "travel": catalog.i18nc("@tooltip", "Travel"), + "retract": catalog.i18nc("@tooltip", "Retractions"), + "none": catalog.i18nc("@tooltip", "Other") + } + + self._print_time_message_values = {} + + # Full fill message values using keys from _print_time_message_translations + for key in sorted(self._print_time_message_translations.keys()): + self._print_time_message_values[key] = Duration(None, self) + + currentPrintTimeChanged = pyqtSignal() preSlicedChanged = pyqtSignal() @@ -107,10 +121,6 @@ class PrintInformation(QObject): def currentPrintTime(self): return self._current_print_time - @pyqtProperty("QVariantMap", notify = currentPrintTimeChanged) - def printTimesPerFeature(self): - return self._print_times_per_feature - materialLengthsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify = materialLengthsChanged) @@ -129,22 +139,28 @@ class PrintInformation(QObject): def materialCosts(self): return self._material_costs - def _onPrintDurationMessage(self, time_per_feature, material_amounts): - total_time = 0 - for feature, time in time_per_feature.items(): - if time != time: # Check for NaN. Engine can sometimes give us weird values. - self._print_times_per_feature[feature].setDuration(0) - Logger.log("w", "Received NaN for print duration message") - continue - total_time += time - self._print_times_per_feature[feature].setDuration(time) - self._current_print_time.setDuration(total_time) + def _onPrintDurationMessage(self, print_time, material_amounts): + self._updateTotalPrintTimePerFeature(print_time) self.currentPrintTimeChanged.emit() self._material_amounts = material_amounts self._calculateInformation() + def _updateTotalPrintTimePerFeature(self, print_time): + total_estimated_time = 0 + + for feature, time in print_time.items(): + if time != time: # Check for NaN. Engine can sometimes give us weird values. + self._print_time_message_values.get(feature).setDuration(0) + Logger.log("w", "Received NaN for print duration message") + continue + + total_estimated_time += time + self._print_time_message_values.get(feature).setDuration(time) + + self._current_print_time.setDuration(total_estimated_time) + def _calculateInformation(self): if Application.getInstance().getGlobalContainerStack() is None: return @@ -294,3 +310,23 @@ class PrintInformation(QObject): ## Utility method that strips accents from characters (eg: รข -> a) def _stripAccents(self, str): return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn') + + @pyqtSlot(result = "QVariantMap") + def getFeaturePrintTimes(self): + result = {} + for feature, time in self._print_time_message_values.items(): + if feature in self._print_time_message_translations: + result[self._print_time_message_translations[feature]] = time + else: + result[feature] = time + return result + + # Simulate message with zero time duration + def setToZeroPrintInformation(self): + temp_message = {} + for key in self._print_time_message_values.keys(): + temp_message[key] = 0 + + temp_material_amounts = [0] + self._onPrintDurationMessage(temp_message, temp_material_amounts) + diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index d473ecaa8b..66dfb6130e 100755 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -73,11 +73,11 @@ class ThreeMFReader(MeshReader): return temp_mat - - ## Convenience function that converts a SceneNode object (as obtained from libSavitar) to a Uranium scenenode. - # \returns Uranium Scenen node. + ## Convenience function that converts a SceneNode object (as obtained from libSavitar) to a Uranium SceneNode. + # \returns Uranium SceneNode. def _convertSavitarNodeToUMNode(self, savitar_node): um_node = SceneNode() + um_node.setSetting("auto_drop", False) # Disable the auto-drop feature when loading a project file and processing the nodes for the first time transformation = self._createMatrixFromTransformationString(savitar_node.getTransformation()) um_node.setTransformation(transformation) mesh_builder = MeshBuilder() diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 62e3703a3f..d642fdfe08 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015 Ultimaker B.V. +# Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. from UM.Backend.Backend import Backend, BackendState @@ -196,19 +196,7 @@ class CuraEngineBackend(QObject, Backend): Logger.log("w", "Slice unnecessary, nothing has changed that needs reslicing.") return - self.printDurationMessage.emit({ - "none": 0, - "inset_0": 0, - "inset_x": 0, - "skin": 0, - "support": 0, - "skirt": 0, - "infill": 0, - "support_infill": 0, - "travel": 0, - "retract": 0, - "support_interface": 0 - }, [0]) + Application.getInstance().getPrintInformation().setToZeroPrintInformation() self._stored_layer_data = [] self._stored_optimized_layer_data = [] @@ -514,29 +502,6 @@ class CuraEngineBackend(QObject, Backend): def _onGCodePrefixMessage(self, message): self._scene.gcode_list.insert(0, message.data.decode("utf-8", "replace")) - ## Called when a print time message is received from the engine. - # - # \param message The protobuf message containing the print time per feature and - # material amount per extruder - def _onPrintTimeMaterialEstimates(self, message): - material_amounts = [] - for index in range(message.repeatedMessageCount("materialEstimates")): - material_amounts.append(message.getRepeatedMessage("materialEstimates", index).material_amount) - feature_times = { - "none": message.time_none, - "inset_0": message.time_inset_0, - "inset_x": message.time_inset_x, - "skin": message.time_skin, - "support": message.time_support, - "skirt": message.time_skirt, - "infill": message.time_infill, - "support_infill": message.time_support_infill, - "travel": message.time_travel, - "retract": message.time_retract, - "support_interface": message.time_support_interface - } - self.printDurationMessage.emit(feature_times, material_amounts) - ## Creates a new socket connection. def _createSocket(self): super()._createSocket(os.path.abspath(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "Cura.proto"))) @@ -555,6 +520,38 @@ class CuraEngineBackend(QObject, Backend): else: self._change_timer.start() + ## Called when a print time message is received from the engine. + # + # \param message The protobuf message containing the print time per feature and + # material amount per extruder + def _onPrintTimeMaterialEstimates(self, message): + material_amounts = [] + for index in range(message.repeatedMessageCount("materialEstimates")): + material_amounts.append(message.getRepeatedMessage("materialEstimates", index).material_amount) + + times = self._parseMessagePrintTimes(message) + self.printDurationMessage.emit(times, material_amounts) + + ## Called for parsing message to retrieve estimated time per feature + # + # \param message The protobuf message containing the print time per feature + def _parseMessagePrintTimes(self, message): + + result = { + "inset_0": message.time_inset_0, + "inset_x": message.time_inset_x, + "skin": message.time_skin, + "infill": message.time_infill, + "support_infill": message.time_support_infill, + "support_interface": message.time_support_interface, + "support": message.time_support, + "skirt": message.time_skirt, + "travel": message.time_travel, + "retract": message.time_retract, + "none": message.time_none + } + return result + ## Called when the back-end connects to the front-end. def _onBackendConnected(self): if self._restart: diff --git a/resources/qml/SaveButton.qml b/resources/qml/SaveButton.qml index 616017ebf6..2b7930793f 100644 --- a/resources/qml/SaveButton.qml +++ b/resources/qml/SaveButton.qml @@ -238,22 +238,22 @@ Item { if(!control.enabled) return UM.Theme.getColor("action_button_disabled_border"); else if(control.pressed) - return UM.Theme.getColor("action_button_active_border"); + return UM.Theme.getColor("print_button_ready_pressed_border"); else if(control.hovered) - return UM.Theme.getColor("action_button_hovered_border"); + return UM.Theme.getColor("print_button_ready_hovered_border"); else - return UM.Theme.getColor("action_button_border"); + return UM.Theme.getColor("print_button_ready_border"); } color: { if(!control.enabled) return UM.Theme.getColor("action_button_disabled"); else if(control.pressed) - return UM.Theme.getColor("action_button_active"); + return UM.Theme.getColor("print_button_ready_pressed"); else if(control.hovered) - return UM.Theme.getColor("action_button_hovered"); + return UM.Theme.getColor("print_button_ready_hovered"); else - return UM.Theme.getColor("action_button"); + return UM.Theme.getColor("print_button_ready"); } Behavior on color { ColorAnimation { duration: 50; } } @@ -268,11 +268,11 @@ Item { if(!control.enabled) return UM.Theme.getColor("action_button_disabled_text"); else if(control.pressed) - return UM.Theme.getColor("action_button_active_text"); + return UM.Theme.getColor("print_button_ready_text"); else if(control.hovered) - return UM.Theme.getColor("action_button_hovered_text"); + return UM.Theme.getColor("print_button_ready_text"); else - return UM.Theme.getColor("action_button_text"); + return UM.Theme.getColor("print_button_ready_text"); } font: UM.Theme.getFont("action_button") text: control.text; diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index ccaff1cd9a..6d417fa011 100755 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -26,7 +26,6 @@ Rectangle property bool monitoringPrint: false property variant printDuration: PrintInformation.currentPrintTime - property variant printDurationPerFeature: PrintInformation.printTimesPerFeature property variant printMaterialLengths: PrintInformation.materialLengths property variant printMaterialWeights: PrintInformation.materialWeights property variant printMaterialCosts: PrintInformation.materialCosts @@ -314,54 +313,60 @@ Rectangle anchors.bottom: parent.bottom anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width anchors.bottomMargin: UM.Theme.getSize("sidebar_margin").height - height: childrenRect.height + height: timeDetails.height + timeSpecDescription.height + lengthSpec.height visible: !monitoringPrint - UM.TooltipArea + Text { - id: timeSpecPerFeatureTooltipArea - width: timeSpec.width - height: timeSpec.height + id: timeDetails anchors.left: parent.left anchors.bottom: timeSpecDescription.top + font: UM.Theme.getFont("large") + color: UM.Theme.getColor("text_subtext") + text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short) - text: { - var order = ["inset_0", "inset_x", "skin", "infill", "support_infill", "support_interface", "support", "travel", "retract", "none"]; - var visible_names = { - "inset_0": catalog.i18nc("@tooltip", "Outer Wall"), - "inset_x": catalog.i18nc("@tooltip", "Inner Walls"), - "skin": catalog.i18nc("@tooltip", "Skin"), - "infill": catalog.i18nc("@tooltip", "Infill"), - "support_infill": catalog.i18nc("@tooltip", "Support Infill"), - "support_interface": catalog.i18nc("@tooltip", "Support Interface"), - "support": catalog.i18nc("@tooltip", "Support"), - "travel": catalog.i18nc("@tooltip", "Travel"), - "retract": catalog.i18nc("@tooltip", "Retractions"), - "none": catalog.i18nc("@tooltip", "Other") - }; - var result = ""; - for(var feature in order) + MouseArea + { + id: infillMouseArea + anchors.fill: parent + hoverEnabled: true + //enabled: base.settingsEnabled + + onEntered: { - feature = order[feature]; - if(base.printDurationPerFeature[feature] && base.printDurationPerFeature[feature].totalSeconds > 0) + + if(base.printDuration.valid && !base.printDuration.isTotalDurationZero) { - result += "
" + visible_names[feature] + ": " + base.printDurationPerFeature[feature].getDisplayString(UM.DurationFormat.Short); + var print_time = PrintInformation.getFeaturePrintTimes() + + var valid_data = []; + for(var feature in print_time) + { + if(!print_time[feature].isTotalDurationZero) + { + valid_data.push(feature + ": " + print_time[feature].getDisplayString(UM.DurationFormat.Short)) + } + } + + var output = "" + for(var counter = 0; counter < valid_data.length; counter++) + { + output += valid_data[counter]; + if(counter + 1 != valid_data.length) + output += "\n" + } + + var content = catalog.i18nc("@tooltip",output) + base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), content) } } - result = result.replace(/^\/, ""); // remove newline before first item - return result; - } - - Text - { - id: timeSpec - anchors.left: parent.left - anchors.bottom: parent.bottom - font: UM.Theme.getFont("large") - color: UM.Theme.getColor("text_subtext") - text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short) + onExited: + { + base.hideTooltip(); + } } } + Text { id: timeSpecDescription diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 20d92885d7..bbfd8a424a 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -143,6 +143,7 @@ Item } } resolutionSlider.currentQualityIndex = undefined; + backgroundBarUpdateTimer.start(); } function updateBar() @@ -246,9 +247,10 @@ Item anchors.fill: parent Timer { - interval: 16 - running: true - repeat: true + id: backgroundBarUpdateTimer + interval: 10 + running: false + repeat: false onTriggered: backgroundBar.requestPaint() } diff --git a/resources/quality/abax_pri3/apri3_pla_fast.inst.cfg b/resources/quality/abax_pri3/apri3_pla_fast.inst.cfg index d0c09692db..6be4578649 100644 --- a/resources/quality/abax_pri3/apri3_pla_fast.inst.cfg +++ b/resources/quality/abax_pri3/apri3_pla_fast.inst.cfg @@ -6,7 +6,7 @@ definition = abax_pri3 [metadata] type = quality material = generic_pla -weight = 0 +weight = -1 quality_type = normal setting_version = 3 diff --git a/resources/quality/abax_pri5/apri5_pla_fast.inst.cfg b/resources/quality/abax_pri5/apri5_pla_fast.inst.cfg index 1484dd33b0..140a59db3b 100644 --- a/resources/quality/abax_pri5/apri5_pla_fast.inst.cfg +++ b/resources/quality/abax_pri5/apri5_pla_fast.inst.cfg @@ -6,7 +6,7 @@ definition = abax_pri5 [metadata] type = quality material = generic_pla -weight = 0 +weight = -1 quality_type = normal setting_version = 3 diff --git a/resources/quality/abax_titan/atitan_pla_fast.inst.cfg b/resources/quality/abax_titan/atitan_pla_fast.inst.cfg index abd58cadb8..b8d8f019cd 100644 --- a/resources/quality/abax_titan/atitan_pla_fast.inst.cfg +++ b/resources/quality/abax_titan/atitan_pla_fast.inst.cfg @@ -6,7 +6,7 @@ definition = abax_titan [metadata] type = quality material = generic_pla -weight = 0 +weight = -1 quality_type = normal setting_version = 3 diff --git a/resources/themes/cura-dark/theme.json b/resources/themes/cura-dark/theme.json index 6b7edb6429..187896aa28 100644 --- a/resources/themes/cura-dark/theme.json +++ b/resources/themes/cura-dark/theme.json @@ -16,7 +16,7 @@ "secondary": [241, 242, 242, 255], "topbar_background_color": [0, 0, 0, 0], - "topbar_background_color_monitoring": [0, 0, 0, 255], + "topbar_background_color_monitoring": [39, 44, 48, 255], "topbar_button_text_active": [255, 255, 255, 255], "topbar_button_text_inactive": [128, 128, 128, 255], @@ -36,7 +36,7 @@ "error": [212, 31, 53, 255], "sidebar_header_bar": [39, 44, 48, 255], "sidebar_header_active": [39, 44, 48, 255], - "sidebar_header_hover": [39, 44, 48, 255], + "sidebar_header_hover": [68, 72, 75, 255], "sidebar_header_highlight": [68, 192, 255, 255], "sidebar_header_highlight_hover": [68, 192, 255, 255], "sidebar_header_text_active": [255, 255, 255, 255], @@ -109,7 +109,7 @@ "setting_control": [43, 48, 52, 255], "setting_control_selected": [34, 39, 42, 38], - "setting_control_highlight": [255, 255, 255, 0], + "setting_control_highlight": [43, 48, 52, 255], "setting_control_border": [255, 255, 255, 38], "setting_control_border_highlight": [12, 169, 227, 255], "setting_control_text": [255, 255, 255, 181], @@ -128,9 +128,9 @@ "progressbar_background": [255, 255, 255, 48], "progressbar_control": [255, 255, 255, 197], - "slider_groove": [245, 245, 245, 255], + "slider_groove": [127, 127, 127, 255], "slider_groove_border": [127, 127, 127, 255], - "slider_groove_fill": [127, 127, 127, 255], + "slider_groove_fill": [245, 245, 245, 255], "slider_handle": [255, 255, 255, 255], "slider_handle_hover": [77, 182, 226, 255], "slider_handle_border": [39, 44, 48, 255], @@ -197,11 +197,6 @@ "material_compatibility_warning": [255, 255, 255, 255], - "topbar_button_text_inactive": [255, 255, 255, 255], - "topbar_button_text_active": [255, 255, 255, 255], - "topbar_button_text_hovered": [255, 255, 255, 255], - "topbar_background_color_monitoring": [39, 44, 48, 255], - "quality_slider_unavailable": [179, 179, 179, 255], "quality_slider_available": [255, 255, 255, 255], "quality_slider_handle": [255, 255, 255, 255], diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index fb6e43d0be..92d51ae7d2 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -143,6 +143,14 @@ "action_button_disabled_text": [127, 127, 127, 255], "action_button_disabled_border": [245, 245, 245, 255], + "print_button_ready": [12, 169, 227, 255], + "print_button_ready_border": [12, 169, 227, 255], + "print_button_ready_text": [255, 255, 255, 255], + "print_button_ready_hovered": [12, 169, 255, 255], + "print_button_ready_hovered_border": [12, 169, 227, 255], + "print_button_ready_pressed": [12, 169, 220, 255], + "print_button_ready_pressed_border": [12, 169, 227, 255], + "scrollbar_background": [255, 255, 255, 255], "scrollbar_handle": [24, 41, 77, 255], "scrollbar_handle_hover": [12, 159, 227, 255], @@ -295,7 +303,7 @@ "extruder_button_material_margin": [0.70, 0.9], "extruder_button_material": [0.75, 0.75], - "sidebar": [35.0, 10.0], + "sidebar": [32.0, 10.0], "sidebar_margin": [1.71, 1.43], "sidebar_margin_thin": [0.71, 0.71], "sidebar_header": [0.0, 4.0],