Browse Source

Removed crappy legend

Jack Ha 8 years ago
parent
commit
3a2438937d

+ 51 - 25
cura/BuildVolume.py

@@ -34,16 +34,18 @@ PRIME_CLEARANCE = 6.5
 
 ##  Build volume is a special kind of node that is responsible for rendering the printable area & disallowed areas.
 class BuildVolume(SceneNode):
-    VolumeOutlineColor = Color(12, 169, 227, 255)
-    XAxisColor = Color(255, 0, 0, 255)
-    YAxisColor = Color(0, 0, 255, 255)
-    ZAxisColor = Color(0, 255, 0, 255)
-
     raftThicknessChanged = Signal()
 
     def __init__(self, parent = None):
         super().__init__(parent)
 
+        self._volume_outline_color = None
+        self._x_axis_color = None
+        self._y_axis_color = None
+        self._z_axis_color = None
+        self._disallowed_area_color = None
+        self._error_area_color = None
+
         self._width = 0
         self._height = 0
         self._depth = 0
@@ -75,6 +77,9 @@ class BuildVolume(SceneNode):
         Application.getInstance().globalContainerStackChanged.connect(self._onStackChanged)
         self._onStackChanged()
 
+        self._engine_ready = False
+        Application.getInstance().engineCreatedSignal.connect(self._onEngineCreated)
+
         self._has_errors = False
         Application.getInstance().getController().getScene().sceneChanged.connect(self._onSceneChanged)
 
@@ -99,6 +104,7 @@ class BuildVolume(SceneNode):
         # but it does not update the disallowed areas after material change
         Application.getInstance().getMachineManager().activeStackChanged.connect(self._onStackChanged)
 
+
     def _onSceneChanged(self, source):
         if self._global_container_stack:
             self._change_timer.start()
@@ -158,6 +164,9 @@ class BuildVolume(SceneNode):
         if not self._shader:
             self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "default.shader"))
             self._grid_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "grid.shader"))
+            theme = Application.getInstance().getTheme()
+            self._grid_shader.setUniformValue("u_gridColor0", Color(*theme.getColor("buildplate").getRgb()))
+            self._grid_shader.setUniformValue("u_gridColor1", Color(*theme.getColor("buildplate_alt").getRgb()))
 
         renderer.queueNode(self, mode = RenderBatch.RenderMode.Lines)
         renderer.queueNode(self, mesh = self._origin_mesh)
@@ -176,6 +185,18 @@ class BuildVolume(SceneNode):
         if not self._width or not self._height or not self._depth:
             return
 
+        if not Application.getInstance()._engine:
+            return
+
+        if not self._volume_outline_color:
+            theme = Application.getInstance().getTheme()
+            self._volume_outline_color = Color(*theme.getColor("volume_outline").getRgb())
+            self._x_axis_color = Color(*theme.getColor("x_axis").getRgb())
+            self._y_axis_color = Color(*theme.getColor("y_axis").getRgb())
+            self._z_axis_color = Color(*theme.getColor("z_axis").getRgb())
+            self._disallowed_area_color = Color(*theme.getColor("disallowed_area").getRgb())
+            self._error_area_color = Color(*theme.getColor("error_area").getRgb())
+
         min_w = -self._width / 2
         max_w = self._width / 2
         min_h = 0.0
@@ -188,20 +209,20 @@ class BuildVolume(SceneNode):
         if self._shape != "elliptic":
             # Outline 'cube' of the build volume
             mb = MeshBuilder()
-            mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color = self.VolumeOutlineColor)
-            mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color = self.VolumeOutlineColor)
-            mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor)
-            mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor)
+            mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color = self._volume_outline_color)
+            mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color = self._volume_outline_color)
+            mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color = self._volume_outline_color)
+            mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, max_h, min_d), color = self._volume_outline_color)
 
