diff --git a/cura/ConvexHullNode.py b/cura/ConvexHullNode.py index a94ae60897..5be5820982 100644 --- a/cura/ConvexHullNode.py +++ b/cura/ConvexHullNode.py @@ -48,6 +48,9 @@ class ConvexHullNode(SceneNode): self.setMeshData(mesh) + def getWatchedNode(self): + return self._node + def render(self, renderer): if not self._material: self._material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "color.frag")) diff --git a/plugins/CuraEngineBackend/Cura_pb2.py b/plugins/CuraEngineBackend/Cura_pb2.py index cf95bd2832..f97aaafc4d 100644 --- a/plugins/CuraEngineBackend/Cura_pb2.py +++ b/plugins/CuraEngineBackend/Cura_pb2.py @@ -1,6 +1,3 @@ -# Copyright (c) 2015 Ultimaker B.V. -# Cura is released under the terms of the AGPLv3 or higher. - # Generated by the protocol buffer compiler. DO NOT EDIT! # source: Cura.proto @@ -21,7 +18,7 @@ _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='Cura.proto', package='Cura', - serialized_pb=_b('\n\nCura.proto\x12\x04\x43ura\"+\n\nObjectList\x12\x1d\n\x07objects\x18\x01 \x03(\x0b\x32\x0c.Cura.Object\"i\n\x06Object\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08vertices\x18\x02 \x01(\x0c\x12\x0f\n\x07normals\x18\x03 \x01(\x0c\x12\x0f\n\x07indices\x18\x04 \x01(\x0c\x12\x1f\n\x08settings\x18\x05 \x03(\x0b\x32\r.Cura.Setting\"\x1a\n\x08Progress\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x02\"7\n\x10SlicedObjectList\x12#\n\x07objects\x18\x01 \x03(\x0b\x32\x12.Cura.SlicedObject\"7\n\x0cSlicedObject\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x1b\n\x06layers\x18\x02 \x03(\x0b\x32\x0b.Cura.Layer\"4\n\x05Layer\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x1f\n\x08polygons\x18\x02 \x03(\x0b\x32\r.Cura.Polygon\"\x9f\x01\n\x07Polygon\x12 \n\x04type\x18\x01 \x01(\x0e\x32\x12.Cura.Polygon.Type\x12\x0e\n\x06points\x18\x02 \x01(\x0c\"b\n\x04Type\x12\x0c\n\x08NoneType\x10\x00\x12\x0e\n\nInset0Type\x10\x01\x12\x0e\n\nInsetXType\x10\x02\x12\x0c\n\x08SkinType\x10\x03\x12\x0f\n\x0bSupportType\x10\x04\x12\r\n\tSkirtType\x10\x05\"&\n\nGCodeLayer\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"D\n\x0fObjectPrintTime\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04time\x18\x02 \x01(\x02\x12\x17\n\x0fmaterial_amount\x18\x03 \x01(\x02\".\n\x0bSettingList\x12\x1f\n\x08settings\x18\x01 \x03(\x0b\x32\r.Cura.Setting\"&\n\x07Setting\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\"\x1b\n\x0bGCodePrefix\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x62\x06proto3') + serialized_pb=_b('\n\nCura.proto\x12\x04\x43ura\"+\n\nObjectList\x12\x1d\n\x07objects\x18\x01 \x03(\x0b\x32\x0c.Cura.Object\"i\n\x06Object\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08vertices\x18\x02 \x01(\x0c\x12\x0f\n\x07normals\x18\x03 \x01(\x0c\x12\x0f\n\x07indices\x18\x04 \x01(\x0c\x12\x1f\n\x08settings\x18\x05 \x03(\x0b\x32\r.Cura.Setting\"\x1a\n\x08Progress\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x02\"7\n\x10SlicedObjectList\x12#\n\x07objects\x18\x01 \x03(\x0b\x32\x12.Cura.SlicedObject\"7\n\x0cSlicedObject\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x1b\n\x06layers\x18\x02 \x03(\x0b\x32\x0b.Cura.Layer\"W\n\x05Layer\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0e\n\x06height\x18\x02 \x01(\x02\x12\x11\n\tthickness\x18\x03 \x01(\x02\x12\x1f\n\x08polygons\x18\x04 \x03(\x0b\x32\r.Cura.Polygon\"\xdb\x01\n\x07Polygon\x12 \n\x04type\x18\x01 \x01(\x0e\x32\x12.Cura.Polygon.Type\x12\x0e\n\x06points\x18\x02 \x01(\x0c\x12\x12\n\nline_width\x18\x03 \x01(\x02\"\x89\x01\n\x04Type\x12\x0c\n\x08NoneType\x10\x00\x12\x0e\n\nInset0Type\x10\x01\x12\x0e\n\nInsetXType\x10\x02\x12\x0c\n\x08SkinType\x10\x03\x12\x0f\n\x0bSupportType\x10\x04\x12\r\n\tSkirtType\x10\x05\x12\x0e\n\nInfillType\x10\x06\x12\x15\n\x11SupportInfillType\x10\x07\"&\n\nGCodeLayer\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"D\n\x0fObjectPrintTime\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04time\x18\x02 \x01(\x02\x12\x17\n\x0fmaterial_amount\x18\x03 \x01(\x02\".\n\x0bSettingList\x12\x1f\n\x08settings\x18\x01 \x03(\x0b\x32\r.Cura.Setting\"&\n\x07Setting\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\"\x1b\n\x0bGCodePrefix\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x62\x06proto3') ) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -57,11 +54,19 @@ _POLYGON_TYPE = _descriptor.EnumDescriptor( name='SkirtType', index=5, number=5, options=None, type=None), + _descriptor.EnumValueDescriptor( + name='InfillType', index=6, number=6, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SupportInfillType', index=7, number=7, + options=None, + type=None), ], containing_type=None, options=None, - serialized_start=430, - serialized_end=528, + serialized_start=486, + serialized_end=623, ) _sym_db.RegisterEnumDescriptor(_POLYGON_TYPE) @@ -266,8 +271,22 @@ _LAYER = _descriptor.Descriptor( is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='polygons', full_name='Cura.Layer.polygons', index=1, - number=2, type=11, cpp_type=10, label=3, + name='height', full_name='Cura.Layer.height', index=1, + number=2, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='thickness', full_name='Cura.Layer.thickness', index=2, + number=3, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='polygons', full_name='Cura.Layer.polygons', index=3, + number=4, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, @@ -284,7 +303,7 @@ _LAYER = _descriptor.Descriptor( oneofs=[ ], serialized_start=314, - serialized_end=366, + serialized_end=401, ) @@ -309,6 +328,13 @@ _POLYGON = _descriptor.Descriptor( message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), + _descriptor.FieldDescriptor( + name='line_width', full_name='Cura.Polygon.line_width', index=2, + number=3, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), ], extensions=[ ], @@ -321,8 +347,8 @@ _POLYGON = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=369, - serialized_end=528, + serialized_start=404, + serialized_end=623, ) @@ -358,8 +384,8 @@ _GCODELAYER = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=530, - serialized_end=568, + serialized_start=625, + serialized_end=663, ) @@ -402,8 +428,8 @@ _OBJECTPRINTTIME = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=570, - serialized_end=638, + serialized_start=665, + serialized_end=733, ) @@ -432,8 +458,8 @@ _SETTINGLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=640, - serialized_end=686, + serialized_start=735, + serialized_end=781, ) @@ -469,8 +495,8 @@ _SETTING = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=688, - serialized_end=726, + serialized_start=783, + serialized_end=821, ) @@ -499,8 +525,8 @@ _GCODEPREFIX = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=728, - serialized_end=755, + serialized_start=823, + serialized_end=850, ) _OBJECTLIST.fields_by_name['objects'].message_type = _OBJECT diff --git a/plugins/CuraEngineBackend/LayerData.py b/plugins/CuraEngineBackend/LayerData.py index 546397e460..b129942c36 100644 --- a/plugins/CuraEngineBackend/LayerData.py +++ b/plugins/CuraEngineBackend/LayerData.py @@ -2,7 +2,9 @@ # Cura is released under the terms of the AGPLv3 or higher. from UM.Mesh.MeshData import MeshData +from UM.Mesh.MeshBuilder import MeshBuilder from UM.Math.Color import Color +from UM.Math.Vector import Vector import numpy import math @@ -13,12 +15,19 @@ class LayerData(MeshData): self._layers = {} self._element_counts = {} - def addPolygon(self, layer, type, data): + def addLayer(self, layer): if layer not in self._layers: - self._layers[layer] = [] + self._layers[layer] = Layer(layer) - p = Polygon(self, type, data) - self._layers[layer].append(p) + def addPolygon(self, layer, type, data, line_width): + if layer not in self._layers: + self.addLayer(layer) + + p = Polygon(self, type, data, line_width) + self._layers[layer].polygons.append(p) + + def getLayer(self, layer): + return self._layers[layer] def getLayers(self): return self._layers @@ -26,14 +35,112 @@ class LayerData(MeshData): def getElementCounts(self): return self._element_counts + def setLayerHeight(self, layer, height): + if layer not in self._layers: + self.addLayer(layer) + + self._layers[layer].setHeight(height) + + def setLayerThickness(self, layer, thickness): + if layer not in self._layers: + self.addLayer(layer) + + self._layers[layer].setThickness(thickness) + def build(self): for layer, data in self._layers.items(): - if layer not in self._element_counts: - self._element_counts[layer] = [] + data.build() - for polygon in data: - polygon.build() - self._element_counts[layer].append(polygon.elementCount) + self._element_counts[layer] = data.elementCount + +class Layer(): + def __init__(self, id): + self._id = id + self._height = 0.0 + self._thickness = 0.0 + self._polygons = [] + self._element_count = 0 + + @property + def height(self): + return self._height + + @property + def thickness(self): + return self._thickness + + @property + def polygons(self): + return self._polygons + + @property + def elementCount(self): + return self._element_count + + def setHeight(self, height): + self._height = height + + def setThickness(self, thickness): + self._thickness = thickness + + def build(self): + for polygon in self._polygons: + if polygon._type == Polygon.InfillType or polygon._type == Polygon.SupportInfillType: + continue + + polygon.build() + self._element_count += polygon.elementCount + + def createMesh(self): + builder = MeshBuilder() + + for polygon in self._polygons: + poly_color = polygon.getColor() + poly_color = Color(poly_color[0], poly_color[1], poly_color[2], poly_color[3]) + + points = numpy.copy(polygon.data) + if polygon.type == Polygon.InfillType or polygon.type == Polygon.SkinType or polygon.type == Polygon.SupportInfillType: + points[:,1] -= 0.01 + + # Calculate normals for the entire polygon using numpy. + normals = numpy.copy(points) + normals[:,1] = 0.0 # We are only interested in 2D normals + + # Calculate the edges between points. + # The call to numpy.roll shifts the entire array by one so that + # we end up subtracting each next point from the current, wrapping + # around. This gives us the edges from the next point to the current + # point. + normals[:] = normals[:] - numpy.roll(normals, -1, axis = 0) + # Calculate the length of each edge using standard Pythagoras + lengths = numpy.sqrt(normals[:,0] ** 2 + normals[:,2] ** 2) + # The normal of a 2D vector is equal to its x and y coordinates swapped + # and then x inverted. This code does that. + normals[:,[0, 2]] = normals[:,[2, 0]] + normals[:,0] *= -1 + + # Normalize the normals. + normals[:,0] /= lengths + normals[:,2] /= lengths + + # Scale all by the line width of the polygon so we can easily offset. + normals *= (polygon.lineWidth / 2) + + #TODO: Use numpy magic to perform the vertex creation to speed up things. + for i in range(len(points)): + start = points[i - 1] + end = points[i] + + normal = normals[i - 1] + + point1 = Vector(data = start - normal) + point2 = Vector(data = start + normal) + point3 = Vector(data = end + normal) + point4 = Vector(data = end - normal) + + builder.addQuad(point1, point2, point3, point4, color = poly_color) + + return builder.getData() class Polygon(): NoneType = 0 @@ -42,34 +149,26 @@ class Polygon(): SkinType = 3 SupportType = 4 SkirtType = 5 + InfillType = 6 + SupportInfillType = 7 - def __init__(self, mesh, type, data): + def __init__(self, mesh, type, data, line_width): super().__init__() self._mesh = mesh self._type = type self._data = data + self._line_width = line_width / 1000 def build(self): self._begin = self._mesh._vertex_count self._mesh.addVertices(self._data) self._end = self._begin + len(self._data) - 1 - color = None - if self._type == self.Inset0Type: - color = [1, 0, 0, 1] - elif self._type == self.InsetXType: - color = [0, 1, 0, 1] - elif self._type == self.SkinType: - color = [1, 1, 0, 1] - elif self._type == self.SupportType: - color = [0, 1, 1, 1] - elif self._type == self.SkirtType: - color = [0, 1, 1, 1] - else: - color = [1, 1, 1, 1] + color = self.getColor() + color[3] = 2.0 colors = [color for i in range(len(self._data))] - self._mesh.addColors(numpy.array(colors, dtype=numpy.float32)) + self._mesh.addColors(numpy.array(colors, dtype=numpy.float32) * 0.5) indices = [] for i in range(self._begin, self._end): @@ -80,6 +179,24 @@ class Polygon(): indices.append(self._begin) self._mesh.addIndices(numpy.array(indices, dtype=numpy.int32)) + def getColor(self): + if self._type == self.Inset0Type: + return [1.0, 0.0, 0.0, 1.0] + elif self._type == self.InsetXType: + return [0.0, 1.0, 0.0, 1.0] + elif self._type == self.SkinType: + return [1.0, 1.0, 0.0, 1.0] + elif self._type == self.SupportType: + return [0.0, 1.0, 1.0, 1.0] + elif self._type == self.SkirtType: + return [0.0, 1.0, 1.0, 1.0] + elif self._type == self.InfillType: + return [1.0, 1.0, 0.0, 1.0] + elif self._type == self.SupportInfillType: + return [0.0, 1.0, 1.0, 1.0] + else: + return [1.0, 1.0, 1.0, 1.0] + @property def type(self): return self._type @@ -90,4 +207,8 @@ class Polygon(): @property def elementCount(self): - return (self._end - self._begin) * 2 #The range of vertices multiplied by 2 since each vertex is used twice + return ((self._end - self._begin) + 1) * 2 #The range of vertices multiplied by 2 since each vertex is used twice + + @property + def lineWidth(self): + return self._line_width diff --git a/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py b/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py index 804338e4dc..6113da78a0 100644 --- a/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py +++ b/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py @@ -32,22 +32,24 @@ class ProcessSlicedObjectListJob(Job): settings = Application.getInstance().getActiveMachine() layerHeight = settings.getSettingValueByKey("layer_height") + mesh = MeshData() for object in self._message.objects: - try: + try: node = objectIdMap[object.id] except KeyError: continue - - mesh = MeshData() layerData = LayerData.LayerData() for layer in object.layers: + layerData.addLayer(layer.id) + layerData.setLayerHeight(layer.id, layer.height) + layerData.setLayerThickness(layer.id, layer.thickness) for polygon in layer.polygons: points = numpy.fromstring(polygon.points, dtype="i8") # Convert bytearray to numpy array points = points.reshape((-1,2)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly. points = numpy.asarray(points, dtype=numpy.float32) points /= 1000 - points = numpy.insert(points, 1, layer.id * layerHeight, axis = 1) + points = numpy.insert(points, 1, (layer.height / 1000), axis = 1) points[:,2] *= -1 @@ -55,16 +57,11 @@ class ProcessSlicedObjectListJob(Job): center = [settings.getSettingValueByKey("machine_width") / 2, 0.0, -settings.getSettingValueByKey("machine_depth") / 2] points -= numpy.array(center) - #points = numpy.pad(points, ((0,0), (0,1)), "constant", constant_values=(0.0, 1.0)) - #inverse = node.getWorldTransformation().getInverse().getData() - #points = points.dot(inverse) - #points = points[:,0:3] + layerData.addPolygon(layer.id, polygon.type, points, polygon.line_width) - layerData.addPolygon(layer.id, polygon.type, points) + # We are done processing all the layers we got from the engine, now create a mesh out of the data + layerData.build() + mesh.layerData = layerData - # We are done processing all the layers we got from the engine, now create a mesh out of the data - layerData.build() - mesh.layerData = layerData - new_node.setMeshData(mesh) new_node.setParent(self._scene.getRoot()) diff --git a/plugins/LayerView/LayerView.py b/plugins/LayerView/LayerView.py index f3580039c5..17cea9988c 100644 --- a/plugins/LayerView/LayerView.py +++ b/plugins/LayerView/LayerView.py @@ -9,6 +9,10 @@ from UM.Event import Event, KeyEvent from UM.Signal import Signal from UM.Scene.Selection import Selection from UM.Math.Color import Color +from UM.Mesh.MeshData import MeshData + +from cura.ConvexHullNode import ConvexHullNode + from . import LayerViewProxy ## View used to display g-code paths. @@ -22,6 +26,9 @@ class LayerView(View): self._controller.getScene().sceneChanged.connect(self._onSceneChanged) self._max_layers = 10 self._current_layer_num = 10 + self._current_layer_mesh = None + + self._solid_layers = 5 def getCurrentLayer(self): return self._current_layer_num @@ -45,6 +52,11 @@ class LayerView(View): self._selection_material.setUniformValue("u_color", Color(35, 35, 35, 128)) for node in DepthFirstIterator(scene.getRoot()): + # We do not want to render ConvexHullNode as it conflicts with the bottom layers. + # However, it is somewhat relevant when the node is selected, so do render it then. + if type(node) is ConvexHullNode and not Selection.isSelected(node.getWatchedNode()): + continue + if not node.render(renderer): if node.getMeshData() and node.isVisible(): if Selection.isSelected(node): @@ -55,19 +67,39 @@ class LayerView(View): except AttributeError: continue - start = 0 - end = 0 + # Render all layers below a certain number as line mesh instead of vertices. + if self._current_layer_num - self._solid_layers > -1: + start = 0 + end = 0 + element_counts = layer_data.getElementCounts() + for layer, counts in element_counts.items(): + if layer + self._solid_layers > self._current_layer_num: + break + end += counts - element_counts = layer_data.getElementCounts() - for layer, counts in element_counts.items(): - end += sum(counts) - ## Hack to ensure the end is correct. Not quite sure what causes this - end += 2 * len(counts) + # This uses glDrawRangeElements internally to only draw a certain range of lines. + renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines, start = start, end = end) - if layer >= self._current_layer_num: - break + # We currently recreate the current "solid" layers every time a + if not self._current_layer_mesh: + self._current_layer_mesh = MeshData() + for i in range(self._solid_layers): + layer = self._current_layer_num - i + if layer < 0: + continue - renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines, start = start, end = end) + layer_mesh = layer_data.getLayer(layer).createMesh() + if not layer_mesh or layer_mesh.getVertices() is None: + continue + + self._current_layer_mesh.addVertices(layer_mesh.getVertices()) + + # Scale layer color by a brightness factor based on the current layer number + # This will result in a range of 0.5 - 1.0 to multiply colors by. + brightness = (2.0 - (i / self._solid_layers)) / 2.0 + self._current_layer_mesh.addColors(layer_mesh.getColors() * brightness) + + renderer.queueNode(node, mesh = self._current_layer_mesh, material = self._material) def setLayer(self, value): if self._current_layer_num != value: @@ -76,6 +108,8 @@ class LayerView(View): self._current_layer_num = 0 if self._current_layer_num > self._max_layers: self._current_layer_num = self._max_layers + + self._current_layer_mesh = None self.currentLayerNumChanged.emit() currentLayerNumChanged = Signal() @@ -96,7 +130,7 @@ class LayerView(View): except AttributeError: continue if new_max_layers < len(layer_data.getLayers()): - new_max_layers = len(layer_data.getLayers()) + new_max_layers = len(layer_data.getLayers()) - 1 if new_max_layers > 0 and new_max_layers != self._old_max_layers: self._max_layers = new_max_layers diff --git a/resources/themes/cura/styles.qml b/resources/themes/cura/styles.qml index 3ca9ea6ea2..43bbb8c400 100644 --- a/resources/themes/cura/styles.qml +++ b/resources/themes/cura/styles.qml @@ -35,39 +35,42 @@ QtObject { } } - property Component open_file_button: Component { + property Component open_file_button: Component { ButtonStyle { - background: UM.AngledCornerRectangle { + background: Item { implicitWidth: UM.Theme.sizes.button.width; implicitHeight: UM.Theme.sizes.button.height; - color: { - if(control.hovered) { - return UM.Theme.colors.button_active_hover; - } else { - return UM.Theme.colors.button_active; - } - } - Behavior on color { ColorAnimation { duration: 50; } } - cornerSize: UM.Theme.sizes.default_margin.width; Rectangle { - anchors.bottom: parent.top; - + anchors.bottom: parent.verticalCenter; width: parent.width; - height: control.hovered ? label.height : 0; - Behavior on height { NumberAnimation { duration: 75; } } + height: control.hovered ? parent.height / 2 + label.height : 0; + Behavior on height { NumberAnimation { duration: 100; } } opacity: control.hovered ? 1.0 : 0.0; - Behavior on opacity { NumberAnimation { duration: 75; } } + Behavior on opacity { NumberAnimation { duration: 100; } } Label { - id: label + id: label; anchors.horizontalCenter: parent.horizontalCenter; - text: control.text; + text: control.text.replace("&", ""); font: UM.Theme.fonts.button_tooltip; color: UM.Theme.colors.button_tooltip_text; } } + + UM.AngledCornerRectangle { + anchors.fill: parent; + color: { + if(control.hovered) { + return UM.Theme.colors.button_active_hover; + } else { + return UM.Theme.colors.button_active; + } + } + Behavior on color { ColorAnimation { duration: 50; } } + cornerSize: UM.Theme.sizes.default_margin.width; + } } label: Item { @@ -148,6 +151,49 @@ QtObject { } } + + property Component progressbar: Component{ + ProgressBarStyle { + background: UM.AngledCornerRectangle { + anchors.fill: parent + anchors.left: parent.left + implicitWidth: UM.Theme.sizes.progressbar.width + implicitHeight: UM.Theme.sizes.progressbar.height + color: "transparent" + } + progress: UM.AngledCornerRectangle { + anchors.left: parent.left + anchors.fill: parent + cornerSize: UM.Theme.sizes.progressbar_control.height + color: UM.Theme.colors.progressbar_background + Item { + anchors.fill: parent + anchors.margins: UM.Theme.sizes.progressbar_margin.width + visible: control.indeterminate + Row { + Repeater { + UM.AngledCornerRectangle { + cornerSize: UM.Theme.sizes.progressbar_control.height + color: UM.Theme.colors.progressbar_control + width: UM.Theme.sizes.progressbar_control.width + height: UM.Theme.sizes.progressbar_control.height + } + model: 1 + } + SequentialAnimation on x { + id: xAnim + property int animEndPoint: UM.Theme.sizes.progressbar.width - UM.Theme.sizes.progressbar_control.width + running: control.indeterminate + loops: Animation.Infinite + NumberAnimation { from: 0; to: xAnim.animEndPoint; duration: 2000;} + NumberAnimation { from: xAnim.animEndPoint; to: 0; duration: 2000;} + } + } + } + } + } + } + property Component sidebar_category: Component { ButtonStyle { background: UM.AngledCornerRectangle { diff --git a/resources/themes/cura/theme.json b/resources/themes/cura/theme.json index 9e5911e4e0..1e34028046 100644 --- a/resources/themes/cura/theme.json +++ b/resources/themes/cura/theme.json @@ -88,6 +88,9 @@ "setting_validation_warning": [255, 186, 15, 255], "setting_validation_ok": [255, 255, 255, 255], + "progressbar_background": [245, 245, 245, 255], + "progressbar_control": [12, 169, 227, 255], + "slider_groove": [245, 245, 245, 255], "slider_groove_border": [205, 202, 201, 255], "slider_groove_fill": [205, 202, 201, 255], @@ -135,6 +138,10 @@ "button": [4.25, 4.25], "button_icon": [2.9, 2.9], + "progressbar": [26.0, 0.5], + "progressbar_control": [8.0, 0.5], + "progressbar_padding": [0.0, 1.0], + "scrollbar": [0.5, 0.5], "slider_groove": [0.5, 0.5],