-            mb.addLine(Vector(min_w, min_h, max_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor)
-            mb.addLine(Vector(min_w, min_h, max_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor)
-            mb.addLine(Vector(min_w, max_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)
-            mb.addLine(Vector(max_w, min_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)
+            mb.addLine(Vector(min_w, min_h, max_d), Vector(max_w, min_h, max_d), color = self._volume_outline_color)
+            mb.addLine(Vector(min_w, min_h, max_d), Vector(min_w, max_h, max_d), color = self._volume_outline_color)
+            mb.addLine(Vector(min_w, max_h, max_d), Vector(max_w, max_h, max_d), color = self._volume_outline_color)
+            mb.addLine(Vector(max_w, min_h, max_d), Vector(max_w, max_h, max_d), color = self._volume_outline_color)
 
-            mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, min_h, max_d), color = self.VolumeOutlineColor)
-            mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor)
-            mb.addLine(Vector(min_w, max_h, min_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor)
-            mb.addLine(Vector(max_w, max_h, min_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)
+            mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, min_h, max_d), color = self._volume_outline_color)
+            mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, min_h, max_d), color = self._volume_outline_color)
+            mb.addLine(Vector(min_w, max_h, min_d), Vector(min_w, max_h, max_d), color = self._volume_outline_color)
+            mb.addLine(Vector(max_w, max_h, min_d), Vector(max_w, max_h, max_d), color = self._volume_outline_color)
 
             self.setMeshData(mb.build())
 
@@ -228,8 +249,8 @@ class BuildVolume(SceneNode):
                 aspect = self._depth / self._width
                 scale_matrix.compose(scale = Vector(1, 1, aspect))
             mb = MeshBuilder()
-            mb.addArc(max_w, Vector.Unit_Y, center = (0, min_h - z_fight_distance, 0), color = self.VolumeOutlineColor)
-            mb.addArc(max_w, Vector.Unit_Y, center = (0, max_h, 0),  color = self.VolumeOutlineColor)
+            mb.addArc(max_w, Vector.Unit_Y, center = (0, min_h - z_fight_distance, 0), color = self._volume_outline_color)
+            mb.addArc(max_w, Vector.Unit_Y, center = (0, max_h, 0),  color = self._volume_outline_color)
             self.setMeshData(mb.build().getTransformed(scale_matrix))
 
             # Build plate grid mesh
@@ -260,21 +281,21 @@ class BuildVolume(SceneNode):
             height = self._origin_line_width,
             depth = self._origin_line_width,
             center = origin + Vector(self._origin_line_length / 2, 0, 0),
-            color = self.XAxisColor
+            color = self._x_axis_color
         )
         mb.addCube(
             width = self._origin_line_width,
             height = self._origin_line_length,
             depth = self._origin_line_width,
             center = origin + Vector(0, self._origin_line_length / 2, 0),
-            color = self.YAxisColor
+            color = self._y_axis_color
         )
         mb.addCube(
             width = self._origin_line_width,
             height = self._origin_line_width,
             depth = self._origin_line_length,
             center = origin - Vector(0, 0, self._origin_line_length / 2),
-            color = self.ZAxisColor
+            color = self._z_axis_color
         )
         self._origin_mesh = mb.build()
 
@@ -282,7 +303,7 @@ class BuildVolume(SceneNode):
         disallowed_area_size = 0
         if self._disallowed_areas:
             mb = MeshBuilder()
-            color = Color(0.0, 0.0, 0.0, 0.15)
+            color = self._disallowed_area_color
             for polygon in self._disallowed_areas:
                 points = polygon.getPoints()
                 if len(points) == 0:
@@ -311,7 +332,7 @@ class BuildVolume(SceneNode):
         if self._error_areas:
             mb = MeshBuilder()
             for error_area in self._error_areas:
-                color = Color(1.0, 0.0, 0.0, 0.5)
+                color = self._error_area_color
                 points = error_area.getPoints()
                 first = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height,
                                self._clamp(points[0][1], min_d, max_d))
@@ -398,7 +419,12 @@ class BuildVolume(SceneNode):
             self._updateDisallowedAreas()
             self._updateRaftThickness()
 
-            self.rebuild()
+            if self._engine_ready:
+                self.rebuild()
+
+    def _onEngineCreated(self):
+        self._engine_ready = True
+        self.rebuild()
 
     def _onSettingPropertyChanged(self, setting_key, property_name):
         if property_name != "value":

+ 3 - 2
cura/ConvexHullNode.py

@@ -1,6 +1,7 @@
 # Copyright (c) 2015 Ultimaker B.V.
 # Cura is released under the terms of the AGPLv3 or higher.
 
+from UM.Application import Application
 from UM.Scene.SceneNode import SceneNode
 from UM.Resources import Resources
 from UM.Math.Color import Color
@@ -23,7 +24,7 @@ class ConvexHullNode(SceneNode):
         self._original_parent = parent
 
         # Color of the drawn convex hull
-        self._color = Color(0.4, 0.4, 0.4, 1.0)
+        self._color = None
 
         # The y-coordinate of the convex hull mesh. Must not be 0, to prevent z-fighting.
         self._mesh_height = 0.1
@@ -72,7 +73,7 @@ class ConvexHullNode(SceneNode):
         return True
 
     def _onNodeDecoratorsChanged(self, node):
-        self._color = Color(35, 35, 35, 0.5)
+        self._color = Color(*Application.getInstance().getTheme().getColor("convex_hull").getRgb())
 
         convex_hull_head = self._node.callDecoration("getConvexHullHead")
         if convex_hull_head:

+ 9 - 0
cura/CuraApplication.py

@@ -223,6 +223,10 @@ class CuraApplication(QtApplication):
         Preferences.getInstance().addPreference("mesh/scale_tiny_meshes", True)
         Preferences.getInstance().addPreference("cura/dialog_on_project_save", True)
         Preferences.getInstance().addPreference("cura/asked_dialog_on_project_save", False)
+
+        Preferences.getInstance().addPreference("cura/currency", "€")
+        Preferences.getInstance().addPreference("cura/material_settings", "{}")
+
         for key in [
             "dialog_load_path",  # dialog_save_path is in LocalFileOutputDevicePlugin
             "dialog_profile_path",
@@ -315,6 +319,11 @@ class CuraApplication(QtApplication):
 
     showPrintMonitor = pyqtSignal(bool, arguments = ["show"])
 
+    def setViewLegendItems(self, items):
+        self.viewLegendItemsChanged.emit(items)
+
+    viewLegendItemsChanged = pyqtSignal("QVariantList", arguments = ["items"])
+
     ##  Cura has multiple locations where instance containers need to be saved, so we need to handle this differently.
     #
     #   Note that the AutoSave plugin also calls this method.

+ 24 - 14
cura/LayerPolygon.py

@@ -1,4 +1,5 @@
 from UM.Math.Color import Color
+from UM.Application import Application
 
 import numpy
 
@@ -40,6 +41,7 @@ class LayerPolygon:
 
         # Buffering the colors shouldn't be necessary as it is not 
         # re-used and can save alot of memory usage.
+        self._color_map = LayerPolygon.getColorMap()
         self._colors = self._color_map[self._types]
         
         # When type is used as index returns true if type == LayerPolygon.InfillType or type == LayerPolygon.SkinType or type == LayerPolygon.SupportInfillType
@@ -182,17 +184,25 @@ class LayerPolygon:
 
         return normals
 
-    # Should be generated in better way, not hardcoded.
-    _color_map = numpy.array([
-        [1.0,  1.0,  1.0, 1.0], # NoneType
-        [1.0,  0.0,  0.0, 1.0], # Inset0Type
-        [0.0,  1.0,  0.0, 1.0], # InsetXType
-        [1.0,  1.0,  0.0, 1.0], # SkinType
-        [0.0,  1.0,  1.0, 1.0], # SupportType
-        [0.0,  1.0,  1.0, 1.0], # SkirtType
-        [1.0,  0.75, 0.0, 1.0], # InfillType
-        [0.0,  1.0,  1.0, 1.0], # SupportInfillType
-        [0.0,  0.0,  1.0, 1.0], # MoveCombingType
-        [0.5,  0.5,  1.0, 1.0], # MoveRetractionType
-        [0.25, 0.75, 1.0, 1.0]  # SupportInterfaceType
-    ])
+    __color_map = None
+
+    ##  Gets the instance of the VersionUpgradeManager, or creates one.
+    @classmethod
+    def getColorMap(cls):
+        if cls.__color_map is None:
+            theme = Application.getInstance().getTheme()
+            cls.__color_map = numpy.array([
+                theme.getColor("layerview_none").getRgbF(), # NoneType
+                theme.getColor("layerview_inset_0").getRgbF(), # Inset0Type
+                theme.getColor("layerview_inset_x").getRgbF(), # InsetXType
+                theme.getColor("layerview_skin").getRgbF(), # SkinType
+                theme.getColor("layerview_support").getRgbF(), # SupportType
+                theme.getColor("layerview_skirt").getRgbF(), # SkirtType
+                theme.getColor("layerview_infill").getRgbF(), # InfillType
+                theme.getColor("layerview_support_infill").getRgbF(), # SupportInfillType
+                theme.getColor("layerview_move_combing").getRgbF(), # MoveCombingType
+                theme.getColor("layerview_move_retraction").getRgbF(), # MoveRetractionType
+                theme.getColor("layerview_support_interface").getRgbF()  # SupportInterfaceType
+            ])
+
+        return cls.__color_map

+ 65 - 2
cura/PrintInformation.py

@@ -7,12 +7,14 @@ from UM.FlameProfiler import pyqtSlot
 from UM.Application import Application
 from UM.Qt.Duration import Duration
 from UM.Preferences import Preferences
+from UM.Settings import ContainerRegistry
 
 import cura.Settings.ExtruderManager
 
 import math
 import os.path
 import unicodedata
+import json
 
 from UM.i18n import i18nCatalog
 catalog = i18nCatalog("cura")
@@ -52,6 +54,7 @@ class PrintInformation(QObject):
 
         self._material_lengths = []
         self._material_weights = []
+        self._material_costs = []
 
         self._pre_sliced = False
 
@@ -65,6 +68,12 @@ class PrintInformation(QObject):
         Application.getInstance().globalContainerStackChanged.connect(self._setAbbreviatedMachineName)
         Application.getInstance().fileLoaded.connect(self.setJobName)
 
+        Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)
+
+        self._active_material_container = None
+        Application.getInstance().getMachineManager().activeMaterialChanged.connect(self._onActiveMaterialChanged)
+        self._onActiveMaterialChanged()
+
     currentPrintTimeChanged = pyqtSignal()
 
     preSlicedChanged = pyqtSignal()
@@ -93,28 +102,82 @@ class PrintInformation(QObject):
     def materialWeights(self):
         return self._material_weights
 
+    materialCostsChanged = pyqtSignal()
+
+    @pyqtProperty("QVariantList", notify = materialCostsChanged)
+    def materialCosts(self):
+        return self._material_costs
+
     def _onPrintDurationMessage(self, total_time, material_amounts):
         self._current_print_time.setDuration(total_time)
         self.currentPrintTimeChanged.emit()
 
+        self._material_amounts = material_amounts
+        self._calculateInformation()
+
+    def _calculateInformation(self):
         # Material amount is sent as an amount of mm^3, so calculate length from that
         r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2
         self._material_lengths = []
         self._material_weights = []
+        self._material_costs = []
+
+        material_preference_values = json.loads(Preferences.getInstance().getValue("cura/material_settings"))
+
         extruder_stacks = list(cura.Settings.ExtruderManager.getInstance().getMachineExtruders(Application.getInstance().getGlobalContainerStack().getId()))
-        for index, amount in enumerate(material_amounts):
+        for index, amount in enumerate(self._material_amounts):
             ## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some
             #  list comprehension filtering to solve this for us.
+            material = None
             if extruder_stacks:  # Multi extrusion machine
                 extruder_stack = [extruder for extruder in extruder_stacks if extruder.getMetaDataEntry("position") == str(index)][0]
                 density = extruder_stack.getMetaDataEntry("properties", {}).get("density", 0)
+                material = extruder_stack.findContainer({"type": "material"})
             else:  # Machine with no extruder stacks
                 density = Application.getInstance().getGlobalContainerStack().getMetaDataEntry("properties", {}).get("density", 0)
+                material = Application.getInstance().getGlobalContainerStack().findContainer({"type": "material"})
+
+            weight = float(amount) * float(density) / 1000
+            cost = 0
+            if material:
+                material_guid = material.getMetaDataEntry("GUID")
+                if material_guid in material_preference_values:
+                    material_values = material_preference_values[material_guid]
+
+                    weight_per_spool = float(material_values["spool_weight"] if material_values and "spool_weight" in material_values else 0)
+                    cost_per_spool = float(material_values["spool_cost"] if material_values and "spool_cost" in material_values else 0)
 
-            self._material_weights.append(float(amount) * float(density) / 1000)
+                    if weight_per_spool != 0:
+                        cost = cost_per_spool * weight / weight_per_spool
+                    else:
+                        cost = 0
+
+            self._material_weights.append(weight)
             self._material_lengths.append(round((amount / (math.pi * r ** 2)) / 1000, 2))
+            self._material_costs.append(cost)
+
         self.materialLengthsChanged.emit()
         self.materialWeightsChanged.emit()
+        self.materialCostsChanged.emit()
+
+    def _onPreferencesChanged(self, preference):
+        if preference != "cura/material_settings":
+            return
+
+        self._calculateInformation()
+
+    def _onActiveMaterialChanged(self):
+        if self._active_material_container:
+            self._active_material_container.metaDataChanged.disconnect(self._onMaterialMetaDataChanged)
+
+        active_material_id = Application.getInstance().getMachineManager().activeMaterialId
+        self._active_material_container = ContainerRegistry.getInstance().findInstanceContainers(id=active_material_id)[0]
+
+        if self._active_material_container:
+            self._active_material_container.metaDataChanged.connect(self._onMaterialMetaDataChanged)
+
+    def _onMaterialMetaDataChanged(self):
+        self._calculateInformation()
 
     @pyqtSlot(str)
     def setJobName(self, name):

+ 3 - 2
cura/Settings/ExtruderManager.py

@@ -96,8 +96,9 @@ class ExtruderManager(QObject):
     #   \param index The index of the new active extruder.
     @pyqtSlot(int)
     def setActiveExtruderIndex(self, index):
-        self._active_extruder_index = index
-        self.activeExtruderChanged.emit()
+        if self._active_extruder_index != index:
+            self._active_extruder_index = index
+            self.activeExtruderChanged.emit()
 
     @pyqtProperty(int, notify = activeExtruderChanged)
     def activeExtruderIndex(self):

+ 36 - 24
plugins/3MFReader/WorkspaceDialog.py

@@ -70,8 +70,9 @@ class WorkspaceDialog(QObject):
         return self._variant_type
 
     def setVariantType(self, variant_type):
-        self._variant_type = variant_type
-        self.variantTypeChanged.emit()
+        if self._variant_type != variant_type:
+            self._variant_type = variant_type
+            self.variantTypeChanged.emit()
 
     @pyqtProperty(str, notify=machineTypeChanged)
     def machineType(self):
@@ -82,8 +83,9 @@ class WorkspaceDialog(QObject):
         self.machineTypeChanged.emit()
 
     def setNumUserSettings(self, num_user_settings):
-        self._num_user_settings = num_user_settings
-        self.numVisibleSettingsChanged.emit()
+        if self._num_user_settings != num_user_settings:
+            self._num_user_settings = num_user_settings
+            self.numVisibleSettingsChanged.emit()
 
     @pyqtProperty(int, notify=numUserSettingsChanged)
     def numUserSettings(self):
@@ -94,40 +96,45 @@ class WorkspaceDialog(QObject):
         return self._objects_on_plate
 
     def setHasObjectsOnPlate(self, objects_on_plate):
-        self._objects_on_plate = objects_on_plate
-        self.objectsOnPlateChanged.emit()
+        if self._objects_on_plate != objects_on_plate:
+            self._objects_on_plate = objects_on_plate
+            self.objectsOnPlateChanged.emit()
 
     @pyqtProperty("QVariantList", notify = materialLabelsChanged)
     def materialLabels(self):
         return self._material_labels
 
     def setMaterialLabels(self, material_labels):
-        self._material_labels = material_labels
-        self.materialLabelsChanged.emit()
+        if self._material_labels != material_labels:
+            self._material_labels = material_labels
+            self.materialLabelsChanged.emit()
 
     @pyqtProperty("QVariantList", notify=extrudersChanged)
     def extruders(self):
         return self._extruders
 
     def setExtruders(self, extruders):
-        self._extruders = extruders
-        self.extrudersChanged.emit()
+        if self._extruders != extruders:
+            self._extruders = extruders
+            self.extrudersChanged.emit()
 
     @pyqtProperty(str, notify = machineNameChanged)
     def machineName(self):
         return self._machine_name
 
     def setMachineName(self, machine_name):
-        self._machine_name = machine_name
-        self.machineNameChanged.emit()
+        if self._machine_name != machine_name:
+            self._machine_name = machine_name
+            self.machineNameChanged.emit()
 
     @pyqtProperty(str, notify=qualityTypeChanged)
     def qualityType(self):
         return self._quality_type
 
     def setQualityType(self, quality_type):
-        self._quality_type = quality_type
-        self.qualityTypeChanged.emit()
+        if self._quality_type != quality_type:
+            self._quality_type = quality_type
+            self.qualityTypeChanged.emit()
 
     @pyqtProperty(int, notify=numSettingsOverridenByQualityChangesChanged)
     def numSettingsOverridenByQualityChanges(self):
@@ -142,8 +149,9 @@ class WorkspaceDialog(QObject):
         return self._quality_name
 
     def setQualityName(self, quality_name):
-        self._quality_name = quality_name
-        self.qualityNameChanged.emit()
+        if self._quality_name != quality_name:
+            self._quality_name = quality_name
+            self.qualityNameChanged.emit()
 
     @pyqtProperty(str, notify=activeModeChanged)
     def activeMode(self):
@@ -165,8 +173,9 @@ class WorkspaceDialog(QObject):
         return self._num_visible_settings
 
     def setNumVisibleSettings(self, num_visible_settings):
-        self._num_visible_settings = num_visible_settings
-        self.numVisibleSettingsChanged.emit()
+        if self._num_visible_settings != num_visible_settings:
+            self._num_visible_settings = num_visible_settings
+            self.numVisibleSettingsChanged.emit()
 
     @pyqtProperty(bool, notify = machineConflictChanged)
     def machineConflict(self):
@@ -191,16 +200,19 @@ class WorkspaceDialog(QObject):
         Application.getInstance().getBackend().close()
 
     def setMaterialConflict(self, material_conflict):
-        self._has_material_conflict = material_conflict
-        self.materialConflictChanged.emit()
+        if self._has_material_conflict != material_conflict:
+            self._has_material_conflict = material_conflict
+            self.materialConflictChanged.emit()
 
     def setMachineConflict(self, machine_conflict):
-        self._has_machine_conflict = machine_conflict
-        self.machineConflictChanged.emit()
+        if self._has_machine_conflict != machine_conflict:
+            self._has_machine_conflict = machine_conflict
+            self.machineConflictChanged.emit()
 
     def setQualityChangesConflict(self, quality_changes_conflict):
-        self._has_quality_changes_conflict = quality_changes_conflict
-        self.qualityChangesConflictChanged.emit()
+        if self._has_quality_changes_conflict != quality_changes_conflict:
+            self._has_quality_changes_conflict = quality_changes_conflict
+            self.qualityChangesConflictChanged.emit()
 
     def getResult(self):
         if "machine" in self._result and not self._has_machine_conflict:

+ 3 - 0
plugins/ChangeLogPlugin/ChangeLog.txt

@@ -98,6 +98,9 @@ Use a mesh to specify a volume within which to classify nothing as overhang for
 *Delta printer support
 This release adds support for printers with elliptic buildplates. This feature has not been extensively tested so please let us know if it works or get involved in improving it.
 
+*AppImage for Linux
+The Linux distribution is now in AppImage format, which makes Cura easier to install.
+
 *bugfixes
 The user is now notified when a new version of Cura is available.
 When searching in the setting visibility preferences, the category for each setting is always displayed.

+ 0 - 2
plugins/ImageReader/ConfigUI.qml

@@ -12,11 +12,9 @@ UM.Dialog
 {
     width: 350 * Screen.devicePixelRatio;
     minimumWidth: 350 * Screen.devicePixelRatio;
-    maximumWidth: 350 * Screen.devicePixelRatio;
 
     height: 250 * Screen.devicePixelRatio;
     minimumHeight: 250 * Screen.devicePixelRatio;
-    maximumHeight: 250 * Screen.devicePixelRatio;
 
     title: catalog.i18nc("@title:window", "Convert Image...")
 

+ 27 - 1
plugins/LayerView/LayerView.py

@@ -67,6 +67,7 @@ class LayerView(View):
         self._show_adhesion = 1
         self._show_skin = 1
         self._show_infill = 1
+        self._legend_items = None
 
         Preferences.getInstance().addPreference("view/top_layer_count", 5)
         Preferences.getInstance().addPreference("view/only_show_top_layers", False)
@@ -125,7 +126,7 @@ class LayerView(View):
 
         if not self._ghost_shader:
             self._ghost_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "color.shader"))
-            self._ghost_shader.setUniformValue("u_color", Color(32, 32, 32, 96))
+            self._ghost_shader.setUniformValue("u_color", Color(*Application.getInstance().getTheme().getColor("layerview_ghost").getRgb()))
 
         for node in DepthFirstIterator(scene.getRoot()):
             # We do not want to render ConvexHullNode as it conflicts with the bottom layers.
@@ -278,6 +279,9 @@ class LayerView(View):
 
             if not self._layerview_composite_shader:
                 self._layerview_composite_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("LayerView"), "layerview_composite.shader"))
+                theme = Application.getInstance().getTheme()
+                self._layerview_composite_shader.setUniformValue("u_background_color", Color(*theme.getColor("viewport_background").getRgb()))
+                self._layerview_composite_shader.setUniformValue("u_outline_color", Color(*theme.getColor("model_selection_outline").getRgb()))
 
             if not self._composite_pass:
                 self._composite_pass = self.getRenderer().getRenderPass("composite")
@@ -287,6 +291,8 @@ class LayerView(View):
             self._old_composite_shader = self._composite_pass.getCompositeShader()
             self._composite_pass.setCompositeShader(self._layerview_composite_shader)
 
+            Application.getInstance().setViewLegendItems(self._getLegendItems())
+
         elif event.type == Event.ViewDeactivateEvent:
             self._wireprint_warning_message.hide()
             Application.getInstance().globalContainerStackChanged.disconnect(self._onGlobalStackChanged)
@@ -296,6 +302,8 @@ class LayerView(View):
             self._composite_pass.setLayerBindings(self._old_layer_bindings)
             self._composite_pass.setCompositeShader(self._old_composite_shader)
 
+            Application.getInstance().setViewLegendItems([])
+
     def _onGlobalStackChanged(self):
         if self._global_container_stack:
             self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
@@ -348,6 +356,24 @@ class LayerView(View):
 
         self._startUpdateTopLayers()
 
+    def _getLegendItems(self):
+        if self._legend_items is None:
+            theme = Application.getInstance().getTheme()
+            self._legend_items = [
+                {"color": theme.getColor("layerview_inset_0").name(), "title": catalog.i18nc("@label:layerview polygon type", "Outer Wall")}, # Inset0Type
+                {"color": theme.getColor("layerview_inset_x").name(), "title": catalog.i18nc("@label:layerview polygon type", "Inner Wall")}, # InsetXType
+                {"color": theme.getColor("layerview_skin").name(), "title": catalog.i18nc("@label:layerview polygon type", "Top / Bottom")}, # SkinType
+                {"color": theme.getColor("layerview_infill").name(), "title": catalog.i18nc("@label:layerview polygon type", "Infill")}, # InfillType
+                {"color": theme.getColor("layerview_support").name(), "title": catalog.i18nc("@label:layerview polygon type", "Support Skin")}, # SupportType
+                {"color": theme.getColor("layerview_support_infill").name(), "title": catalog.i18nc("@label:layerview polygon type", "Support Infill")}, # SupportInfillType
+                {"color": theme.getColor("layerview_support_interface").name(), "title": catalog.i18nc("@label:layerview polygon type", "Support Interface")},  # SupportInterfaceType
+                {"color": theme.getColor("layerview_skirt").name(), "title": catalog.i18nc("@label:layerview polygon type", "Build Plate Adhesion")}, # SkirtType
+                {"color": theme.getColor("layerview_move_combing").name(), "title": catalog.i18nc("@label:layerview polygon type", "Travel Move")}, # MoveCombingType
+                {"color": theme.getColor("layerview_move_retraction").name(), "title": catalog.i18nc("@label:layerview polygon type", "Retraction Move")}, # MoveRetractionType
+                #{"color": theme.getColor("layerview_none").name(), "title": catalog.i18nc("@label:layerview polygon type", "Unknown")} # NoneType
+            ]
+        return self._legend_items
+
 
 class _CreateTopLayersJob(Job):
     def __init__(self, scene, layer_number, solid_layers):

Some files were not shown because too many files changed in this diff