Merge branch 'STAR-322_cloud-connection' of github.com:Ultimaker/Cura into STAR-322_cloud-connection

This commit is contained in:
Daniel Schiavini 2018-12-03 16:39:24 +01:00
commit 2b8c9c17bb
191 changed files with 7411 additions and 5513 deletions

View file

@ -3,7 +3,7 @@
from PyQt5.QtCore import QObject, QUrl from PyQt5.QtCore import QObject, QUrl
from PyQt5.QtGui import QDesktopServices from PyQt5.QtGui import QDesktopServices
from typing import List, TYPE_CHECKING from typing import List, TYPE_CHECKING, cast
from UM.Event import CallFunctionEvent from UM.Event import CallFunctionEvent
from UM.FlameProfiler import pyqtSlot from UM.FlameProfiler import pyqtSlot
@ -61,8 +61,10 @@ class CuraActions(QObject):
operation = GroupedOperation() operation = GroupedOperation()
for node in Selection.getAllSelectedObjects(): for node in Selection.getAllSelectedObjects():
current_node = node current_node = node
while current_node.getParent() and current_node.getParent().callDecoration("isGroup"): parent_node = current_node.getParent()
current_node = current_node.getParent() while parent_node and parent_node.callDecoration("isGroup"):
current_node = parent_node
parent_node = current_node.getParent()
# This was formerly done with SetTransformOperation but because of # This was formerly done with SetTransformOperation but because of
# unpredictable matrix deconstruction it was possible that mirrors # unpredictable matrix deconstruction it was possible that mirrors
@ -150,13 +152,13 @@ class CuraActions(QObject):
root = cura.CuraApplication.CuraApplication.getInstance().getController().getScene().getRoot() root = cura.CuraApplication.CuraApplication.getInstance().getController().getScene().getRoot()
nodes_to_change = [] nodes_to_change = [] # type: List[SceneNode]
for node in Selection.getAllSelectedObjects(): for node in Selection.getAllSelectedObjects():
parent_node = node # Find the parent node to change instead parent_node = node # Find the parent node to change instead
while parent_node.getParent() != root: while parent_node.getParent() != root:
parent_node = parent_node.getParent() parent_node = cast(SceneNode, parent_node.getParent())
for single_node in BreadthFirstIterator(parent_node): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. for single_node in BreadthFirstIterator(parent_node): # type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
nodes_to_change.append(single_node) nodes_to_change.append(single_node)
if not nodes_to_change: if not nodes_to_change:

View file

@ -439,6 +439,7 @@ class CuraApplication(QtApplication):
"XmlMaterialProfile", #Cura crashes without this one. "XmlMaterialProfile", #Cura crashes without this one.
"Toolbox", #This contains the interface to enable/disable plug-ins, so if you disable it you can't enable it back. "Toolbox", #This contains the interface to enable/disable plug-ins, so if you disable it you can't enable it back.
"PrepareStage", #Cura is useless without this one since you can't load models. "PrepareStage", #Cura is useless without this one since you can't load models.
"PreviewStage", #This shows the list of the plugin views that are installed in Cura.
"MonitorStage", #Major part of Cura's functionality. "MonitorStage", #Major part of Cura's functionality.
"LocalFileOutputDevice", #Major part of Cura's functionality. "LocalFileOutputDevice", #Major part of Cura's functionality.
"LocalContainerProvider", #Cura is useless without any profiles or setting definitions. "LocalContainerProvider", #Cura is useless without any profiles or setting definitions.
@ -631,9 +632,7 @@ class CuraApplication(QtApplication):
self._message_box_callback(button, *self._message_box_callback_arguments) self._message_box_callback(button, *self._message_box_callback_arguments)
self._message_box_callback = None self._message_box_callback = None
self._message_box_callback_arguments = [] self._message_box_callback_arguments = []
showPrintMonitor = pyqtSignal(bool, arguments = ["show"])
def setSaveDataEnabled(self, enabled: bool) -> None: def setSaveDataEnabled(self, enabled: bool) -> None:
self._save_data_enabled = enabled self._save_data_enabled = enabled
@ -1664,7 +1663,9 @@ class CuraApplication(QtApplication):
is_non_sliceable = "." + file_extension in self._non_sliceable_extensions is_non_sliceable = "." + file_extension in self._non_sliceable_extensions
if is_non_sliceable: if is_non_sliceable:
self.callLater(lambda: self.getController().setActiveView("SimulationView")) # Need to switch first to the preview stage and then to layer view
self.callLater(lambda: (self.getController().setActiveStage("PreviewStage"),
self.getController().setActiveView("SimulationView")))
block_slicing_decorator = BlockSlicingDecorator() block_slicing_decorator = BlockSlicingDecorator()
node.addDecorator(block_slicing_decorator) node.addDecorator(block_slicing_decorator)

24
cura/CuraView.py Normal file
View file

@ -0,0 +1,24 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import pyqtProperty, QUrl
from UM.View.View import View
# Since Cura has a few pre-defined "space claims" for the locations of certain components, we've provided some structure
# to indicate this.
# MainComponent works in the same way the MainComponent of a stage.
# the stageMenuComponent returns an item that should be used somehwere in the stage menu. It's up to the active stage
# to actually do something with this.
class CuraView(View):
def __init__(self, parent = None) -> None:
super().__init__(parent)
@pyqtProperty(QUrl, constant = True)
def mainComponent(self) -> QUrl:
return self.getDisplayComponent("main")
@pyqtProperty(QUrl, constant = True)
def stageMenuComponent(self) -> QUrl:
return self.getDisplayComponent("menu")

View file

@ -21,6 +21,7 @@ class QualityProfilesDropDownMenuModel(ListModel):
AvailableRole = Qt.UserRole + 5 AvailableRole = Qt.UserRole + 5
QualityGroupRole = Qt.UserRole + 6 QualityGroupRole = Qt.UserRole + 6
QualityChangesGroupRole = Qt.UserRole + 7 QualityChangesGroupRole = Qt.UserRole + 7
IsExperimentalRole = Qt.UserRole + 8
def __init__(self, parent = None): def __init__(self, parent = None):
super().__init__(parent) super().__init__(parent)
@ -32,6 +33,7 @@ class QualityProfilesDropDownMenuModel(ListModel):
self.addRoleName(self.AvailableRole, "available") #Whether the quality profile is available in our current nozzle + material. self.addRoleName(self.AvailableRole, "available") #Whether the quality profile is available in our current nozzle + material.
self.addRoleName(self.QualityGroupRole, "quality_group") self.addRoleName(self.QualityGroupRole, "quality_group")
self.addRoleName(self.QualityChangesGroupRole, "quality_changes_group") self.addRoleName(self.QualityChangesGroupRole, "quality_changes_group")
self.addRoleName(self.IsExperimentalRole, "is_experimental")
self._application = Application.getInstance() self._application = Application.getInstance()
self._machine_manager = self._application.getMachineManager() self._machine_manager = self._application.getMachineManager()
@ -74,7 +76,8 @@ class QualityProfilesDropDownMenuModel(ListModel):
"layer_height": layer_height, "layer_height": layer_height,
"layer_height_unit": self._layer_height_unit, "layer_height_unit": self._layer_height_unit,
"available": quality_group.is_available, "available": quality_group.is_available,
"quality_group": quality_group} "quality_group": quality_group,
"is_experimental": quality_group.is_experimental}
item_list.append(item) item_list.append(item)

View file

@ -4,6 +4,9 @@
from typing import Dict, Optional, List, Set from typing import Dict, Optional, List, Set
from PyQt5.QtCore import QObject, pyqtSlot from PyQt5.QtCore import QObject, pyqtSlot
from UM.Util import parseBool
from cura.Machines.ContainerNode import ContainerNode from cura.Machines.ContainerNode import ContainerNode
@ -29,6 +32,7 @@ class QualityGroup(QObject):
self.nodes_for_extruders = {} # type: Dict[int, ContainerNode] self.nodes_for_extruders = {} # type: Dict[int, ContainerNode]
self.quality_type = quality_type self.quality_type = quality_type
self.is_available = False self.is_available = False
self.is_experimental = False
@pyqtSlot(result = str) @pyqtSlot(result = str)
def getName(self) -> str: def getName(self) -> str:
@ -51,3 +55,17 @@ class QualityGroup(QObject):
for extruder_node in self.nodes_for_extruders.values(): for extruder_node in self.nodes_for_extruders.values():
result.append(extruder_node) result.append(extruder_node)
return result return result
def setGlobalNode(self, node: "ContainerNode") -> None:
self.node_for_global = node
# Update is_experimental flag
is_experimental = parseBool(node.getMetaDataEntry("is_experimental", False))
self.is_experimental |= is_experimental
def setExtruderNode(self, position: int, node: "ContainerNode") -> None:
self.nodes_for_extruders[position] = node
# Update is_experimental flag
is_experimental = parseBool(node.getMetaDataEntry("is_experimental", False))
self.is_experimental |= is_experimental

View file

@ -235,7 +235,7 @@ class QualityManager(QObject):
for quality_type, quality_node in node.quality_type_map.items(): for quality_type, quality_node in node.quality_type_map.items():
quality_group = QualityGroup(quality_node.getMetaDataEntry("name", ""), quality_type) quality_group = QualityGroup(quality_node.getMetaDataEntry("name", ""), quality_type)
quality_group.node_for_global = quality_node quality_group.setGlobalNode(quality_node)
quality_group_dict[quality_type] = quality_group quality_group_dict[quality_type] = quality_group
break break
@ -337,7 +337,7 @@ class QualityManager(QObject):
quality_group = quality_group_dict[quality_type] quality_group = quality_group_dict[quality_type]
if position not in quality_group.nodes_for_extruders: if position not in quality_group.nodes_for_extruders:
quality_group.nodes_for_extruders[position] = quality_node quality_group.setExtruderNode(position, quality_node)
# If the machine has its own specific qualities, for extruders, it should skip the global qualities # If the machine has its own specific qualities, for extruders, it should skip the global qualities
# and use the material/variant specific qualities. # and use the material/variant specific qualities.
@ -367,7 +367,7 @@ class QualityManager(QObject):
if node and node.quality_type_map: if node and node.quality_type_map:
for quality_type, quality_node in node.quality_type_map.items(): for quality_type, quality_node in node.quality_type_map.items():
quality_group = QualityGroup(quality_node.getMetaDataEntry("name", ""), quality_type) quality_group = QualityGroup(quality_node.getMetaDataEntry("name", ""), quality_type)
quality_group.node_for_global = quality_node quality_group.setGlobalNode(quality_node)
quality_group_dict[quality_type] = quality_group quality_group_dict[quality_type] = quality_group
break break

View file

@ -107,7 +107,7 @@ class VariantManager:
break break
return variant_node return variant_node
return self._machine_to_variant_dict_map[machine_definition_id].get(variant_type, {}).get(variant_name) return self._machine_to_variant_dict_map.get(machine_definition_id, {}).get(variant_type, {}).get(variant_name)
def getVariantNodes(self, machine: "GlobalStack", variant_type: "VariantType") -> Dict[str, ContainerNode]: def getVariantNodes(self, machine: "GlobalStack", variant_type: "VariantType") -> Dict[str, ContainerNode]:
machine_definition_id = machine.definition.getId() machine_definition_id = machine.definition.getId()

View file

@ -1,4 +1,6 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional from typing import Optional

View file

@ -14,8 +14,7 @@ from UM.Logger import Logger
from UM.Qt.Duration import Duration from UM.Qt.Duration import Duration
from UM.Scene.SceneNode import SceneNode from UM.Scene.SceneNode import SceneNode
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from UM.MimeTypeDatabase import MimeTypeDatabase from UM.MimeTypeDatabase import MimeTypeDatabase, MimeTypeNotFoundError
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@ -361,7 +360,7 @@ class PrintInformation(QObject):
try: try:
mime_type = MimeTypeDatabase.getMimeTypeForFile(name) mime_type = MimeTypeDatabase.getMimeTypeForFile(name)
data = mime_type.stripExtension(name) data = mime_type.stripExtension(name)
except: except MimeTypeNotFoundError:
Logger.log("w", "Unsupported Mime Type Database file extension %s", name) Logger.log("w", "Unsupported Mime Type Database file extension %s", name)
if data is not None and check_name is not None: if data is not None and check_name is not None:
@ -395,28 +394,14 @@ class PrintInformation(QObject):
return return
active_machine_type_name = global_container_stack.definition.getName() active_machine_type_name = global_container_stack.definition.getName()
abbr_machine = "" self._abbr_machine = self._application.getMachineManager().getAbbreviatedMachineName(active_machine_type_name)
for word in re.findall(r"[\w']+", active_machine_type_name):
if word.lower() == "ultimaker":
abbr_machine += "UM"
elif word.isdigit():
abbr_machine += word
else:
stripped_word = self._stripAccents(word.upper())
# - use only the first character if the word is too long (> 3 characters)
# - use the whole word if it's not too long (<= 3 characters)
if len(stripped_word) > 3:
stripped_word = stripped_word[0]
abbr_machine += stripped_word
self._abbr_machine = abbr_machine
## Utility method that strips accents from characters (eg: â -> a) ## Utility method that strips accents from characters (eg: â -> a)
def _stripAccents(self, to_strip: str) -> str: def _stripAccents(self, to_strip: str) -> str:
return ''.join(char for char in unicodedata.normalize('NFD', to_strip) if unicodedata.category(char) != 'Mn') return ''.join(char for char in unicodedata.normalize('NFD', to_strip) if unicodedata.category(char) != 'Mn')
@pyqtSlot(result = "QVariantMap") @pyqtSlot(result = "QVariantMap")
def getFeaturePrintTimes(self): def getFeaturePrintTimes(self) -> Dict[str, Duration]:
result = {} result = {}
if self._active_build_plate not in self._print_times_per_feature: if self._active_build_plate not in self._print_times_per_feature:
self._initPrintTimesPerFeature(self._active_build_plate) self._initPrintTimesPerFeature(self._active_build_plate)

View file

@ -211,6 +211,11 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._unique_configurations.sort(key = lambda k: k.printerType) self._unique_configurations.sort(key = lambda k: k.printerType)
self.uniqueConfigurationsChanged.emit() self.uniqueConfigurationsChanged.emit()
# Returns the unique configurations of the printers within this output device
@pyqtProperty("QStringList", notify = uniqueConfigurationsChanged)
def uniquePrinterTypes(self) -> List[str]:
return list(set([configuration.printerType for configuration in self._unique_configurations]))
def _onPrintersChanged(self) -> None: def _onPrintersChanged(self) -> None:
for printer in self._printers: for printer in self._printers:
printer.configurationChanged.connect(self._updateUniqueConfigurations) printer.configurationChanged.connect(self._updateUniqueConfigurations)
@ -238,4 +243,4 @@ class PrinterOutputDevice(QObject, OutputDevice):
if not self._firmware_updater: if not self._firmware_updater:
return return
self._firmware_updater.updateFirmware(firmware_file) self._firmware_updater.updateFirmware(firmware_file)

View file

@ -1,7 +1,10 @@
# Copyright (c) 2015 Ultimaker B.V. # Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional
from UM.Application import Application from UM.Application import Application
from UM.Math.Polygon import Polygon
from UM.Qt.QtApplication import QtApplication
from UM.Scene.SceneNode import SceneNode from UM.Scene.SceneNode import SceneNode
from UM.Resources import Resources from UM.Resources import Resources
from UM.Math.Color import Color from UM.Math.Color import Color
@ -16,7 +19,7 @@ class ConvexHullNode(SceneNode):
# location an object uses on the buildplate. This area (or area's in case of one at a time printing) is # location an object uses on the buildplate. This area (or area's in case of one at a time printing) is
# then displayed as a transparent shadow. If the adhesion type is set to raft, the area is extruded # then displayed as a transparent shadow. If the adhesion type is set to raft, the area is extruded
# to represent the raft as well. # to represent the raft as well.
def __init__(self, node, hull, thickness, parent = None): def __init__(self, node: SceneNode, hull: Optional[Polygon], thickness: float, parent: Optional[SceneNode] = None) -> None:
super().__init__(parent) super().__init__(parent)
self.setCalculateBoundingBox(False) self.setCalculateBoundingBox(False)
@ -25,7 +28,11 @@ class ConvexHullNode(SceneNode):
# Color of the drawn convex hull # Color of the drawn convex hull
if not Application.getInstance().getIsHeadLess(): if not Application.getInstance().getIsHeadLess():
self._color = Color(*Application.getInstance().getTheme().getColor("convex_hull").getRgb()) theme = QtApplication.getInstance().getTheme()
if theme:
self._color = Color(*theme.getColor("convex_hull").getRgb())
else:
self._color = Color(0, 0, 0)
else: else:
self._color = Color(0, 0, 0) self._color = Color(0, 0, 0)
@ -75,7 +82,7 @@ class ConvexHullNode(SceneNode):
return True return True
def _onNodeDecoratorsChanged(self, node): def _onNodeDecoratorsChanged(self, node: SceneNode) -> None:
convex_hull_head = self._node.callDecoration("getConvexHullHead") convex_hull_head = self._node.callDecoration("getConvexHullHead")
if convex_hull_head: if convex_hull_head:
convex_hull_head_builder = MeshBuilder() convex_hull_head_builder = MeshBuilder()

View file

@ -24,8 +24,6 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
## Human-readable name of the extruder. ## Human-readable name of the extruder.
NameRole = Qt.UserRole + 2 NameRole = Qt.UserRole + 2
## Is the extruder enabled?
EnabledRole = Qt.UserRole + 9
## Colour of the material loaded in the extruder. ## Colour of the material loaded in the extruder.
ColorRole = Qt.UserRole + 3 ColorRole = Qt.UserRole + 3
@ -47,6 +45,12 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
VariantRole = Qt.UserRole + 7 VariantRole = Qt.UserRole + 7
StackRole = Qt.UserRole + 8 StackRole = Qt.UserRole + 8
MaterialBrandRole = Qt.UserRole + 9
ColorNameRole = Qt.UserRole + 10
## Is the extruder enabled?
EnabledRole = Qt.UserRole + 11
## List of colours to display if there is no material or the material has no known ## List of colours to display if there is no material or the material has no known
# colour. # colour.
defaultColors = ["#ffc924", "#86ec21", "#22eeee", "#245bff", "#9124ff", "#ff24c8"] defaultColors = ["#ffc924", "#86ec21", "#22eeee", "#245bff", "#9124ff", "#ff24c8"]
@ -67,7 +71,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
self.addRoleName(self.MaterialRole, "material") self.addRoleName(self.MaterialRole, "material")
self.addRoleName(self.VariantRole, "variant") self.addRoleName(self.VariantRole, "variant")
self.addRoleName(self.StackRole, "stack") self.addRoleName(self.StackRole, "stack")
self.addRoleName(self.MaterialBrandRole, "material_brand")
self.addRoleName(self.ColorNameRole, "color_name")
self._update_extruder_timer = QTimer() self._update_extruder_timer = QTimer()
self._update_extruder_timer.setInterval(100) self._update_extruder_timer.setInterval(100)
self._update_extruder_timer.setSingleShot(True) self._update_extruder_timer.setSingleShot(True)
@ -183,7 +188,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
default_color = self.defaultColors[position] if 0 <= position < len(self.defaultColors) else self.defaultColors[0] default_color = self.defaultColors[position] if 0 <= position < len(self.defaultColors) else self.defaultColors[0]
color = extruder.material.getMetaDataEntry("color_code", default = default_color) if extruder.material else default_color color = extruder.material.getMetaDataEntry("color_code", default = default_color) if extruder.material else default_color
material_brand = extruder.material.getMetaDataEntry("brand", default = "generic")
color_name = extruder.material.getMetaDataEntry("color_name")
# construct an item with only the relevant information # construct an item with only the relevant information
item = { item = {
"id": extruder.getId(), "id": extruder.getId(),
@ -195,6 +201,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
"material": extruder.material.getName() if extruder.material else "", "material": extruder.material.getName() if extruder.material else "",
"variant": extruder.variant.getName() if extruder.variant else "", # e.g. print core "variant": extruder.variant.getName() if extruder.variant else "", # e.g. print core
"stack": extruder, "stack": extruder,
"material_brand": material_brand,
"color_name": color_name
} }
items.append(item) items.append(item)

View file

@ -3,6 +3,8 @@
import collections import collections
import time import time
import re
import unicodedata
from typing import Any, Callable, List, Dict, TYPE_CHECKING, Optional, cast from typing import Any, Callable, List, Dict, TYPE_CHECKING, Optional, cast
from UM.ConfigurationErrorMessage import ConfigurationErrorMessage from UM.ConfigurationErrorMessage import ConfigurationErrorMessage
@ -616,6 +618,14 @@ class MachineManager(QObject):
is_supported = self._current_quality_group.is_available is_supported = self._current_quality_group.is_available
return is_supported return is_supported
@pyqtProperty(bool, notify = activeQualityGroupChanged)
def isActiveQualityExperimental(self) -> bool:
is_experimental = False
if self._global_container_stack:
if self._current_quality_group:
is_experimental = self._current_quality_group.is_experimental
return is_experimental
## Returns whether there is anything unsupported in the current set-up. ## Returns whether there is anything unsupported in the current set-up.
# #
# The current set-up signifies the global stack and all extruder stacks, # The current set-up signifies the global stack and all extruder stacks,
@ -1532,3 +1542,22 @@ class MachineManager(QObject):
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
self.updateMaterialWithVariant(None) self.updateMaterialWithVariant(None)
self._updateQualityWithMaterial() self._updateQualityWithMaterial()
## This function will translate any printer type name to an abbreviated printer type name
@pyqtSlot(str, result = str)
def getAbbreviatedMachineName(self, machine_type_name: str) -> str:
abbr_machine = ""
for word in re.findall(r"[\w']+", machine_type_name):
if word.lower() == "ultimaker":
abbr_machine += "UM"
elif word.isdigit():
abbr_machine += word
else:
stripped_word = ''.join(char for char in unicodedata.normalize('NFD', word.upper()) if unicodedata.category(char) != 'Mn')
# - use only the first character if the word is too long (> 3 characters)
# - use the whole word if it's not too long (<= 3 characters)
if len(stripped_word) > 3:
stripped_word = stripped_word[0]
abbr_machine += stripped_word
return abbr_machine

View file

@ -1,23 +1,33 @@
# Copyright (c) 2017 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import pyqtProperty, QUrl from PyQt5.QtCore import pyqtProperty, QUrl
from UM.Stage import Stage from UM.Stage import Stage
# Since Cura has a few pre-defined "space claims" for the locations of certain components, we've provided some structure
# to indicate this.
# * The StageMenuComponent is the horizontal area below the stage bar. This should be used to show stage specific
# buttons and elements. This component will be drawn over the bar & main component.
# * The MainComponent is the component that will be drawn starting from the bottom of the stageBar and fills the rest
# of the screen.
class CuraStage(Stage): class CuraStage(Stage):
def __init__(self, parent = None) -> None:
def __init__(self, parent = None):
super().__init__(parent) super().__init__(parent)
@pyqtProperty(str, constant = True) @pyqtProperty(str, constant = True)
def stageId(self): def stageId(self) -> str:
return self.getPluginId() return self.getPluginId()
@pyqtProperty(QUrl, constant = True) @pyqtProperty(QUrl, constant = True)
def mainComponent(self): def mainComponent(self) -> QUrl:
return self.getDisplayComponent("main") return self.getDisplayComponent("main")
@pyqtProperty(QUrl, constant = True) @pyqtProperty(QUrl, constant = True)
def sidebarComponent(self): def sidebarComponent(self) -> QUrl:
return self.getDisplayComponent("sidebar") return self.getDisplayComponent("sidebar")
@pyqtProperty(QUrl, constant = True)
def stageMenuComponent(self) -> QUrl:
return self.getDisplayComponent("menu")

View file

@ -72,7 +72,7 @@ class GcodeStartEndFormatter(Formatter):
# "-1" is global stack, and if the setting value exists in the global stack, use it as the fallback value. # "-1" is global stack, and if the setting value exists in the global stack, use it as the fallback value.
if key in kwargs["-1"]: if key in kwargs["-1"]:
value = kwargs["-1"] value = kwargs["-1"]
if key in kwargs[str(extruder_nr)]: if str(extruder_nr) in kwargs and key in kwargs[str(extruder_nr)]:
value = kwargs[str(extruder_nr)][key] value = kwargs[str(extruder_nr)][key]
if value == default_value_str: if value == default_value_str:

View file

@ -22,7 +22,7 @@ Cura.MachineAction
{ {
id: firmwareUpdaterMachineAction id: firmwareUpdaterMachineAction
anchors.fill: parent; anchors.fill: parent;
UM.I18nCatalog { id: catalog; name:"cura"} UM.I18nCatalog { id: catalog; name: "cura"}
spacing: UM.Theme.getSize("default_margin").height spacing: UM.Theme.getSize("default_margin").height
Label Label

View file

@ -20,7 +20,7 @@ UM.Dialog
GridLayout GridLayout
{ {
UM.I18nCatalog{id: catalog; name:"cura"} UM.I18nCatalog{id: catalog; name: "cura"}
anchors.fill: parent; anchors.fill: parent;
Layout.fillWidth: true Layout.fillWidth: true
columnSpacing: 16 * screenScaleFactor columnSpacing: 16 * screenScaleFactor

View file

@ -16,7 +16,7 @@ Button
{ {
id: modelCheckerButton id: modelCheckerButton
UM.I18nCatalog{id: catalog; name:"cura"} UM.I18nCatalog{id: catalog; name: "cura"}
visible: manager.hasWarnings visible: manager.hasWarnings
tooltip: catalog.i18nc("@info:tooltip", "Some things could be problematic in this print. Click to see tips for adjustment.") tooltip: catalog.i18nc("@info:tooltip", "Some things could be problematic in this print. Click to see tips for adjustment.")

View file

@ -1,45 +1,40 @@
// Copyright (c) 2017 Ultimaker B.V. // Copyright (c) 2017 Ultimaker B.V.
import QtQuick 2.2 import QtQuick 2.10
import QtQuick.Controls 1.1 import QtQuick.Controls 1.4
import UM 1.3 as UM import UM 1.3 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Item
{ Item
// parent could be undefined as this component is not visible at all times {
width: parent ? parent.width : 0 // We show a nice overlay on the 3D viewer when the current output device has no monitor view
height: parent ? parent.height : 0 Rectangle
{
// We show a nice overlay on the 3D viewer when the current output device has no monitor view id: viewportOverlay
Rectangle
{ color: UM.Theme.getColor("viewport_overlay")
id: viewportOverlay anchors.fill: parent
MouseArea
color: UM.Theme.getColor("viewport_overlay") {
width: parent.width anchors.fill: parent
height: parent.height acceptedButtons: Qt.AllButtons
onWheel: wheel.accepted = true
MouseArea }
{ }
anchors.fill: parent
acceptedButtons: Qt.AllButtons Loader
onWheel: wheel.accepted = true {
} id: monitorViewComponent
}
anchors.fill: parent
Loader
{ height: parent.height
id: monitorViewComponent
property real maximumWidth: parent.width
width: parent.width property real maximumHeight: parent.height
height: parent.height
sourceComponent: Cura.MachineManager.printerOutputDevices.length > 0 ? Cura.MachineManager.printerOutputDevices[0].monitorItem: null
property real maximumWidth: parent.width }
property real maximumHeight: parent.height }
sourceComponent: Cura.MachineManager.printerOutputDevices.length > 0 ? Cura.MachineManager.printerOutputDevices[0].monitorItem: null
visible: sourceComponent != null
}
}

View file

@ -0,0 +1,23 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.3
import UM 1.3 as UM
import Cura 1.1 as Cura
Item
{
signal showTooltip(Item item, point location, string text)
signal hideTooltip()
Cura.MachineSelector
{
id: machineSelection
headerCornerSide: Cura.RoundedRectangle.Direction.All
width: UM.Theme.getSize("machine_selector_widget").width
height: parent.height
anchors.centerIn: parent
}
}

View file

@ -65,15 +65,10 @@ class MonitorStage(CuraStage):
# We can only connect now, as we need to be sure that everything is loaded (plugins get created quite early) # We can only connect now, as we need to be sure that everything is loaded (plugins get created quite early)
Application.getInstance().getMachineManager().outputDevicesChanged.connect(self._onOutputDevicesChanged) Application.getInstance().getMachineManager().outputDevicesChanged.connect(self._onOutputDevicesChanged)
self._onOutputDevicesChanged() self._onOutputDevicesChanged()
self._updateMainOverlay()
self._updateSidebar()
def _updateMainOverlay(self): plugin_path = Application.getInstance().getPluginRegistry().getPluginPath(self.getPluginId())
main_component_path = os.path.join(PluginRegistry.getInstance().getPluginPath("MonitorStage"), if plugin_path is not None:
"MonitorMainView.qml") menu_component_path = os.path.join(plugin_path, "MonitorMenu.qml")
self.addDisplayComponent("main", main_component_path) main_component_path = os.path.join(plugin_path, "MonitorMain.qml")
self.addDisplayComponent("menu", menu_component_path)
def _updateSidebar(self): self.addDisplayComponent("main", main_component_path)
sidebar_component_path = os.path.join(Resources.getPath(Application.getInstance().ResourceTypes.QmlFiles),
"MonitorSidebar.qml")
self.addDisplayComponent("sidebar", sidebar_component_path)

View file

@ -7,14 +7,16 @@ from . import MonitorStage
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("cura") i18n_catalog = i18nCatalog("cura")
def getMetaData(): def getMetaData():
return { return {
"stage": { "stage": {
"name": i18n_catalog.i18nc("@item:inmenu", "Monitor"), "name": i18n_catalog.i18nc("@item:inmenu", "Monitor"),
"weight": 1 "weight": 2
} }
} }
def register(app): def register(app):
return { return {
"stage": MonitorStage.MonitorStage() "stage": MonitorStage.MonitorStage()

View file

@ -55,14 +55,14 @@ class PostProcessingPlugin(QObject, Extension):
def selectedScriptDefinitionId(self) -> Optional[str]: def selectedScriptDefinitionId(self) -> Optional[str]:
try: try:
return self._script_list[self._selected_script_index].getDefinitionId() return self._script_list[self._selected_script_index].getDefinitionId()
except: except IndexError:
return "" return ""
@pyqtProperty(str, notify=selectedIndexChanged) @pyqtProperty(str, notify=selectedIndexChanged)
def selectedScriptStackId(self) -> Optional[str]: def selectedScriptStackId(self) -> Optional[str]:
try: try:
return self._script_list[self._selected_script_index].getStackId() return self._script_list[self._selected_script_index].getStackId()
except: except IndexError:
return "" return ""
## Execute all post-processing scripts on the gcode. ## Execute all post-processing scripts on the gcode.

View file

@ -31,7 +31,7 @@ UM.Dialog
Item Item
{ {
UM.I18nCatalog{id: catalog; name:"cura"} UM.I18nCatalog{id: catalog; name: "cura"}
id: base id: base
property int columnWidth: Math.round((base.width / 2) - UM.Theme.getSize("default_margin").width) property int columnWidth: Math.round((base.width / 2) - UM.Theme.getSize("default_margin").width)
property int textMargin: Math.round(UM.Theme.getSize("default_margin").width / 2) property int textMargin: Math.round(UM.Theme.getSize("default_margin").width / 2)
@ -260,7 +260,7 @@ UM.Dialog
Rectangle Rectangle
{ {
color: UM.Theme.getColor("sidebar") color: UM.Theme.getColor("main_background")
anchors.left: activeScripts.right anchors.left: activeScripts.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.right: parent.right anchors.right: parent.right

View file

@ -0,0 +1,3 @@
A good example script is SearchAndReplace.py.
If you have any questions please ask them at:
https://github.com/Ultimaker/Cura/issues

View file

@ -1,43 +0,0 @@
# Copyright (c) 2015 Jaime van Kessel, Ultimaker B.V.
# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
from ..Script import Script
class ExampleScript(Script):
def __init__(self):
super().__init__()
def getSettingDataString(self):
return """{
"name":"Example script",
"key": "ExampleScript",
"metadata": {},
"version": 2,
"settings":
{
"test":
{
"label": "Test",
"description": "None",
"unit": "mm",
"type": "float",
"default_value": 0.5,
"minimum_value": "0",
"minimum_value_warning": "0.1",
"maximum_value_warning": "1"
},
"derp":
{
"label": "zomg",
"description": "afgasgfgasfgasf",
"unit": "mm",
"type": "float",
"default_value": 0.5,
"minimum_value": "0",
"minimum_value_warning": "0.1",
"maximum_value_warning": "1"
}
}
}"""
def execute(self, data):
return data

View file

@ -0,0 +1,140 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.3
import UM 1.3 as UM
import Cura 1.1 as Cura
import QtGraphicalEffects 1.0 // For the dropshadow
Item
{
id: prepareMenu
// This widget doesn't show tooltips by itself. Instead it emits signals so others can do something with it.
signal showTooltip(Item item, point location, string text)
signal hideTooltip()
UM.I18nCatalog
{
id: catalog
name: "cura"
}
// Item to ensure that all of the buttons are nicely centered.
Item
{
anchors.horizontalCenter: parent.horizontalCenter
width: openFileButton.width + itemRow.width + UM.Theme.getSize("default_margin").width
height: parent.height
RowLayout
{
id: itemRow
anchors.left: openFileButton.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
width: Math.round(0.9 * prepareMenu.width)
height: parent.height
spacing: 0
Cura.MachineSelector
{
id: machineSelection
z: openFileButton.z - 1 //Ensure that the tooltip of the open file button stays above the item row.
headerCornerSide: Cura.RoundedRectangle.Direction.Left
Layout.minimumWidth: UM.Theme.getSize("machine_selector_widget").width
Layout.maximumWidth: UM.Theme.getSize("machine_selector_widget").width
Layout.fillWidth: true
Layout.fillHeight: true
}
// Separator line
Rectangle
{
height: parent.height
width: UM.Theme.getSize("default_lining").width
color: UM.Theme.getColor("lining")
}
Cura.QuickConfigurationSelector
{
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredWidth: itemRow.width - machineSelection.width - printSetupSelectorItem.width - 2 * UM.Theme.getSize("default_lining").width
}
// Separator line
Rectangle
{
height: parent.height
width: UM.Theme.getSize("default_lining").width
color: UM.Theme.getColor("lining")
}
Item
{
id: printSetupSelectorItem
// This is a work around to prevent the printSetupSelector from having to be re-loaded every time
// a stage switch is done.
children: [printSetupSelector]
height: childrenRect.height
width: childrenRect.width
}
}
Button
{
id: openFileButton
height: UM.Theme.getSize("stage_menu").height
width: UM.Theme.getSize("stage_menu").height
onClicked: Cura.Actions.open.trigger()
hoverEnabled: true
contentItem: Item
{
anchors.fill: parent
UM.RecolorImage
{
id: buttonIcon
anchors.centerIn: parent
source: UM.Theme.getIcon("load")
width: UM.Theme.getSize("button_icon").width
height: UM.Theme.getSize("button_icon").height
color: UM.Theme.getColor("toolbar_button_text")
sourceSize.width: width
sourceSize.height: height
}
}
background: Rectangle
{
id: background
height: UM.Theme.getSize("stage_menu").height
width: UM.Theme.getSize("stage_menu").height
radius: UM.Theme.getSize("default_radius").width
color: openFileButton.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button")
}
DropShadow
{
id: shadow
// Don't blur the shadow
radius: 0
anchors.fill: background
source: background
verticalOffset: 2
visible: true
color: UM.Theme.getColor("action_button_shadow")
// Should always be drawn behind the background.
z: background.z - 1
}
}
}
}

View file

@ -2,13 +2,14 @@
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import os.path import os.path
from UM.Application import Application from UM.Application import Application
from UM.PluginRegistry import PluginRegistry
from UM.Resources import Resources from UM.Resources import Resources
from cura.Stages.CuraStage import CuraStage from cura.Stages.CuraStage import CuraStage
## Stage for preparing model (slicing). ## Stage for preparing model (slicing).
class PrepareStage(CuraStage): class PrepareStage(CuraStage):
def __init__(self, parent = None): def __init__(self, parent = None):
super().__init__(parent) super().__init__(parent)
Application.getInstance().engineCreatedSignal.connect(self._engineCreated) Application.getInstance().engineCreatedSignal.connect(self._engineCreated)
@ -16,4 +17,7 @@ class PrepareStage(CuraStage):
def _engineCreated(self): def _engineCreated(self):
sidebar_component_path = os.path.join(Resources.getPath(Application.getInstance().ResourceTypes.QmlFiles), sidebar_component_path = os.path.join(Resources.getPath(Application.getInstance().ResourceTypes.QmlFiles),
"PrepareSidebar.qml") "PrepareSidebar.qml")
menu_component_path = os.path.join(PluginRegistry.getInstance().getPluginPath("PrepareStage"), "PrepareMenu.qml")
self.addDisplayComponent("menu", menu_component_path)
self.addDisplayComponent("sidebar", sidebar_component_path) self.addDisplayComponent("sidebar", sidebar_component_path)

View file

@ -0,0 +1,18 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.4
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import UM 1.0 as UM
import Cura 1.0 as Cura
Loader
{
id: previewMain
source: UM.Controller.activeView != null && UM.Controller.activeView.mainComponent != null ? UM.Controller.activeView.mainComponent : ""
}

View file

@ -0,0 +1,77 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.3
import UM 1.3 as UM
import Cura 1.1 as Cura
Item
{
id: previewMenu
// This widget doesn't show tooltips by itself. Instead it emits signals so others can do something with it.
signal showTooltip(Item item, point location, string text)
signal hideTooltip()
property real itemHeight: height - 2 * UM.Theme.getSize("default_lining").width
UM.I18nCatalog
{
id: catalog
name: "cura"
}
Row
{
id: stageMenuRow
anchors.centerIn: parent
height: parent.height
Cura.ViewsSelector
{
id: viewsSelector
height: parent.height
width: UM.Theme.getSize("views_selector").width
headerCornerSide: Cura.RoundedRectangle.Direction.Left
}
// Separator line
Rectangle
{
height: parent.height
// If there is no viewPanel, we only need a single spacer, so hide this one.
visible: viewPanel.source != ""
width: visible ? UM.Theme.getSize("default_lining").width : 0
color: UM.Theme.getColor("lining")
}
Loader
{
id: viewPanel
height: parent.height
width: childrenRect.width
source: UM.Controller.activeView != null && UM.Controller.activeView.stageMenuComponent != null ? UM.Controller.activeView.stageMenuComponent : ""
}
// Separator line
Rectangle
{
height: parent.height
width: UM.Theme.getSize("default_lining").width
color: UM.Theme.getColor("lining")
}
Item
{
id: printSetupSelectorItem
// This is a work around to prevent the printSetupSelector from having to be re-loaded every time
// a stage switch is done.
children: [printSetupSelector]
height: childrenRect.height
width: childrenRect.width
}
}
}

View file

@ -0,0 +1,51 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import os.path
from UM.Qt.QtApplication import QtApplication
from cura.Stages.CuraStage import CuraStage
from typing import TYPE_CHECKING, Optional
if TYPE_CHECKING:
from UM.View.View import View
## Displays a preview of what you're about to print.
#
# The Python component of this stage just loads PreviewMain.qml for display
# when the stage is selected, and makes sure that it reverts to the previous
# view when the previous stage is activated.
class PreviewStage(CuraStage):
def __init__(self, application: QtApplication, parent = None) -> None:
super().__init__(parent)
self._application = application
self._application.engineCreatedSignal.connect(self._engineCreated)
self._previously_active_view = None # type: Optional[View]
## When selecting the stage, remember which was the previous view so that
# we can revert to that view when we go out of the stage later.
def onStageSelected(self) -> None:
self._previously_active_view = self._application.getController().getActiveView()
## Called when going to a different stage (away from the Preview Stage).
#
# When going to a different stage, the view should be reverted to what it
# was before. Normally, that just reverts it to solid view.
def onStageDeselected(self) -> None:
if self._previously_active_view is not None:
self._application.getController().setActiveView(self._previously_active_view.getPluginId())
self._previously_active_view = None
## Delayed load of the QML files.
#
# We need to make sure that the QML engine is running before we can load
# these.
def _engineCreated(self) -> None:
plugin_path = self._application.getPluginRegistry().getPluginPath(self.getPluginId())
if plugin_path is not None:
menu_component_path = os.path.join(plugin_path, "PreviewMenu.qml")
main_component_path = os.path.join(plugin_path, "PreviewMain.qml")
self.addDisplayComponent("menu", menu_component_path)
self.addDisplayComponent("main", main_component_path)

View file

@ -0,0 +1,22 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from . import PreviewStage
from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("cura")
def getMetaData():
return {
"stage": {
"name": i18n_catalog.i18nc("@item:inmenu", "Preview"),
"weight": 1
}
}
def register(app):
return {
"stage": PreviewStage.PreviewStage(app)
}

View file

@ -0,0 +1,8 @@
{
"name": "Preview Stage",
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides a preview stage in Cura.",
"api": 5,
"i18n-catalog": "cura"
}

View file

@ -13,23 +13,20 @@ Item
{ {
id: sliderRoot id: sliderRoot
// handle properties // Handle properties
property real handleSize: 10 property real handleSize: UM.Theme.getSize("slider_handle").width
property real handleRadius: handleSize / 2 property real handleRadius: handleSize / 2
property real minimumRangeHandleSize: handleSize / 2 property real minimumRangeHandleSize: handleSize / 2
property color upperHandleColor: "black" property color upperHandleColor: UM.Theme.getColor("slider_handle")
property color lowerHandleColor: "black" property color lowerHandleColor: UM.Theme.getColor("slider_handle")
property color rangeHandleColor: "black" property color rangeHandleColor: UM.Theme.getColor("slider_groove_fill")
property color handleActiveColor: "white" property color handleActiveColor: UM.Theme.getColor("slider_handle_active")
property real handleLabelWidth: width
property var activeHandle: upperHandle property var activeHandle: upperHandle
// track properties // Track properties
property real trackThickness: 4 // width of the slider track property real trackThickness: UM.Theme.getSize("slider_groove").width // width of the slider track
property real trackRadius: trackThickness / 2 property real trackRadius: UM.Theme.getSize("slider_groove_radius").width
property color trackColor: "white" property color trackColor: UM.Theme.getColor("slider_groove")
property real trackBorderWidth: 1 // width of the slider track border
property color trackBorderColor: "black"
// value properties // value properties
property real maximumValue: 100 property real maximumValue: 100
@ -80,7 +77,7 @@ Item
return Math.min(Math.max(value, sliderRoot.minimumValue), sliderRoot.maximumValue) return Math.min(Math.max(value, sliderRoot.minimumValue), sliderRoot.maximumValue)
} }
// slider track // Slider track
Rectangle Rectangle
{ {
id: track id: track
@ -90,8 +87,6 @@ Item
radius: sliderRoot.trackRadius radius: sliderRoot.trackRadius
anchors.centerIn: sliderRoot anchors.centerIn: sliderRoot
color: sliderRoot.trackColor color: sliderRoot.trackColor
border.width: sliderRoot.trackBorderWidth
border.color: sliderRoot.trackBorderColor
visible: sliderRoot.layersVisible visible: sliderRoot.layersVisible
} }
@ -106,7 +101,7 @@ Item
anchors.horizontalCenter: sliderRoot.horizontalCenter anchors.horizontalCenter: sliderRoot.horizontalCenter
visible: sliderRoot.layersVisible visible: sliderRoot.layersVisible
// set the new value when dragging // Set the new value when dragging
function onHandleDragged() function onHandleDragged()
{ {
sliderRoot.manuallyChanged = true sliderRoot.manuallyChanged = true
@ -140,9 +135,10 @@ Item
Rectangle Rectangle
{ {
width: sliderRoot.trackThickness - 2 * sliderRoot.trackBorderWidth width: sliderRoot.trackThickness
height: parent.height + sliderRoot.handleSize height: parent.height + sliderRoot.handleSize
anchors.centerIn: parent anchors.centerIn: parent
radius: sliderRoot.trackRadius
color: sliderRoot.rangeHandleColor color: sliderRoot.rangeHandleColor
} }
@ -167,9 +163,9 @@ Item
id: rangleHandleLabel id: rangleHandleLabel
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
x: parent.x - width - UM.Theme.getSize("default_margin").width x: parent.x + parent.width + UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
target: Qt.point(sliderRoot.width, y + height / 2) target: Qt.point(sliderRoot.width + width, y + height / 2)
visible: sliderRoot.activeHandle == parent visible: sliderRoot.activeHandle == parent
// custom properties // custom properties
@ -275,7 +271,7 @@ Item
id: upperHandleLabel id: upperHandleLabel
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
x: parent.x - width - UM.Theme.getSize("default_margin").width x: parent.x - parent.width - width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
target: Qt.point(sliderRoot.width, y + height / 2) target: Qt.point(sliderRoot.width, y + height / 2)
visible: sliderRoot.activeHandle == parent visible: sliderRoot.activeHandle == parent
@ -385,9 +381,9 @@ Item
id: lowerHandleLabel id: lowerHandleLabel
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
x: parent.x - width - UM.Theme.getSize("default_margin").width x: parent.x - parent.width - width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
target: Qt.point(sliderRoot.width, y + height / 2) target: Qt.point(sliderRoot.width + width, y + height / 2)
visible: sliderRoot.activeHandle == parent visible: sliderRoot.activeHandle == parent
// custom properties // custom properties

View file

@ -14,19 +14,17 @@ Item
id: sliderRoot id: sliderRoot
// handle properties // handle properties
property real handleSize: 10 property real handleSize: UM.Theme.getSize("slider_handle").width
property real handleRadius: handleSize / 2 property real handleRadius: handleSize / 2
property color handleColor: "black" property color handleColor: UM.Theme.getColor("slider_handle")
property color handleActiveColor: "white" property color handleActiveColor: UM.Theme.getColor("slider_handle_active")
property color rangeColor: "black" property color rangeColor: UM.Theme.getColor("slider_groove_fill")
property real handleLabelWidth: width property real handleLabelWidth: width
// track properties // track properties
property real trackThickness: 4 // width of the slider track property real trackThickness: UM.Theme.getSize("slider_groove").width
property real trackRadius: trackThickness / 2 property real trackRadius: UM.Theme.getSize("slider_groove_radius").width
property color trackColor: "white" property color trackColor: UM.Theme.getColor("slider_groove")
property real trackBorderWidth: 1 // width of the slider track border
property color trackBorderColor: "black"
// value properties // value properties
property real maximumValue: 100 property real maximumValue: 100
@ -68,8 +66,6 @@ Item
radius: sliderRoot.trackRadius radius: sliderRoot.trackRadius
anchors.centerIn: sliderRoot anchors.centerIn: sliderRoot
color: sliderRoot.trackColor color: sliderRoot.trackColor
border.width: sliderRoot.trackBorderWidth
border.color: sliderRoot.trackBorderColor
visible: sliderRoot.pathsVisible visible: sliderRoot.pathsVisible
} }
@ -86,9 +82,10 @@ Item
Rectangle Rectangle
{ {
height: sliderRoot.trackThickness - 2 * sliderRoot.trackBorderWidth height: sliderRoot.trackThickness
width: parent.width + sliderRoot.handleSize width: parent.width + sliderRoot.handleSize
anchors.centerIn: parent anchors.centerIn: parent
radius: sliderRoot.trackRadius
color: sliderRoot.rangeColor color: sliderRoot.rangeColor
} }
} }

View file

@ -16,6 +16,7 @@ from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Message import Message from UM.Message import Message
from UM.Platform import Platform from UM.Platform import Platform
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from UM.Qt.QtApplication import QtApplication
from UM.Resources import Resources from UM.Resources import Resources
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
@ -26,8 +27,8 @@ from UM.View.GL.OpenGL import OpenGL
from UM.View.GL.OpenGLContext import OpenGLContext from UM.View.GL.OpenGLContext import OpenGLContext
from UM.View.GL.ShaderProgram import ShaderProgram from UM.View.GL.ShaderProgram import ShaderProgram
from UM.View.View import View
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from cura.CuraView import CuraView
from cura.Scene.ConvexHullNode import ConvexHullNode from cura.Scene.ConvexHullNode import ConvexHullNode
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
@ -48,15 +49,15 @@ catalog = i18nCatalog("cura")
## View used to display g-code paths. ## View used to display g-code paths.
class SimulationView(View): class SimulationView(CuraView):
# Must match SimulationView.qml # Must match SimulationView.qml
LAYER_VIEW_TYPE_MATERIAL_TYPE = 0 LAYER_VIEW_TYPE_MATERIAL_TYPE = 0
LAYER_VIEW_TYPE_LINE_TYPE = 1 LAYER_VIEW_TYPE_LINE_TYPE = 1
LAYER_VIEW_TYPE_FEEDRATE = 2 LAYER_VIEW_TYPE_FEEDRATE = 2
LAYER_VIEW_TYPE_THICKNESS = 3 LAYER_VIEW_TYPE_THICKNESS = 3
def __init__(self) -> None: def __init__(self, parent = None) -> None:
super().__init__() super().__init__(parent)
self._max_layers = 0 self._max_layers = 0
self._current_layer_num = 0 self._current_layer_num = 0
@ -113,6 +114,16 @@ class SimulationView(View):
self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled"), self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled"),
title = catalog.i18nc("@info:title", "Simulation View")) title = catalog.i18nc("@info:title", "Simulation View"))
QtApplication.getInstance().engineCreatedSignal.connect(self._onEngineCreated)
def _onEngineCreated(self) -> None:
plugin_path = PluginRegistry.getInstance().getPluginPath(self.getPluginId())
if plugin_path:
self.addDisplayComponent("main", os.path.join(plugin_path, "SimulationViewMainComponent.qml"))
self.addDisplayComponent("menu", os.path.join(plugin_path, "SimulationViewMenuComponent.qml"))
else:
Logger.log("e", "Unable to find the path for %s", self.getPluginId())
def _evaluateCompatibilityMode(self) -> bool: def _evaluateCompatibilityMode(self) -> bool:
return OpenGLContext.isLegacyOpenGL() or bool(Application.getInstance().getPreferences().getValue("view/force_layer_view_compatibility_mode")) return OpenGLContext.isLegacyOpenGL() or bool(Application.getInstance().getPreferences().getValue("view/force_layer_view_compatibility_mode"))

View file

@ -1,808 +0,0 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.4
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import UM 1.0 as UM
import Cura 1.0 as Cura
Item
{
id: base
width:
{
if (UM.SimulationView.compatibilityMode)
{
return UM.Theme.getSize("layerview_menu_size_compatibility").width;
}
else
{
return UM.Theme.getSize("layerview_menu_size").width;
}
}
height: {
if (viewSettings.collapsed)
{
if (UM.SimulationView.compatibilityMode)
{
return UM.Theme.getSize("layerview_menu_size_compatibility_collapsed").height;
}
return UM.Theme.getSize("layerview_menu_size_collapsed").height;
}
else if (UM.SimulationView.compatibilityMode)
{
return UM.Theme.getSize("layerview_menu_size_compatibility").height;
}
else if (UM.Preferences.getValue("layerview/layer_view_type") == 0)
{
return UM.Theme.getSize("layerview_menu_size_material_color_mode").height + UM.SimulationView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height)
}
else
{
return UM.Theme.getSize("layerview_menu_size").height + UM.SimulationView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height)
}
}
Behavior on height { NumberAnimation { duration: 100 } }
property var buttonTarget:
{
if(parent != null)
{
var force_binding = parent.y; // ensure this gets reevaluated when the panel moves
return base.mapFromItem(parent.parent, parent.buttonTarget.x, parent.buttonTarget.y)
}
return Qt.point(0,0)
}
Rectangle
{
id: layerViewMenu
anchors.right: parent.right
anchors.top: parent.top
width: parent.width
height: parent.height
clip: true
z: layerSlider.z - 1
color: UM.Theme.getColor("tool_panel_background")
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
Button {
id: collapseButton
anchors.top: parent.top
anchors.topMargin: Math.round(UM.Theme.getSize("default_margin").height + (UM.Theme.getSize("layerview_row").height - UM.Theme.getSize("default_margin").height) / 2)
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
width: UM.Theme.getSize("standard_arrow").width
height: UM.Theme.getSize("standard_arrow").height
onClicked: viewSettings.collapsed = !viewSettings.collapsed
style: ButtonStyle
{
background: UM.RecolorImage
{
width: control.width
height: control.height
sourceSize.width: width
sourceSize.height: width
color: UM.Theme.getColor("setting_control_text")
source: viewSettings.collapsed ? UM.Theme.getIcon("arrow_left") : UM.Theme.getIcon("arrow_bottom")
}
label: Label{ }
}
}
ColumnLayout
{
id: viewSettings
property bool collapsed: false
property var extruder_opacities: UM.Preferences.getValue("layerview/extruder_opacities").split("|")
property bool show_travel_moves: UM.Preferences.getValue("layerview/show_travel_moves")
property bool show_helpers: UM.Preferences.getValue("layerview/show_helpers")
property bool show_skin: UM.Preferences.getValue("layerview/show_skin")
property bool show_infill: UM.Preferences.getValue("layerview/show_infill")
// if we are in compatibility mode, we only show the "line type"
property bool show_legend: UM.SimulationView.compatibilityMode ? true : UM.Preferences.getValue("layerview/layer_view_type") == 1
property bool show_gradient: UM.SimulationView.compatibilityMode ? false : UM.Preferences.getValue("layerview/layer_view_type") == 2 || UM.Preferences.getValue("layerview/layer_view_type") == 3
property bool show_feedrate_gradient: show_gradient && UM.Preferences.getValue("layerview/layer_view_type") == 2
property bool show_thickness_gradient: show_gradient && UM.Preferences.getValue("layerview/layer_view_type") == 3
property bool only_show_top_layers: UM.Preferences.getValue("view/only_show_top_layers")
property int top_layer_count: UM.Preferences.getValue("view/top_layer_count")
anchors.top: parent.top
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("layerview_row_spacing").height
Label
{
id: layerViewTypesLabel
anchors.left: parent.left
text: catalog.i18nc("@label","Color scheme")
font: UM.Theme.getFont("default");
visible: !UM.SimulationView.compatibilityMode
Layout.fillWidth: true
color: UM.Theme.getColor("setting_control_text")
}
ListModel // matches SimulationView.py
{
id: layerViewTypes
}
Component.onCompleted:
{
layerViewTypes.append({
text: catalog.i18nc("@label:listbox", "Material Color"),
type_id: 0
})
layerViewTypes.append({
text: catalog.i18nc("@label:listbox", "Line Type"),
type_id: 1
})
layerViewTypes.append({
text: catalog.i18nc("@label:listbox", "Feedrate"),
type_id: 2
})
layerViewTypes.append({
text: catalog.i18nc("@label:listbox", "Layer thickness"),
type_id: 3 // these ids match the switching in the shader
})
}
ComboBox
{
id: layerTypeCombobox
anchors.left: parent.left
Layout.fillWidth: true
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
model: layerViewTypes
visible: !UM.SimulationView.compatibilityMode
style: UM.Theme.styles.combobox
anchors.right: parent.right
onActivated:
{
UM.Preferences.setValue("layerview/layer_view_type", index);
}
Component.onCompleted:
{
currentIndex = UM.SimulationView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type");
updateLegends(currentIndex);
}
function updateLegends(type_id)
{
// update visibility of legends
viewSettings.show_legend = UM.SimulationView.compatibilityMode || (type_id == 1);
viewSettings.show_gradient = !UM.SimulationView.compatibilityMode && (type_id == 2 || type_id == 3);
viewSettings.show_feedrate_gradient = viewSettings.show_gradient && (type_id == 2);
viewSettings.show_thickness_gradient = viewSettings.show_gradient && (type_id == 3);
}
}
Label
{
id: compatibilityModeLabel
anchors.left: parent.left
text: catalog.i18nc("@label","Compatibility Mode")
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
visible: UM.SimulationView.compatibilityMode
Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
}
Item
{
height: Math.round(UM.Theme.getSize("default_margin").width / 2)
width: width
}
Connections
{
target: UM.Preferences
onPreferenceChanged:
{
layerTypeCombobox.currentIndex = UM.SimulationView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type");
layerTypeCombobox.updateLegends(layerTypeCombobox.currentIndex);
playButton.pauseSimulation();
viewSettings.extruder_opacities = UM.Preferences.getValue("layerview/extruder_opacities").split("|");
viewSettings.show_travel_moves = UM.Preferences.getValue("layerview/show_travel_moves");
viewSettings.show_helpers = UM.Preferences.getValue("layerview/show_helpers");
viewSettings.show_skin = UM.Preferences.getValue("layerview/show_skin");
viewSettings.show_infill = UM.Preferences.getValue("layerview/show_infill");
viewSettings.only_show_top_layers = UM.Preferences.getValue("view/only_show_top_layers");
viewSettings.top_layer_count = UM.Preferences.getValue("view/top_layer_count");
}
}
Repeater
{
model: Cura.ExtrudersModel{}
CheckBox
{
id: extrudersModelCheckBox
checked: viewSettings.extruder_opacities[index] > 0.5 || viewSettings.extruder_opacities[index] == undefined || viewSettings.extruder_opacities[index] == ""
onClicked:
{
viewSettings.extruder_opacities[index] = checked ? 1.0 : 0.0
UM.Preferences.setValue("layerview/extruder_opacities", viewSettings.extruder_opacities.join("|"));
}
visible: !UM.SimulationView.compatibilityMode
enabled: index + 1 <= 4
Rectangle
{
anchors.verticalCenter: parent.verticalCenter
anchors.right: extrudersModelCheckBox.right
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: model.color
radius: Math.round(width / 2)
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
visible: !viewSettings.show_legend & !viewSettings.show_gradient
}
Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
style: UM.Theme.styles.checkbox
Label
{
text: model.name
elide: Text.ElideRight
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
anchors.verticalCenter: parent.verticalCenter
anchors.left: extrudersModelCheckBox.left;
anchors.right: extrudersModelCheckBox.right;
anchors.leftMargin: UM.Theme.getSize("checkbox").width + Math.round(UM.Theme.getSize("default_margin").width/2)
anchors.rightMargin: UM.Theme.getSize("default_margin").width * 2
}
}
}
Repeater
{
model: ListModel
{
id: typesLegendModel
Component.onCompleted:
{
typesLegendModel.append({
label: catalog.i18nc("@label", "Show Travels"),
initialValue: viewSettings.show_travel_moves,
preference: "layerview/show_travel_moves",
colorId: "layerview_move_combing"
});
typesLegendModel.append({
label: catalog.i18nc("@label", "Show Helpers"),
initialValue: viewSettings.show_helpers,
preference: "layerview/show_helpers",
colorId: "layerview_support"
});
typesLegendModel.append({
label: catalog.i18nc("@label", "Show Shell"),
initialValue: viewSettings.show_skin,
preference: "layerview/show_skin",
colorId: "layerview_inset_0"
});
typesLegendModel.append({
label: catalog.i18nc("@label", "Show Infill"),
initialValue: viewSettings.show_infill,
preference: "layerview/show_infill",
colorId: "layerview_infill"
});
}
}
CheckBox
{
id: legendModelCheckBox
checked: model.initialValue
onClicked:
{
UM.Preferences.setValue(model.preference, checked);
}
Rectangle
{
anchors.verticalCenter: parent.verticalCenter
anchors.right: legendModelCheckBox.right
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: UM.Theme.getColor(model.colorId)
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
visible: viewSettings.show_legend
}
Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
style: UM.Theme.styles.checkbox
Label
{
text: label
font: UM.Theme.getFont("default")
elide: Text.ElideRight
color: UM.Theme.getColor("setting_control_text")
anchors.verticalCenter: parent.verticalCenter
anchors.left: legendModelCheckBox.left;
anchors.right: legendModelCheckBox.right;
anchors.leftMargin: UM.Theme.getSize("checkbox").width + Math.round(UM.Theme.getSize("default_margin").width/2)
anchors.rightMargin: UM.Theme.getSize("default_margin").width * 2
}
}
}
CheckBox
{
checked: viewSettings.only_show_top_layers
onClicked:
{
UM.Preferences.setValue("view/only_show_top_layers", checked ? 1.0 : 0.0);
}
text: catalog.i18nc("@label", "Only Show Top Layers")
visible: UM.SimulationView.compatibilityMode
style: UM.Theme.styles.checkbox
}
CheckBox
{
checked: viewSettings.top_layer_count == 5
onClicked:
{
UM.Preferences.setValue("view/top_layer_count", checked ? 5 : 1);
}
text: catalog.i18nc("@label", "Show 5 Detailed Layers On Top")
visible: UM.SimulationView.compatibilityMode
style: UM.Theme.styles.checkbox
}
Repeater
{
model: ListModel
{
id: typesLegendModelNoCheck
Component.onCompleted:
{
typesLegendModelNoCheck.append({
label: catalog.i18nc("@label", "Top / Bottom"),
colorId: "layerview_skin",
});
typesLegendModelNoCheck.append({
label: catalog.i18nc("@label", "Inner Wall"),
colorId: "layerview_inset_x",
});
}
}
Label
{
text: label
visible: viewSettings.show_legend
id: typesLegendModelLabel
Rectangle
{
anchors.verticalCenter: parent.verticalCenter
anchors.right: typesLegendModelLabel.right
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: UM.Theme.getColor(model.colorId)
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
visible: viewSettings.show_legend
}
Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
}
}
// Text for the minimum, maximum and units for the feedrates and layer thickness
Item
{
id: gradientLegend
visible: viewSettings.show_gradient
width: parent.width
height: UM.Theme.getSize("layerview_row").height
anchors
{
topMargin: UM.Theme.getSize("slider_layerview_margin").height
horizontalCenter: parent.horizontalCenter
}
Label
{
text: minText()
anchors.left: parent.left
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
function minText()
{
if (UM.SimulationView.layerActivity && CuraApplication.platformActivity)
{
// Feedrate selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 2)
{
return parseFloat(UM.SimulationView.getMinFeedrate()).toFixed(2)
}
// Layer thickness selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 3)
{
return parseFloat(UM.SimulationView.getMinThickness()).toFixed(2)
}
}
return catalog.i18nc("@label","min")
}
}
Label
{
text: unitsText()
anchors.horizontalCenter: parent.horizontalCenter
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
function unitsText()
{
if (UM.SimulationView.layerActivity && CuraApplication.platformActivity)
{
// Feedrate selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 2)
{
return "mm/s"
}
// Layer thickness selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 3)
{
return "mm"
}
}
return ""
}
}
Label
{
text: maxText()
anchors.right: parent.right
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
function maxText()
{
if (UM.SimulationView.layerActivity && CuraApplication.platformActivity)
{
// Feedrate selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 2)
{
return parseFloat(UM.SimulationView.getMaxFeedrate()).toFixed(2)
}
// Layer thickness selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 3)
{
return parseFloat(UM.SimulationView.getMaxThickness()).toFixed(2)
}
}
return catalog.i18nc("@label","max")
}
}
}
// Gradient colors for feedrate
Rectangle
{ // In QML 5.9 can be changed by LinearGradient
// Invert values because then the bar is rotated 90 degrees
id: feedrateGradient
visible: viewSettings.show_feedrate_gradient
anchors.left: parent.right
height: parent.width
width: Math.round(UM.Theme.getSize("layerview_row").height * 1.5)
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
transform: Rotation {origin.x: 0; origin.y: 0; angle: 90}
gradient: Gradient
{
GradientStop
{
position: 0.000
color: Qt.rgba(1, 0.5, 0, 1)
}
GradientStop
{
position: 0.625
color: Qt.rgba(0.375, 0.5, 0, 1)
}
GradientStop
{
position: 0.75
color: Qt.rgba(0.25, 1, 0, 1)
}
GradientStop
{
position: 1.0
color: Qt.rgba(0, 0, 1, 1)
}
}
}
// Gradient colors for layer thickness (similar to parula colormap)
Rectangle // In QML 5.9 can be changed by LinearGradient
{
// Invert values because then the bar is rotated 90 degrees
id: thicknessGradient
visible: viewSettings.show_thickness_gradient
anchors.left: parent.right
height: parent.width
width: Math.round(UM.Theme.getSize("layerview_row").height * 1.5)
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
transform: Rotation {origin.x: 0; origin.y: 0; angle: 90}
gradient: Gradient
{
GradientStop
{
position: 0.000
color: Qt.rgba(1, 1, 0, 1)
}
GradientStop
{
position: 0.25
color: Qt.rgba(1, 0.75, 0.25, 1)
}
GradientStop
{
position: 0.5
color: Qt.rgba(0, 0.75, 0.5, 1)
}
GradientStop
{
position: 0.75
color: Qt.rgba(0, 0.375, 0.75, 1)
}
GradientStop
{
position: 1.0
color: Qt.rgba(0, 0, 0.5, 1)
}
}
}
}
}
Item
{
id: slidersBox
width: parent.width
visible: UM.SimulationView.layerActivity && CuraApplication.platformActivity
anchors
{
top: parent.bottom
topMargin: UM.Theme.getSize("slider_layerview_margin").height
left: parent.left
}
PathSlider
{
id: pathSlider
height: UM.Theme.getSize("slider_handle").width
anchors.left: playButton.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.right: parent.right
visible: !UM.SimulationView.compatibilityMode
// custom properties
handleValue: UM.SimulationView.currentPath
maximumValue: UM.SimulationView.numPaths
handleSize: UM.Theme.getSize("slider_handle").width
trackThickness: UM.Theme.getSize("slider_groove").width
trackColor: UM.Theme.getColor("slider_groove")
trackBorderColor: UM.Theme.getColor("slider_groove_border")
handleColor: UM.Theme.getColor("slider_handle")
handleActiveColor: UM.Theme.getColor("slider_handle_active")
rangeColor: UM.Theme.getColor("slider_groove_fill")
// update values when layer data changes
Connections
{
target: UM.SimulationView
onMaxPathsChanged: pathSlider.setHandleValue(UM.SimulationView.currentPath)
onCurrentPathChanged:
{
// Only pause the simulation when the layer was changed manually, not when the simulation is running
if (pathSlider.manuallyChanged)
{
playButton.pauseSimulation()
}
pathSlider.setHandleValue(UM.SimulationView.currentPath)
}
}
// make sure the slider handlers show the correct value after switching views
Component.onCompleted:
{
pathSlider.setHandleValue(UM.SimulationView.currentPath)
}
}
LayerSlider
{
id: layerSlider
width: UM.Theme.getSize("slider_handle").width
height: UM.Theme.getSize("layerview_menu_size").height
anchors
{
top: !UM.SimulationView.compatibilityMode ? pathSlider.bottom : parent.top
topMargin: !UM.SimulationView.compatibilityMode ? UM.Theme.getSize("default_margin").height : 0
right: parent.right
rightMargin: UM.Theme.getSize("slider_layerview_margin").width
}
// custom properties
upperValue: UM.SimulationView.currentLayer
lowerValue: UM.SimulationView.minimumLayer
maximumValue: UM.SimulationView.numLayers
handleSize: UM.Theme.getSize("slider_handle").width
trackThickness: UM.Theme.getSize("slider_groove").width
trackColor: UM.Theme.getColor("slider_groove")
trackBorderColor: UM.Theme.getColor("slider_groove_border")
upperHandleColor: UM.Theme.getColor("slider_handle")
lowerHandleColor: UM.Theme.getColor("slider_handle")
rangeHandleColor: UM.Theme.getColor("slider_groove_fill")
handleActiveColor: UM.Theme.getColor("slider_handle_active")
handleLabelWidth: UM.Theme.getSize("slider_layerview_background").width
// update values when layer data changes
Connections
{
target: UM.SimulationView
onMaxLayersChanged: layerSlider.setUpperValue(UM.SimulationView.currentLayer)
onMinimumLayerChanged: layerSlider.setLowerValue(UM.SimulationView.minimumLayer)
onCurrentLayerChanged:
{
// Only pause the simulation when the layer was changed manually, not when the simulation is running
if (layerSlider.manuallyChanged)
{
playButton.pauseSimulation()
}
layerSlider.setUpperValue(UM.SimulationView.currentLayer)
}
}
// make sure the slider handlers show the correct value after switching views
Component.onCompleted:
{
layerSlider.setLowerValue(UM.SimulationView.minimumLayer)
layerSlider.setUpperValue(UM.SimulationView.currentLayer)
}
}
// Play simulation button
Button
{
id: playButton
iconSource: "./resources/simulation_resume.svg"
style: UM.Theme.styles.small_tool_button
visible: !UM.SimulationView.compatibilityMode
anchors
{
verticalCenter: pathSlider.verticalCenter
}
property var status: 0 // indicates if it's stopped (0) or playing (1)
onClicked:
{
switch(status)
{
case 0:
{
resumeSimulation()
break
}
case 1:
{
pauseSimulation()
break
}
}
}
function pauseSimulation()
{
UM.SimulationView.setSimulationRunning(false)
iconSource = "./resources/simulation_resume.svg"
simulationTimer.stop()
status = 0
layerSlider.manuallyChanged = true
pathSlider.manuallyChanged = true
}
function resumeSimulation()
{
UM.SimulationView.setSimulationRunning(true)
iconSource = "./resources/simulation_pause.svg"
simulationTimer.start()
layerSlider.manuallyChanged = false
pathSlider.manuallyChanged = false
}
}
Timer
{
id: simulationTimer
interval: 100
running: false
repeat: true
onTriggered:
{
var currentPath = UM.SimulationView.currentPath
var numPaths = UM.SimulationView.numPaths
var currentLayer = UM.SimulationView.currentLayer
var numLayers = UM.SimulationView.numLayers
// When the user plays the simulation, if the path slider is at the end of this layer, we start
// the simulation at the beginning of the current layer.
if (playButton.status == 0)
{
if (currentPath >= numPaths)
{
UM.SimulationView.setCurrentPath(0)
}
else
{
UM.SimulationView.setCurrentPath(currentPath+1)
}
}
// If the simulation is already playing and we reach the end of a layer, then it automatically
// starts at the beginning of the next layer.
else
{
if (currentPath >= numPaths)
{
// At the end of the model, the simulation stops
if (currentLayer >= numLayers)
{
playButton.pauseSimulation()
}
else
{
UM.SimulationView.setCurrentLayer(currentLayer+1)
UM.SimulationView.setCurrentPath(0)
}
}
else
{
UM.SimulationView.setCurrentPath(currentPath+1)
}
}
// The status must be set here instead of in the resumeSimulation function otherwise it won't work
// correctly, because part of the logic is in this trigger function.
playButton.status = 1
}
}
}
FontMetrics
{
id: fontMetrics
font: UM.Theme.getFont("default")
}
}

View file

@ -0,0 +1,212 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.4
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import UM 1.4 as UM
import Cura 1.0 as Cura
Item
{
property bool is_simulation_playing: false
visible: UM.SimulationView.layerActivity && CuraApplication.platformActivity
PathSlider
{
id: pathSlider
height: UM.Theme.getSize("slider_handle").width
width: UM.Theme.getSize("slider_layerview_size").height
anchors.bottom: parent.bottom
anchors.bottomMargin: UM.Theme.getSize("default_margin").height
anchors.horizontalCenter: parent.horizontalCenter
visible: !UM.SimulationView.compatibilityMode
// Custom properties
handleValue: UM.SimulationView.currentPath
maximumValue: UM.SimulationView.numPaths
// Update values when layer data changes.
Connections
{
target: UM.SimulationView
onMaxPathsChanged: pathSlider.setHandleValue(UM.SimulationView.currentPath)
onCurrentPathChanged:
{
// Only pause the simulation when the layer was changed manually, not when the simulation is running
if (pathSlider.manuallyChanged)
{
playButton.pauseSimulation()
}
pathSlider.setHandleValue(UM.SimulationView.currentPath)
}
}
// Ensure that the slider handlers show the correct value after switching views.
Component.onCompleted:
{
pathSlider.setHandleValue(UM.SimulationView.currentPath)
}
}
UM.SimpleButton
{
id: playButton
iconSource: !is_simulation_playing ? "./resources/simulation_resume.svg": "./resources/simulation_pause.svg"
width: UM.Theme.getSize("small_button").width
height: UM.Theme.getSize("small_button").height
hoverBackgroundColor: UM.Theme.getColor("small_button_hover")
hoverColor: UM.Theme.getColor("small_button_text_hover")
color: UM.Theme.getColor("small_button_text")
iconMargin: 0.5 * UM.Theme.getSize("wide_lining").width
visible: !UM.SimulationView.compatibilityMode
Connections
{
target: UM.Preferences
onPreferenceChanged:
{
playButton.pauseSimulation()
}
}
anchors
{
right: pathSlider.left
verticalCenter: pathSlider.verticalCenter
}
onClicked:
{
if(is_simulation_playing)
{
pauseSimulation()
}
else
{
resumeSimulation()
}
}
function pauseSimulation()
{
UM.SimulationView.setSimulationRunning(false)
simulationTimer.stop()
is_simulation_playing = false
layerSlider.manuallyChanged = true
pathSlider.manuallyChanged = true
}
function resumeSimulation()
{
UM.SimulationView.setSimulationRunning(true)
simulationTimer.start()
layerSlider.manuallyChanged = false
pathSlider.manuallyChanged = false
}
}
Timer
{
id: simulationTimer
interval: 100
running: false
repeat: true
onTriggered:
{
var currentPath = UM.SimulationView.currentPath
var numPaths = UM.SimulationView.numPaths
var currentLayer = UM.SimulationView.currentLayer
var numLayers = UM.SimulationView.numLayers
// When the user plays the simulation, if the path slider is at the end of this layer, we start
// the simulation at the beginning of the current layer.
if (!is_simulation_playing)
{
if (currentPath >= numPaths)
{
UM.SimulationView.setCurrentPath(0)
}
else
{
UM.SimulationView.setCurrentPath(currentPath + 1)
}
}
// If the simulation is already playing and we reach the end of a layer, then it automatically
// starts at the beginning of the next layer.
else
{
if (currentPath >= numPaths)
{
// At the end of the model, the simulation stops
if (currentLayer >= numLayers)
{
playButton.pauseSimulation()
}
else
{
UM.SimulationView.setCurrentLayer(currentLayer + 1)
UM.SimulationView.setCurrentPath(0)
}
}
else
{
UM.SimulationView.setCurrentPath(currentPath + 1)
}
}
// The status must be set here instead of in the resumeSimulation function otherwise it won't work
// correctly, because part of the logic is in this trigger function.
is_simulation_playing = true
}
}
LayerSlider
{
id: layerSlider
width: UM.Theme.getSize("slider_handle").width
height: UM.Theme.getSize("slider_layerview_size").height
anchors
{
right: parent.right
verticalCenter: parent.verticalCenter
rightMargin: UM.Theme.getSize("default_margin").width
}
// Custom properties
upperValue: UM.SimulationView.currentLayer
lowerValue: UM.SimulationView.minimumLayer
maximumValue: UM.SimulationView.numLayers
// Update values when layer data changes
Connections
{
target: UM.SimulationView
onMaxLayersChanged: layerSlider.setUpperValue(UM.SimulationView.currentLayer)
onMinimumLayerChanged: layerSlider.setLowerValue(UM.SimulationView.minimumLayer)
onCurrentLayerChanged:
{
// Only pause the simulation when the layer was changed manually, not when the simulation is running
if (layerSlider.manuallyChanged)
{
playButton.pauseSimulation()
}
layerSlider.setUpperValue(UM.SimulationView.currentLayer)
}
}
// Make sure the slider handlers show the correct value after switching views
Component.onCompleted:
{
layerSlider.setLowerValue(UM.SimulationView.minimumLayer)
layerSlider.setUpperValue(UM.SimulationView.currentLayer)
}
}
}

View file

@ -0,0 +1,530 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.4
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import QtGraphicalEffects 1.0
import UM 1.0 as UM
import Cura 1.0 as Cura
Cura.ExpandableComponent
{
id: base
width: UM.Theme.getSize("layerview_menu_size").width
iconSource: UM.Theme.getIcon("pencil")
Connections
{
target: UM.Preferences
onPreferenceChanged:
{
layerTypeCombobox.currentIndex = UM.SimulationView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type")
layerTypeCombobox.updateLegends(layerTypeCombobox.currentIndex)
viewSettings.extruder_opacities = UM.Preferences.getValue("layerview/extruder_opacities").split("|")
viewSettings.show_travel_moves = UM.Preferences.getValue("layerview/show_travel_moves")
viewSettings.show_helpers = UM.Preferences.getValue("layerview/show_helpers")
viewSettings.show_skin = UM.Preferences.getValue("layerview/show_skin")
viewSettings.show_infill = UM.Preferences.getValue("layerview/show_infill")
viewSettings.only_show_top_layers = UM.Preferences.getValue("view/only_show_top_layers")
viewSettings.top_layer_count = UM.Preferences.getValue("view/top_layer_count")
}
}
headerItem: Label
{
id: layerViewTypesLabel
text: catalog.i18nc("@label", "Color scheme")
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("setting_control_text")
height: base.height
verticalAlignment: Text.AlignVCenter
}
popupItem: Column
{
id: viewSettings
property var extruder_opacities: UM.Preferences.getValue("layerview/extruder_opacities").split("|")
property bool show_travel_moves: UM.Preferences.getValue("layerview/show_travel_moves")
property bool show_helpers: UM.Preferences.getValue("layerview/show_helpers")
property bool show_skin: UM.Preferences.getValue("layerview/show_skin")
property bool show_infill: UM.Preferences.getValue("layerview/show_infill")
// If we are in compatibility mode, we only show the "line type"
property bool show_legend: UM.SimulationView.compatibilityMode ? true : UM.Preferences.getValue("layerview/layer_view_type") == 1
property bool show_gradient: UM.SimulationView.compatibilityMode ? false : UM.Preferences.getValue("layerview/layer_view_type") == 2 || UM.Preferences.getValue("layerview/layer_view_type") == 3
property bool show_feedrate_gradient: show_gradient && UM.Preferences.getValue("layerview/layer_view_type") == 2
property bool show_thickness_gradient: show_gradient && UM.Preferences.getValue("layerview/layer_view_type") == 3
property bool only_show_top_layers: UM.Preferences.getValue("view/only_show_top_layers")
property int top_layer_count: UM.Preferences.getValue("view/top_layer_count")
width: UM.Theme.getSize("layerview_menu_size").width - 2 * UM.Theme.getSize("default_margin").width
height: implicitHeight
spacing: UM.Theme.getSize("layerview_row_spacing").height
ListModel // matches SimulationView.py
{
id: layerViewTypes
}
Component.onCompleted:
{
layerViewTypes.append({
text: catalog.i18nc("@label:listbox", "Material Color"),
type_id: 0
})
layerViewTypes.append({
text: catalog.i18nc("@label:listbox", "Line Type"),
type_id: 1
})
layerViewTypes.append({
text: catalog.i18nc("@label:listbox", "Feedrate"),
type_id: 2
})
layerViewTypes.append({
text: catalog.i18nc("@label:listbox", "Layer thickness"),
type_id: 3 // these ids match the switching in the shader
})
}
ComboBox
{
id: layerTypeCombobox
width: parent.width
model: layerViewTypes
visible: !UM.SimulationView.compatibilityMode
style: UM.Theme.styles.combobox
onActivated:
{
UM.Preferences.setValue("layerview/layer_view_type", index);
}
Component.onCompleted:
{
currentIndex = UM.SimulationView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type");
updateLegends(currentIndex);
}
function updateLegends(type_id)
{
// Update the visibility of the legends.
viewSettings.show_legend = UM.SimulationView.compatibilityMode || (type_id == 1);
viewSettings.show_gradient = !UM.SimulationView.compatibilityMode && (type_id == 2 || type_id == 3);
viewSettings.show_feedrate_gradient = viewSettings.show_gradient && (type_id == 2);
viewSettings.show_thickness_gradient = viewSettings.show_gradient && (type_id == 3);
}
}
Label
{
id: compatibilityModeLabel
text: catalog.i18nc("@label","Compatibility Mode")
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
visible: UM.SimulationView.compatibilityMode
height: UM.Theme.getSize("layerview_row").height
width: parent.width
renderType: Text.NativeRendering
}
Item // Spacer
{
height: Math.round(UM.Theme.getSize("default_margin").width / 2)
width: width
}
Repeater
{
model: Cura.ExtrudersModel{}
CheckBox
{
id: extrudersModelCheckBox
checked: viewSettings.extruder_opacities[index] > 0.5 || viewSettings.extruder_opacities[index] == undefined || viewSettings.extruder_opacities[index] == ""
height: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
width: parent.width
visible: !UM.SimulationView.compatibilityMode
enabled: index < 4
onClicked:
{
viewSettings.extruder_opacities[index] = checked ? 1.0 : 0.0
UM.Preferences.setValue("layerview/extruder_opacities", viewSettings.extruder_opacities.join("|"));
}
style: UM.Theme.styles.checkbox
Rectangle
{
anchors.verticalCenter: parent.verticalCenter
anchors.right: extrudersModelCheckBox.right
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: model.color
radius: Math.round(width / 2)
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
visible: !viewSettings.show_legend && !viewSettings.show_gradient
}
Label
{
text: model.name
elide: Text.ElideRight
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
anchors
{
verticalCenter: parent.verticalCenter
left: extrudersModelCheckBox.left
right: extrudersModelCheckBox.right
leftMargin: UM.Theme.getSize("checkbox").width + Math.round(UM.Theme.getSize("default_margin").width / 2)
rightMargin: UM.Theme.getSize("default_margin").width * 2
}
renderType: Text.NativeRendering
}
}
}
Repeater
{
model: ListModel
{
id: typesLegendModel
Component.onCompleted:
{
typesLegendModel.append({
label: catalog.i18nc("@label", "Show Travels"),
initialValue: viewSettings.show_travel_moves,
preference: "layerview/show_travel_moves",
colorId: "layerview_move_combing"
});
typesLegendModel.append({
label: catalog.i18nc("@label", "Show Helpers"),
initialValue: viewSettings.show_helpers,
preference: "layerview/show_helpers",
colorId: "layerview_support"
});
typesLegendModel.append({
label: catalog.i18nc("@label", "Show Shell"),
initialValue: viewSettings.show_skin,
preference: "layerview/show_skin",
colorId: "layerview_inset_0"
});
typesLegendModel.append({
label: catalog.i18nc("@label", "Show Infill"),
initialValue: viewSettings.show_infill,
preference: "layerview/show_infill",
colorId: "layerview_infill"
});
}
}
CheckBox
{
id: legendModelCheckBox
checked: model.initialValue
onClicked: UM.Preferences.setValue(model.preference, checked)
height: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
width: parent.width
style: UM.Theme.styles.checkbox
Rectangle
{
anchors.verticalCenter: parent.verticalCenter
anchors.right: legendModelCheckBox.right
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: UM.Theme.getColor(model.colorId)
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
visible: viewSettings.show_legend
}
Label
{
text: label
font: UM.Theme.getFont("default")
elide: Text.ElideRight
renderType: Text.NativeRendering
color: UM.Theme.getColor("setting_control_text")
anchors.verticalCenter: parent.verticalCenter
anchors.left: legendModelCheckBox.left
anchors.right: legendModelCheckBox.right
anchors.leftMargin: UM.Theme.getSize("checkbox").width + Math.round(UM.Theme.getSize("default_margin").width / 2)
anchors.rightMargin: UM.Theme.getSize("default_margin").width * 2
}
}
}
CheckBox
{
checked: viewSettings.only_show_top_layers
onClicked: UM.Preferences.setValue("view/only_show_top_layers", checked ? 1.0 : 0.0)
text: catalog.i18nc("@label", "Only Show Top Layers")
visible: UM.SimulationView.compatibilityMode
style: UM.Theme.styles.checkbox
width: parent.width
}
CheckBox
{
checked: viewSettings.top_layer_count == 5
onClicked: UM.Preferences.setValue("view/top_layer_count", checked ? 5 : 1)
text: catalog.i18nc("@label", "Show 5 Detailed Layers On Top")
width: parent.width
visible: UM.SimulationView.compatibilityMode
style: UM.Theme.styles.checkbox
}
Repeater
{
model: ListModel
{
id: typesLegendModelNoCheck
Component.onCompleted:
{
typesLegendModelNoCheck.append({
label: catalog.i18nc("@label", "Top / Bottom"),
colorId: "layerview_skin",
});
typesLegendModelNoCheck.append({
label: catalog.i18nc("@label", "Inner Wall"),
colorId: "layerview_inset_x",
});
}
}
Label
{
text: label
visible: viewSettings.show_legend
id: typesLegendModelLabel
height: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
width: parent.width
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
renderType: Text.NativeRendering
Rectangle
{
anchors.verticalCenter: parent.verticalCenter
anchors.right: typesLegendModelLabel.right
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: UM.Theme.getColor(model.colorId)
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
}
}
}
// Text for the minimum, maximum and units for the feedrates and layer thickness
Item
{
id: gradientLegend
visible: viewSettings.show_gradient
width: parent.width
height: UM.Theme.getSize("layerview_row").height
Label
{
text:
{
if (UM.SimulationView.layerActivity && CuraApplication.platformActivity)
{
// Feedrate selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 2)
{
return parseFloat(UM.SimulationView.getMinFeedrate()).toFixed(2)
}
// Layer thickness selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 3)
{
return parseFloat(UM.SimulationView.getMinThickness()).toFixed(2)
}
}
return catalog.i18nc("@label","min")
}
anchors.left: parent.left
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
renderType: Text.NativeRendering
}
Label
{
text: {
if (UM.SimulationView.layerActivity && CuraApplication.platformActivity)
{
// Feedrate selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 2)
{
return "mm/s"
}
// Layer thickness selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 3)
{
return "mm"
}
}
return ""
}
anchors.horizontalCenter: parent.horizontalCenter
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
}
Label
{
text: {
if (UM.SimulationView.layerActivity && CuraApplication.platformActivity)
{
// Feedrate selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 2)
{
return parseFloat(UM.SimulationView.getMaxFeedrate()).toFixed(2)
}
// Layer thickness selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 3)
{
return parseFloat(UM.SimulationView.getMaxThickness()).toFixed(2)
}
}
return catalog.i18nc("@label","max")
}
anchors.right: parent.right
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
}
}
// Gradient colors for feedrate
Rectangle
{
id: feedrateGradient
visible: viewSettings.show_feedrate_gradient
anchors.left: parent.left
anchors.right: parent.right
height: Math.round(UM.Theme.getSize("layerview_row").height * 1.5)
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
LinearGradient
{
anchors
{
left: parent.left
leftMargin: UM.Theme.getSize("default_lining").width
right: parent.right
rightMargin: UM.Theme.getSize("default_lining").width
top: parent.top
topMargin: UM.Theme.getSize("default_lining").width
bottom: parent.bottom
bottomMargin: UM.Theme.getSize("default_lining").width
}
start: Qt.point(0, 0)
end: Qt.point(parent.width, 0)
gradient: Gradient
{
GradientStop
{
position: 0.000
color: Qt.rgba(0, 0, 1, 1)
}
GradientStop
{
position: 0.25
color: Qt.rgba(0.25, 1, 0, 1)
}
GradientStop
{
position: 0.375
color: Qt.rgba(0.375, 0.5, 0, 1)
}
GradientStop
{
position: 1.0
color: Qt.rgba(1, 0.5, 0, 1)
}
}
}
}
// Gradient colors for layer thickness (similar to parula colormap)
Rectangle
{
id: thicknessGradient
visible: viewSettings.show_thickness_gradient
anchors.left: parent.left
anchors.right: parent.right
height: Math.round(UM.Theme.getSize("layerview_row").height * 1.5)
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
LinearGradient
{
anchors
{
left: parent.left
leftMargin: UM.Theme.getSize("default_lining").width
right: parent.right
rightMargin: UM.Theme.getSize("default_lining").width
top: parent.top
topMargin: UM.Theme.getSize("default_lining").width
bottom: parent.bottom
bottomMargin: UM.Theme.getSize("default_lining").width
}
start: Qt.point(0, 0)
end: Qt.point(parent.width, 0)
gradient: Gradient
{
GradientStop
{
position: 0.000
color: Qt.rgba(0, 0, 0.5, 1)
}
GradientStop
{
position: 0.25
color: Qt.rgba(0, 0.375, 0.75, 1)
}
GradientStop
{
position: 0.5
color: Qt.rgba(0, 0.75, 0.5, 1)
}
GradientStop
{
position: 0.75
color: Qt.rgba(1, 0.75, 0.25, 1)
}
GradientStop
{
position: 1.0
color: Qt.rgba(1, 1, 0, 1)
}
}
}
}
}
FontMetrics
{
id: fontMetrics
font: UM.Theme.getFont("default")
}
}

View file

@ -8,19 +8,21 @@ from . import SimulationViewProxy, SimulationView
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
def getMetaData(): def getMetaData():
return { return {
"view": { "view": {
"name": catalog.i18nc("@item:inlistbox", "Layer view"), "name": catalog.i18nc("@item:inlistbox", "Layer view"),
"view_panel": "SimulationView.qml", "weight": 0
"weight": 2
} }
} }
def createSimulationViewProxy(engine, script_engine): def createSimulationViewProxy(engine, script_engine):
return SimulationViewProxy.SimulationViewProxy() return SimulationViewProxy.SimulationViewProxy()
def register(app): def register(app):
simulation_view = SimulationView.SimulationView() simulation_view = SimulationView.SimulationView()
qmlRegisterSingletonType(SimulationViewProxy.SimulationViewProxy, "UM", 1, 0, "SimulationView", simulation_view.getProxy) qmlRegisterSingletonType(SimulationViewProxy.SimulationViewProxy, "UM", 1, 0, "SimulationView", simulation_view.getProxy)
return { "view": SimulationView.SimulationView()} return { "view": simulation_view}

View file

@ -10,7 +10,8 @@ def getMetaData():
return { return {
"view": { "view": {
"name": i18n_catalog.i18nc("@item:inmenu", "Solid view"), "name": i18n_catalog.i18nc("@item:inmenu", "Solid view"),
"weight": 0 "weight": 0,
"visible": False
} }
} }

View file

@ -20,11 +20,11 @@ Window
maximumWidth: minimumWidth maximumWidth: minimumWidth
minimumHeight: height minimumHeight: height
maximumHeight: minimumHeight maximumHeight: minimumHeight
color: UM.Theme.getColor("sidebar") color: UM.Theme.getColor("main_background")
UM.I18nCatalog UM.I18nCatalog
{ {
id: catalog id: catalog
name:"cura" name: "cura"
} }
Item Item
{ {

View file

@ -36,12 +36,19 @@ Item
var pg_name = "printingGuidelines" var pg_name = "printingGuidelines"
return (pg_name in packageData.links) ? packageData.links[pg_name] : undefined return (pg_name in packageData.links) ? packageData.links[pg_name] : undefined
} }
property var materialWebsiteUrl:
{
var pg_name = "website"
return (pg_name in packageData.links) ? packageData.links[pg_name] : undefined
}
anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.topMargin: UM.Theme.getSize("default_margin").height
height: visible ? childrenRect.height : 0 height: visible ? childrenRect.height : 0
visible: packageData.type == "material" && visible: packageData.type == "material" &&
(packageData.has_configs || technicalDataSheetUrl !== undefined || (packageData.has_configs || technicalDataSheetUrl !== undefined ||
safetyDataSheetUrl !== undefined || printingGuidelinesUrl !== undefined) safetyDataSheetUrl !== undefined || printingGuidelinesUrl !== undefined ||
materialWebsiteUrl !== undefined)
Item Item
{ {
@ -83,7 +90,7 @@ Item
model: packageData.supported_configs model: packageData.supported_configs
headerDelegate: Rectangle headerDelegate: Rectangle
{ {
color: UM.Theme.getColor("sidebar") color: UM.Theme.getColor("main_background")
height: UM.Theme.getSize("toolbox_chart_row").height height: UM.Theme.getSize("toolbox_chart_row").height
Label Label
{ {
@ -180,7 +187,8 @@ Item
anchors.top: combatibilityItem.bottom anchors.top: combatibilityItem.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height / 2 anchors.topMargin: UM.Theme.getSize("default_margin").height / 2
visible: base.technicalDataSheetUrl !== undefined || visible: base.technicalDataSheetUrl !== undefined ||
base.safetyDataSheetUrl !== undefined || base.printingGuidelinesUrl !== undefined base.safetyDataSheetUrl !== undefined || base.printingGuidelinesUrl !== undefined ||
base.materialWebsiteUrl !== undefined
height: visible ? contentHeight : 0 height: visible ? contentHeight : 0
text: text:
{ {
@ -208,6 +216,16 @@ Item
var pg_name = catalog.i18nc("@action:label", "Printing Guidelines") var pg_name = catalog.i18nc("@action:label", "Printing Guidelines")
result += "<a href='%1'>%2</a>".arg(base.printingGuidelinesUrl).arg(pg_name) result += "<a href='%1'>%2</a>".arg(base.printingGuidelinesUrl).arg(pg_name)
} }
if (base.materialWebsiteUrl !== undefined)
{
if (result.length > 0)
{
result += "<br/>"
}
var pg_name = catalog.i18nc("@action:label", "Website")
result += "<a href='%1'>%2</a>".arg(base.materialWebsiteUrl).arg(pg_name)
}
return result return result
} }
font: UM.Theme.getFont("very_small") font: UM.Theme.getFont("very_small")

View file

@ -37,7 +37,7 @@ Item
leftMargin: UM.Theme.getSize("wide_margin").width leftMargin: UM.Theme.getSize("wide_margin").width
topMargin: UM.Theme.getSize("wide_margin").height topMargin: UM.Theme.getSize("wide_margin").height
} }
color: white //Always a white background for image (regardless of theme). color: "white" //Always a white background for image (regardless of theme).
Image Image
{ {
anchors.fill: parent anchors.fill: parent
@ -144,10 +144,6 @@ Item
{ {
return "" return ""
} }
if (details.author_email)
{
return "<a href=\"mailto:" + details.author_email+"?Subject=Cura: " + details.name + "\">" + details.author_name + "</a>"
}
else else
{ {
return "<a href=\"" + details.website + "\">" + details.author_name + "</a>" return "<a href=\"" + details.website + "\">" + details.author_name + "</a>"

View file

@ -37,7 +37,7 @@ Item
anchors.top: packageName.bottom anchors.top: packageName.bottom
width: parent.width width: parent.width
text: model.description text: model.description
maximumLineCount: 6 maximumLineCount: 25
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")

View file

@ -19,10 +19,10 @@ Button
Rectangle Rectangle
{ {
visible: control.active visible: control.active
color: UM.Theme.getColor("sidebar_header_highlight_hover") color: UM.Theme.getColor("toolbox_header_highlight_hover")
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
width: parent.width width: parent.width
height: UM.Theme.getSize("sidebar_header_highlight").height height: UM.Theme.getSize("toolbox_header_highlight").height
} }
} }
label: Label label: Label
@ -32,15 +32,15 @@ Button
{ {
if(control.hovered) if(control.hovered)
{ {
return UM.Theme.getColor("topbar_button_text_hovered"); return UM.Theme.getColor("toolbox_header_button_text_hovered");
} }
if(control.active) if(control.active)
{ {
return UM.Theme.getColor("topbar_button_text_active"); return UM.Theme.getColor("toolbox_header_button_text_active");
} }
else else
{ {
return UM.Theme.getColor("topbar_button_text_inactive"); return UM.Theme.getColor("toolbox_header_button_text_inactive");
} }
} }
font: control.enabled ? (control.active ? UM.Theme.getFont("medium_bold") : UM.Theme.getFont("medium")) : UM.Theme.getFont("default_italic") font: control.enabled ? (control.active ? UM.Theme.getFont("medium_bold") : UM.Theme.getFont("medium")) : UM.Theme.getFont("default_italic")

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,014 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View file

@ -9,10 +9,10 @@ import Cura 1.0 as Cura
Rectangle { Rectangle {
property var iconSource: null; property var iconSource: null;
color: clickArea.containsMouse ? UM.Theme.getColor("primary_hover") : UM.Theme.getColor("primary"); // "Cura Blue" color: "#0a0850" // TODO: Theme!
height: width; height: width;
radius: Math.round(0.5 * width); radius: Math.round(0.5 * width);
width: 36 * screenScaleFactor; width: 24 * screenScaleFactor;
UM.RecolorImage { UM.RecolorImage {
id: icon; id: icon;

View file

@ -13,7 +13,7 @@ Component {
property var shadowRadius: UM.Theme.getSize("monitor_shadow_radius").width; property var shadowRadius: UM.Theme.getSize("monitor_shadow_radius").width;
property var cornerRadius: UM.Theme.getSize("monitor_corner_radius").width; property var cornerRadius: UM.Theme.getSize("monitor_corner_radius").width;
anchors.fill: parent; anchors.fill: parent;
color: UM.Theme.getColor("sidebar"); color: UM.Theme.getColor("main_background");
visible: OutputDevice != null; visible: OutputDevice != null;
UM.I18nCatalog { UM.I18nCatalog {

View file

@ -10,14 +10,13 @@ import QtGraphicalEffects 1.0
Component Component
{ {
Rectangle Item
{ {
id: monitorFrame id: monitorFrame
property var emphasisColor: UM.Theme.getColor("setting_control_border_highlight") property var emphasisColor: UM.Theme.getColor("setting_control_border_highlight")
property var cornerRadius: UM.Theme.getSize("monitor_corner_radius").width property var cornerRadius: UM.Theme.getSize("monitor_corner_radius").width
color: "transparent"
height: maximumHeight height: maximumHeight
onVisibleChanged: onVisibleChanged:
{ {
@ -48,13 +47,45 @@ Component
} }
} }
ScrollView
{
id: printers
anchors
{
left: queue.left
right: queue.right
top: parent.top
topMargin: 48 * screenScaleFactor // TODO: Theme!
}
height: 264 * screenScaleFactor // TODO: Theme!
Row
{
spacing: 60 * screenScaleFactor // TODO: Theme!
Repeater
{
model: OutputDevice.printers
MonitorPrinterCard
{
printer: modelData
}
}
}
}
Item Item
{ {
id: queue id: queue
width: Math.min(834 * screenScaleFactor, maximumWidth)
anchors.fill: parent anchors {
anchors.top: parent.top bottom: parent.bottom
anchors.topMargin: 400 * screenScaleFactor // TODO: Insert carousel here horizontalCenter: parent.horizontalCenter
top: printers.bottom
topMargin: 48 * screenScaleFactor // TODO: Theme!
}
Label Label
{ {
@ -104,7 +135,6 @@ Component
text: catalog.i18nc("@label link to connect manager", "Manage queue in Cura Connect") text: catalog.i18nc("@label link to connect manager", "Manage queue in Cura Connect")
} }
} }
MouseArea MouseArea
{ {
@ -187,7 +217,7 @@ Component
} }
style: UM.Theme.styles.scrollview style: UM.Theme.styles.scrollview
visible: OutputDevice.receivedPrintJobs visible: OutputDevice.receivedPrintJobs
width: Math.min(834 * screenScaleFactor, maximumWidth) width: parent.width
ListView ListView
{ {
@ -214,5 +244,4 @@ Component
visible: OutputDevice.activeCameraUrl != "" visible: OutputDevice.activeCameraUrl != ""
} }
} }
} }

View file

@ -57,7 +57,7 @@ Cura.MachineAction
spacing: UM.Theme.getSize("default_margin").height spacing: UM.Theme.getSize("default_margin").height
SystemPalette { id: palette } SystemPalette { id: palette }
UM.I18nCatalog { id: catalog; name:"cura" } UM.I18nCatalog { id: catalog; name: "cura" }
Label Label
{ {
id: pageTitle id: pageTitle

View file

@ -0,0 +1,137 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.3
import QtQuick.Controls.Styles 1.3
import QtQuick.Controls 1.4
import UM 1.3 as UM
/**
* NOTE: For most labels, a fixed height with vertical alignment is used to make
* layouts more deterministic (like the fixed-size textboxes used in original
* mock-ups). This is also a stand-in for CSS's 'line-height' property. Denoted
* with '// FIXED-LINE-HEIGHT:'.
*/
Item
{
id: base
property var printJob: null
property var progress:
{
if (!printJob)
{
return 0
}
var result = printJob.timeElapsed / printJob.timeTotal
if (result > 1.0)
{
result = 1.0
}
return result
}
property var remainingTime:
{
if (!printJob) {
return 0
}
/* Sometimes total minus elapsed is less than 0. Use Math.max() to prevent remaining
time from ever being less than 0. Negative durations cause strange behavior such
as displaying "-1h -1m". */
return Math.max(printer.activePrintJob.timeTotal - printer.activePrintJob.timeElapsed, 0)
}
property var progressText:
{
if (!printJob)
{
return "";
}
switch (printJob.state)
{
case "wait_cleanup":
if (printJob.timeTotal > printJob.timeElapsed)
{
return catalog.i18nc("@label:status", "Aborted")
}
return catalog.i18nc("@label:status", "Finished")
case "pre_print":
case "sent_to_printer":
return catalog.i18nc("@label:status", "Preparing")
case "aborted":
return catalog.i18nc("@label:status", "Aborted")
case "wait_user_action":
return catalog.i18nc("@label:status", "Aborted")
case "pausing":
return catalog.i18nc("@label:status", "Pausing")
case "paused":
return OutputDevice.formatDuration( remainingTime )
case "resuming":
return catalog.i18nc("@label:status", "Resuming")
case "queued":
return catalog.i18nc("@label:status", "Action required")
default:
return OutputDevice.formatDuration( remainingTime )
}
}
width: childrenRect.width
height: 18 * screenScaleFactor // TODO: Theme!
ProgressBar
{
id: progressBar
anchors
{
verticalCenter: parent.verticalCenter
}
value: progress;
style: ProgressBarStyle
{
background: Rectangle
{
color: "#e4e4f2" // TODO: Theme!
implicitHeight: visible ? 8 * screenScaleFactor : 0 // TODO: Theme!
implicitWidth: 180 * screenScaleFactor // TODO: Theme!
radius: 4 * screenScaleFactor // TODO: Theme!
}
progress: Rectangle
{
id: progressItem;
color:
{
if (printJob)
{
var state = printJob.state
var inactiveStates = [
"pausing",
"paused",
"resuming",
"wait_cleanup"
]
if (inactiveStates.indexOf(state) > -1 && remainingTime > 0)
{
return UM.Theme.getColor("monitor_progress_fill_inactive")
}
}
return "#0a0850" // TODO: Theme!
}
radius: 4 * screenScaleFactor // TODO: Theme!
}
}
}
Label
{
id: progressLabel
anchors
{
left: progressBar.right
leftMargin: 18 * screenScaleFactor // TODO: Theme!
}
text: progressText
color: "#374355" // TODO: Theme!
width: contentWidth
font: UM.Theme.getFont("medium") // 14pt, regular
// FIXED-LINE-HEIGHT:
height: 18 * screenScaleFactor // TODO: Theme!
verticalAlignment: Text.AlignVCenter
}
}

View file

@ -0,0 +1,242 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.3
import QtQuick.Controls 2.0
import UM 1.3 as UM
/**
* A Printer Card is has two main components: the printer portion and the print
* job portion, the latter being paired in the UI when a print job is paired
* a printer in-cluster.
*
* NOTE: For most labels, a fixed height with vertical alignment is used to make
* layouts more deterministic (like the fixed-size textboxes used in original
* mock-ups). This is also a stand-in for CSS's 'line-height' property. Denoted
* with '// FIXED-LINE-HEIGHT:'.
*/
Item
{
id: base
// The printer which all printer data is derived from
property var printer: null
property var borderSize: 1 * screenScaleFactor // TODO: Theme, and remove from here
width: 834 * screenScaleFactor // TODO: Theme!
height: 216 * screenScaleFactor // TODO: Theme!
// Printer portion
Rectangle
{
id: printerInfo
border
{
color: "#EAEAEC" // TODO: Theme!
width: borderSize // TODO: Remove once themed
}
color: "white" // TODO: Theme!
width: parent.width
height: 144 * screenScaleFactor // TODO: Theme!
Row
{
anchors
{
left: parent.left
leftMargin: 36 * screenScaleFactor // TODO: Theme!
verticalCenter: parent.verticalCenter
}
spacing: 18 * screenScaleFactor // TODO: Theme!
Image
{
id: printerImage
width: 108 * screenScaleFactor // TODO: Theme!
height: 108 * screenScaleFactor // TODO: Theme!
fillMode: Image.PreserveAspectFit
source: "../png/" + printer.type + ".png"
mipmap: true
}
Item
{
anchors
{
verticalCenter: parent.verticalCenter
}
width: 216 * screenScaleFactor // TODO: Theme!
height: printerNameLabel.height + printerFamilyPill.height + 6 * screenScaleFactor // TODO: Theme!
Label
{
id: printerNameLabel
text: printer && printer.name ? printer.name : ""
color: "#414054" // TODO: Theme!
elide: Text.ElideRight
font: UM.Theme.getFont("large") // 16pt, bold
width: parent.width
// FIXED-LINE-HEIGHT:
height: 18 * screenScaleFactor // TODO: Theme!
verticalAlignment: Text.AlignVCenter
}
MonitorPrinterPill
{
id: printerFamilyPill
anchors
{
top: printerNameLabel.bottom
topMargin: 6 * screenScaleFactor // TODO: Theme!
left: printerNameLabel.left
}
text: printer.type
}
}
MonitorPrinterConfiguration
{
id: printerConfiguration
anchors.verticalCenter: parent.verticalCenter
buildplate: "Glass"
configurations:
[
base.printer.printerConfiguration.extruderConfigurations[0],
base.printer.printerConfiguration.extruderConfigurations[1]
]
height: 72 * screenScaleFactor // TODO: Theme!
}
}
PrintJobContextMenu
{
id: contextButton
anchors
{
right: parent.right
rightMargin: 12 * screenScaleFactor // TODO: Theme!
top: parent.top
topMargin: 12 * screenScaleFactor // TODO: Theme!
}
printJob: printer.activePrintJob
width: 36 * screenScaleFactor // TODO: Theme!
height: 36 * screenScaleFactor // TODO: Theme!
}
CameraButton
{
id: cameraButton;
anchors
{
right: parent.right
rightMargin: 20 * screenScaleFactor // TODO: Theme!
bottom: parent.bottom
bottomMargin: 20 * screenScaleFactor // TODO: Theme!
}
iconSource: "../svg/icons/camera.svg"
}
}
// Print job portion
Rectangle
{
id: printJobInfo
anchors
{
top: printerInfo.bottom
topMargin: -borderSize * screenScaleFactor // TODO: Theme!
}
border
{
color: "#EAEAEC" // TODO: Theme!
width: borderSize // TODO: Remove once themed
}
color: "white" // TODO: Theme!
height: 84 * screenScaleFactor + borderSize // TODO: Remove once themed
width: parent.width
Row
{
anchors
{
fill: parent
topMargin: 12 * screenScaleFactor + borderSize // TODO: Theme!
bottomMargin: 12 * screenScaleFactor // TODO: Theme!
leftMargin: 36 * screenScaleFactor // TODO: Theme!
}
height: childrenRect.height
spacing: 18 * screenScaleFactor // TODO: Theme!
Item
{
anchors
{
verticalCenter: parent.verticalCenter
}
width: printerImage.width
height: 60 * screenScaleFactor // TODO: Theme!
MonitorPrintJobPreview
{
anchors.centerIn: parent
printJob: base.printer.activePrintJob
size: parent.height
}
}
Item
{
anchors
{
verticalCenter: parent.verticalCenter
}
width: 216 * screenScaleFactor // TODO: Theme!
height: printerNameLabel.height + printerFamilyPill.height + 6 * screenScaleFactor // TODO: Theme!
Label
{
id: printerJobNameLabel
text: base.printer.activePrintJob ? base.printer.activePrintJob.name : "Untitled" // TODO: I18N
color: "#414054" // TODO: Theme!
elide: Text.ElideRight
font: UM.Theme.getFont("large") // 16pt, bold
width: parent.width
// FIXED-LINE-HEIGHT:
height: 18 * screenScaleFactor // TODO: Theme!
verticalAlignment: Text.AlignVCenter
}
Label
{
id: printerJobOwnerLabel
anchors
{
top: printerJobNameLabel.bottom
topMargin: 6 * screenScaleFactor // TODO: Theme!
left: printerJobNameLabel.left
}
text: printer.activePrintJob ? printer.activePrintJob.owner : "Anonymous" // TODO: I18N
color: "#53657d" // TODO: Theme!
elide: Text.ElideRight
font: UM.Theme.getFont("very_small") // 12pt, regular
width: parent.width
// FIXED-LINE-HEIGHT:
height: 18 * screenScaleFactor // TODO: Theme!
verticalAlignment: Text.AlignVCenter
}
}
MonitorPrintJobProgressBar
{
anchors
{
verticalCenter: parent.verticalCenter
}
printJob: printer.activePrintJob
}
}
}
}

View file

@ -25,7 +25,7 @@ Item {
} }
contentItem: Label { contentItem: Label {
color: UM.Theme.getColor("monitor_context_menu_dots"); color: UM.Theme.getColor("monitor_context_menu_dots");
font.pixelSize: 25 * screenScaleFactor; font.pixelSize: 32 * screenScaleFactor;
horizontalAlignment: Text.AlignHCenter; horizontalAlignment: Text.AlignHCenter;
text: button.text; text: button.text;
verticalAlignment: Text.AlignVCenter; verticalAlignment: Text.AlignVCenter;
@ -41,7 +41,7 @@ Item {
var states = ["queued", "sent_to_printer", "pre_print", "printing", "pausing", "paused", "resuming"]; var states = ["queued", "sent_to_printer", "pre_print", "printing", "pausing", "paused", "resuming"];
return states.indexOf(printJob.state) !== -1; return states.indexOf(printJob.state) !== -1;
} }
width: 35 * screenScaleFactor; // TODO: Theme! width: 36 * screenScaleFactor; // TODO: Theme!
} }
Popup { Popup {

View file

@ -0,0 +1,5 @@
<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M4.298828,0.998047 L7.7,0.998047 L8.7,3 L12,3 L12,10 L0,10 L0,3 L3.3,3 L4.298828,0.998047 Z M6,4 C4.625211,4 3.5,5.1252 3.5,6.5 C3.5,7.8748 4.625211,9 6,9 C7.37479,9 8.5,7.8748 8.5,6.5 C8.5,5.1252 7.37479,4 6,4 Z M6,5 C6.83435,5 7.5,5.6657 7.5,6.5 C7.5,7.3343 6.83435,8 6,8 C5.165651,8 4.5,7.3343 4.5,6.5 C4.5,5.6657 5.165651,5 6,5 Z" id="Combined-Shape" fill="#0A0850" fill-rule="nonzero"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 658 B

View file

@ -65,7 +65,6 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
self._received_print_jobs = False # type: bool self._received_print_jobs = False # type: bool
self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/ClusterMonitorItem.qml") self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/ClusterMonitorItem.qml")
self._control_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/ClusterControlItem.qml")
# See comments about this hack with the clusterPrintersChanged signal # See comments about this hack with the clusterPrintersChanged signal
self.printersChanged.connect(self.clusterPrintersChanged) self.printersChanged.connect(self.clusterPrintersChanged)

View file

@ -344,7 +344,6 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
# Request more data if info is not complete # Request more data if info is not complete
if not info.address: if not info.address:
Logger.log("d", "Trying to get address of %s", name)
info = zero_conf.get_service_info(service_type, name) info = zero_conf.get_service_info(service_type, name)
if info: if info:

View file

@ -3,6 +3,7 @@
from UM.Job import Job from UM.Job import Job
from UM.Logger import Logger from UM.Logger import Logger
from plugins.USBPrinting.avr_isp import ispBase
from .avr_isp.stk500v2 import Stk500v2 from .avr_isp.stk500v2 import Stk500v2
@ -14,12 +15,12 @@ from serial import Serial, SerialException
# It tries a pre-set list of baud rates. All these baud rates are validated by requesting the temperature a few times # It tries a pre-set list of baud rates. All these baud rates are validated by requesting the temperature a few times
# and checking if the results make sense. If getResult() is not None, it was able to find a correct baud rate. # and checking if the results make sense. If getResult() is not None, it was able to find a correct baud rate.
class AutoDetectBaudJob(Job): class AutoDetectBaudJob(Job):
def __init__(self, serial_port): def __init__(self, serial_port: int) -> None:
super().__init__() super().__init__()
self._serial_port = serial_port self._serial_port = serial_port
self._all_baud_rates = [115200, 250000, 230400, 57600, 38400, 19200, 9600] self._all_baud_rates = [115200, 250000, 230400, 57600, 38400, 19200, 9600]
def run(self): def run(self) -> None:
Logger.log("d", "Auto detect baud rate started.") Logger.log("d", "Auto detect baud rate started.")
wait_response_timeouts = [3, 15, 30] wait_response_timeouts = [3, 15, 30]
wait_bootloader_times = [1.5, 5, 15] wait_bootloader_times = [1.5, 5, 15]
@ -32,7 +33,7 @@ class AutoDetectBaudJob(Job):
try: try:
programmer.connect(self._serial_port) programmer.connect(self._serial_port)
serial = programmer.leaveISP() serial = programmer.leaveISP()
except: except ispBase.IspError:
programmer.close() programmer.close()
for retry in range(tries): for retry in range(tries):
@ -58,7 +59,7 @@ class AutoDetectBaudJob(Job):
# We already have a serial connection, just change the baud rate. # We already have a serial connection, just change the baud rate.
try: try:
serial.baudrate = baud_rate serial.baudrate = baud_rate
except: except ValueError:
continue continue
sleep(wait_bootloader) # Ensure that we are not talking to the boot loader. 1.5 seconds seems to be the magic number sleep(wait_bootloader) # Ensure that we are not talking to the boot loader. 1.5 seconds seems to be the magic number
successful_responses = 0 successful_responses = 0
@ -81,5 +82,5 @@ class AutoDetectBaudJob(Job):
return return
serial.write(b"M105\n") serial.write(b"M105\n")
sleep(15) # Give the printer some time to init and try again. sleep(15) # Give the printer some time to init and try again.
self.setResult(None) # Unable to detect the correct baudrate. self.setResult(None) # Unable to detect the correct baudrate.

View file

@ -0,0 +1,46 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
import UM 1.2 as UM
import Cura 1.0 as Cura
Component
{
Item
{
Rectangle
{
anchors.right: parent.right
width: parent.width * 0.3
anchors.top: parent.top
anchors.bottom: parent.bottom
Cura.PrintMonitor
{
anchors.fill: parent
}
Rectangle
{
id: footerSeparator
width: parent.width
height: UM.Theme.getSize("wide_lining").height
color: UM.Theme.getColor("wide_lining")
anchors.bottom: monitorButton.top
anchors.bottomMargin: UM.Theme.getSize("thick_margin").height
}
// MonitorButton is actually the bottom footer panel.
Cura.MonitorButton
{
id: monitorButton
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
}
}
}
}

View file

@ -1,5 +1,6 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import os
from UM.Logger import Logger from UM.Logger import Logger
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
@ -64,7 +65,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._accepts_commands = True self._accepts_commands = True
self._paused = False self._paused = False
self._printer_busy = False # when printer is preheating and waiting (M190/M109), or when waiting for action on the printer self._printer_busy = False # When printer is preheating and waiting (M190/M109), or when waiting for action on the printer
self.setConnectionText(catalog.i18nc("@info:status", "Connected via USB")) self.setConnectionText(catalog.i18nc("@info:status", "Connected via USB"))
@ -77,6 +78,8 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._firmware_name_requested = False self._firmware_name_requested = False
self._firmware_updater = AvrFirmwareUpdater(self) self._firmware_updater = AvrFirmwareUpdater(self)
self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "MonitorItem.qml")
CuraApplication.getInstance().getOnExitCallbackManager().addCallback(self._checkActivePrintingUponAppExit) CuraApplication.getInstance().getOnExitCallbackManager().addCallback(self._checkActivePrintingUponAppExit)
# This is a callback function that checks if there is any printing in progress via USB when the application tries # This is a callback function that checks if there is any printing in progress via USB when the application tries

View file

@ -19,7 +19,7 @@ Cura.MachineAction
property bool heatupBedStarted: false property bool heatupBedStarted: false
property bool printerConnected: Cura.MachineManager.printerConnected property bool printerConnected: Cura.MachineManager.printerConnected
UM.I18nCatalog { id: catalog; name:"cura"} UM.I18nCatalog { id: catalog; name: "cura"}
Label Label
{ {
id: pageTitle id: pageTitle

View file

@ -36,7 +36,7 @@ UM.Dialog
width: parent.width width: parent.width
anchors.bottomMargin: UM.Theme.getSize("default_margin").height anchors.bottomMargin: UM.Theme.getSize("default_margin").height
UM.I18nCatalog { id: catalog; name:"cura" } UM.I18nCatalog { id: catalog; name: "cura" }
Button Button
{ {

View file

@ -356,6 +356,23 @@
} }
} }
}, },
"PreviewStage": {
"package_info": {
"package_id": "PreviewStage",
"package_type": "plugin",
"display_name": "Preview Stage",
"description": "Provides a preview stage in Cura.",
"package_version": "1.0.0",
"sdk_version": 5,
"website": "https://ultimaker.com",
"author": {
"author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
}
}
},
"RemovableDriveOutputDevice": { "RemovableDriveOutputDevice": {
"package_info": { "package_info": {
"package_id": "RemovableDriveOutputDevice", "package_id": "RemovableDriveOutputDevice",

View file

@ -1,11 +1,11 @@
{ {
"name": "Cocoon Create ModelMaker & Wanhao Duplicator i3 Mini", "name": "Cocoon Create ModelMaker",
"version": 2, "version": 2,
"inherits": "fdmprinter", "inherits": "fdmprinter",
"metadata": { "metadata": {
"visible": true, "visible": true,
"author": "Samuel Pinches", "author": "Samuel Pinches",
"manufacturer": "Cocoon Create / Wanhao", "manufacturer": "Cocoon Create",
"file_formats": "text/x-gcode", "file_formats": "text/x-gcode",
"preferred_quality_type": "fine", "preferred_quality_type": "fine",
"machine_extruder_trains": "machine_extruder_trains":
@ -15,7 +15,7 @@
}, },
"overrides": { "overrides": {
"machine_name": { "machine_name": {
"default_value": "Cocoon Create ModelMaker & Wanhao Duplicator i3 Mini" "default_value": "Cocoon Create ModelMaker"
}, },
"machine_start_gcode": { "machine_start_gcode": {
"default_value": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 ;home all axis\nG92 E0 ;zero the extruded length\nG1 Z1 F1000 ;move up slightly\nG1 X60.0 Z0 E9.0 F1000.0;intro line\nG1 X100.0 E21.5 F1000.0 ;continue line\nG92 E0 ;zero the extruded length again\n; -- end of START GCODE --" "default_value": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 ;home all axis\nG92 E0 ;zero the extruded length\nG1 Z1 F1000 ;move up slightly\nG1 X60.0 Z0 E9.0 F1000.0;intro line\nG1 X100.0 E21.5 F1000.0 ;continue line\nG92 E0 ;zero the extruded length again\n; -- end of START GCODE --"
@ -51,7 +51,7 @@
"default_value": 220 "default_value": 220
}, },
"layer_height": { "layer_height": {
"default_value": 0.15 "default_value": 0.10
}, },
"layer_height_0": { "layer_height_0": {
"default_value": 0.2 "default_value": 0.2

View file

@ -1,170 +0,0 @@
// Copyright (c) 2015 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.1
import UM 1.1 as UM
UM.Dialog
{
id: base
//: About dialog title
title: catalog.i18nc("@title:window","About Cura")
minimumWidth: 500 * screenScaleFactor
minimumHeight: 650 * screenScaleFactor
width: minimumWidth
height: minimumHeight
Rectangle
{
width: parent.width + 2 * margin // margin from Dialog.qml
height: version.y + version.height + margin
anchors.top: parent.top
anchors.topMargin: - margin
anchors.horizontalCenter: parent.horizontalCenter
color: UM.Theme.getColor("viewport_background")
}
Image
{
id: logo
width: (base.minimumWidth * 0.85) | 0
height: (width * (1/4.25)) | 0
source: UM.Theme.getImage("logo")
sourceSize.width: width
sourceSize.height: height
anchors.top: parent.top
anchors.topMargin: ((base.minimumWidth - width) / 2) | 0
anchors.horizontalCenter: parent.horizontalCenter
UM.I18nCatalog{id: catalog; name:"cura"}
}
Label
{
id: version
text: catalog.i18nc("@label","version: %1").arg(UM.Application.version)
font: UM.Theme.getFont("large")
color: UM.Theme.getColor("text")
anchors.right : logo.right
anchors.top: logo.bottom
anchors.topMargin: (UM.Theme.getSize("default_margin").height / 2) | 0
}
Label
{
id: description
width: parent.width
//: About dialog application description
text: catalog.i18nc("@label","End-to-end solution for fused filament 3D printing.")
font: UM.Theme.getFont("system")
wrapMode: Text.WordWrap
anchors.top: version.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
}
Label
{
id: creditsNotes
width: parent.width
//: About dialog application author note
text: catalog.i18nc("@info:credit","Cura is developed by Ultimaker B.V. in cooperation with the community.\nCura proudly uses the following open source projects:")
font: UM.Theme.getFont("system")
wrapMode: Text.WordWrap
anchors.top: description.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
}
ScrollView
{
id: credits
anchors.top: creditsNotes.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width
height: base.height - y - (2 * UM.Theme.getSize("default_margin").height + closeButton.height)
ListView
{
id: projectsList
width: parent.width
delegate: Row
{
Label
{
text: "<a href='%1' title='%2'>%2</a>".arg(model.url).arg(model.name)
width: (projectsList.width * 0.25) | 0
elide: Text.ElideRight
onLinkActivated: Qt.openUrlExternally(link)
}
Label
{
text: model.description
elide: Text.ElideRight
width: (projectsList.width * 0.6) | 0
}
Label
{
text: model.license
elide: Text.ElideRight
width: (projectsList.width * 0.15) | 0
}
}
model: ListModel
{
id: projectsModel
}
Component.onCompleted:
{
projectsModel.append({ name:"Cura", description: catalog.i18nc("@label", "Graphical user interface"), license: "LGPLv3", url: "https://github.com/Ultimaker/Cura" });
projectsModel.append({ name:"Uranium", description: catalog.i18nc("@label", "Application framework"), license: "LGPLv3", url: "https://github.com/Ultimaker/Uranium" });
projectsModel.append({ name:"CuraEngine", description: catalog.i18nc("@label", "G-code generator"), license: "AGPLv3", url: "https://github.com/Ultimaker/CuraEngine" });
projectsModel.append({ name:"libArcus", description: catalog.i18nc("@label", "Interprocess communication library"), license: "LGPLv3", url: "https://github.com/Ultimaker/libArcus" });
projectsModel.append({ name:"Python", description: catalog.i18nc("@label", "Programming language"), license: "Python", url: "http://python.org/" });
projectsModel.append({ name:"Qt5", description: catalog.i18nc("@label", "GUI framework"), license: "LGPLv3", url: "https://www.qt.io/" });
projectsModel.append({ name:"PyQt", description: catalog.i18nc("@label", "GUI framework bindings"), license: "GPL", url: "https://riverbankcomputing.com/software/pyqt" });
projectsModel.append({ name:"SIP", description: catalog.i18nc("@label", "C/C++ Binding library"), license: "GPL", url: "https://riverbankcomputing.com/software/sip" });
projectsModel.append({ name:"Protobuf", description: catalog.i18nc("@label", "Data interchange format"), license: "BSD", url: "https://developers.google.com/protocol-buffers" });
projectsModel.append({ name:"SciPy", description: catalog.i18nc("@label", "Support library for scientific computing"), license: "BSD-new", url: "https://www.scipy.org/" });
projectsModel.append({ name:"NumPy", description: catalog.i18nc("@label", "Support library for faster math"), license: "BSD", url: "http://www.numpy.org/" });
projectsModel.append({ name:"NumPy-STL", description: catalog.i18nc("@label", "Support library for handling STL files"), license: "BSD", url: "https://github.com/WoLpH/numpy-stl" });
projectsModel.append({ name:"Shapely", description: catalog.i18nc("@label", "Support library for handling planar objects"), license: "BSD", url: "https://github.com/Toblerity/Shapely" });
projectsModel.append({ name:"Trimesh", description: catalog.i18nc("@label", "Support library for handling triangular meshes"), license: "MIT", url: "https://trimsh.org" });
projectsModel.append({ name:"NetworkX", description: catalog.i18nc("@label", "Support library for analysis of complex networks"), license: "3-clause BSD", url: "https://networkx.github.io/" });
projectsModel.append({ name:"libSavitar", description: catalog.i18nc("@label", "Support library for handling 3MF files"), license: "LGPLv3", url: "https://github.com/ultimaker/libsavitar" });
projectsModel.append({ name:"libCharon", description: catalog.i18nc("@label", "Support library for file metadata and streaming"), license: "LGPLv3", url: "https://github.com/ultimaker/libcharon" });
projectsModel.append({ name:"PySerial", description: catalog.i18nc("@label", "Serial communication library"), license: "Python", url: "http://pyserial.sourceforge.net/" });
projectsModel.append({ name:"python-zeroconf", description: catalog.i18nc("@label", "ZeroConf discovery library"), license: "LGPL", url: "https://github.com/jstasiak/python-zeroconf" });
projectsModel.append({ name:"Clipper", description: catalog.i18nc("@label", "Polygon clipping library"), license: "Boost", url: "http://www.angusj.com/delphi/clipper.php" });
projectsModel.append({ name:"Requests", description: catalog.i18nc("@Label", "Python HTTP library"), license: "GPL", url: "http://docs.python-requests.org" });
projectsModel.append({ name:"Noto Sans", description: catalog.i18nc("@label", "Font"), license: "Apache 2.0", url: "https://www.google.com/get/noto/" });
projectsModel.append({ name:"Font-Awesome-SVG-PNG", description: catalog.i18nc("@label", "SVG icons"), license: "SIL OFL 1.1", url: "https://github.com/encharm/Font-Awesome-SVG-PNG" });
projectsModel.append({ name:"AppImageKit", description: catalog.i18nc("@label", "Linux cross-distribution application deployment"), license: "MIT", url: "https://github.com/AppImage/AppImageKit" });
}
}
}
rightButtons: Button
{
//: Close about dialog button
id: closeButton
text: catalog.i18nc("@action:button","Close");
onClicked: base.visible = false;
}
}

View file

@ -0,0 +1,69 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.1
import UM 1.4 as UM
import Cura 1.1 as Cura
Column
{
property var profile: null
property var loggedIn: false
property var profileImage: ""
padding: 2 * UM.Theme.getSize("default_margin").height
spacing: 2 * UM.Theme.getSize("default_margin").height
AvatarImage
{
id: avatar
width: UM.Theme.getSize("avatar_image").width
height: UM.Theme.getSize("avatar_image").height
anchors.horizontalCenter: parent.horizontalCenter
source:
{
if(loggedIn)
{
if(profileImage)
{
return profileImage
}
return UM.Theme.getImage("avatar_no_user")
}
return UM.Theme.getImage("avatar_no_user")
}
outlineColor: loggedIn ? UM.Theme.getColor("account_widget_outline_active") : UM.Theme.getColor("lining")
}
Label
{
id: information
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter
renderType: Text.NativeRendering
text: loggedIn ? profile["username"] : catalog.i18nc("@label", "Please log in or create an account to\nenjoy all features of Ultimaker Cura.")
font: loggedIn ? UM.Theme.getFont("large") : UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
}
Loader
{
id: accountOperations
anchors.horizontalCenter: parent.horizontalCenter
sourceComponent: loggedIn ? userOperations : generalOperations
}
Component
{
id: userOperations
UserOperations { }
}
Component
{
id: generalOperations
GeneralOperations { }
}
}

View file

@ -0,0 +1,76 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.1
import UM 1.4 as UM
import Cura 1.1 as Cura
Button
{
id: accountWidget
property var profile: Cura.API.account.userProfile
property var loggedIn: Cura.API.account.isLoggedIn
implicitHeight: UM.Theme.getSize("main_window_header").height
implicitWidth: UM.Theme.getSize("main_window_header").height
background: AvatarImage
{
id: avatar
width: Math.round(0.8 * accountWidget.width)
height: Math.round(0.8 * accountWidget.height)
anchors.verticalCenter: accountWidget.verticalCenter
anchors.horizontalCenter: accountWidget.horizontalCenter
source:
{
if(loggedIn)
{
if(profile["profile_image_url"])
{
return profile["profile_image_url"]
}
return UM.Theme.getImage("avatar_no_user")
}
return UM.Theme.getImage("avatar_no_user")
}
outlineColor: loggedIn ? UM.Theme.getColor("account_widget_outline_active") : UM.Theme.getColor("lining")
}
onClicked: popup.opened ? popup.close() : popup.open()
Popup
{
id: popup
y: parent.height + UM.Theme.getSize("default_arrow").height
x: parent.width - width
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
opacity: opened ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 100 } }
contentItem: AccountDetails
{
id: panel
profile: Cura.API.account.userProfile
loggedIn: Cura.API.account.isLoggedIn
profileImage: Cura.API.account.profileImageUrl
}
background: UM.PointingRectangle
{
color: UM.Theme.getColor("tool_panel_background")
borderColor: UM.Theme.getColor("lining")
borderWidth: UM.Theme.getSize("default_lining").width
target: Qt.point(width - (accountWidget.width / 2), -10)
arrowSize: UM.Theme.getSize("default_arrow").width
}
}
}

View file

@ -0,0 +1,56 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtGraphicalEffects 1.0
import UM 1.4 as UM
Item
{
// This item shows the provided image while applying a round mask to it.
// It also shows a round border around it. The color is defined by the outlineColor property.
id: avatar
property alias source: profileImage.source
property alias outlineColor: profileImageOutline.color
Image
{
id: profileImage
anchors.fill: parent
source: UM.Theme.getImage("avatar_default")
fillMode: Image.PreserveAspectCrop
visible: false
mipmap: true
}
Rectangle
{
id: profileImageMask
anchors.fill: parent
radius: width
}
OpacityMask
{
anchors.fill: parent
source: profileImage
maskSource: profileImageMask
cached: true
}
UM.RecolorImage
{
id: profileImageOutline
anchors.centerIn: parent
// Make it a bit bigger than it has to, otherwise it sometimes shows a white border.
width: parent.width + 2
height: parent.height + 2
source: UM.Theme.getIcon("circle_outline")
sourceSize: Qt.size(parent.width, parent.height)
color: UM.Theme.getColor("account_widget_ouline_active")
}
}

View file

@ -0,0 +1,31 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import UM 1.4 as UM
import Cura 1.1 as Cura
Row
{
spacing: UM.Theme.getSize("default_margin").width
Cura.SecondaryButton
{
width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height
text: catalog.i18nc("@button", "Create account")
onClicked: Qt.openUrlExternally("https://account.ultimaker.com/app/create")
fixedWidthMode: true
}
Cura.PrimaryButton
{
width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height
text: catalog.i18nc("@button", "Login")
onClicked: Cura.API.account.login()
fixedWidthMode: true
}
}

View file

@ -0,0 +1,31 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import UM 1.4 as UM
import Cura 1.1 as Cura
Row
{
spacing: UM.Theme.getSize("default_margin").width
Cura.SecondaryButton
{
width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height
text: catalog.i18nc("@button", "Manage account")
onClicked: Qt.openUrlExternally("https://account.ultimaker.com")
fixedWidthMode: true
}
Cura.PrimaryButton
{
width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height
text: catalog.i18nc("@button", "Logout")
onClicked: Cura.API.account.logout()
fixedWidthMode: true
}
}

View file

@ -0,0 +1,98 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtGraphicalEffects 1.0 // For the dropshadow
import UM 1.1 as UM
Button
{
id: button
property alias iconSource: buttonIcon.source
property alias textFont: buttonText.font
property alias cornerRadius: backgroundRect.radius
property alias tooltip: tooltip.text
property color color: UM.Theme.getColor("primary")
property color hoverColor: UM.Theme.getColor("primary_hover")
property color disabledColor: color
property color textColor: UM.Theme.getColor("button_text")
property color textHoverColor: textColor
property color textDisabledColor: textColor
property color outlineColor: color
property color outlineHoverColor: hoverColor
property color outlineDisabledColor: outlineColor
hoverEnabled: true
property alias shadowColor: shadow.color
property alias shadowEnabled: shadow.visible
// This property is used to indicate whether the button has a fixed width or the width would depend on the contents
// Be careful when using fixedWidthMode, the translated texts can be too long that they won't fit. In any case,
// we elide the text to the right so the text will be cut off with the three dots at the end.
property var fixedWidthMode: false
contentItem: Row
{
UM.RecolorImage
{
id: buttonIcon
source: ""
height: Math.round(0.6 * parent.height)
width: height
sourceSize.width: width
sourceSize.height: height
color: button.hovered ? button.textHoverColor : button.textColor
visible: source != ""
anchors.verticalCenter: parent.verticalCenter
}
Label
{
id: buttonText
text: button.text
color: button.enabled ? (button.hovered ? button.textHoverColor : button.textColor): button.textDisabledColor
font: UM.Theme.getFont("action_button")
visible: text != ""
renderType: Text.NativeRendering
anchors.verticalCenter: parent.verticalCenter
width: fixedWidthMode ? button.width - button.leftPadding - button.rightPadding : undefined
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
}
}
background: Rectangle
{
id: backgroundRect
color: button.enabled ? (button.hovered ? button.hoverColor : button.color) : button.disabledColor
radius: UM.Theme.getSize("action_button_radius").width
border.width: UM.Theme.getSize("default_lining").width
border.color: button.enabled ? (button.hovered ? button.outlineHoverColor : button.outlineColor) : button.outlineDisabledColor
}
DropShadow
{
id: shadow
// Don't blur the shadow
radius: 0
anchors.fill: backgroundRect
source: backgroundRect
verticalOffset: 2
visible: false
// Should always be drawn behind the background.
z: backgroundRect.z - 1
}
ToolTip
{
id: tooltip
text: ""
delay: 500
visible: text != "" && button.hovered
}
}

View file

@ -0,0 +1,55 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
import UM 1.2 as UM
import Cura 1.0 as Cura
// This element hold all the elements needed for the user to trigger the slicing process, and later
// to get information about the printing times, material consumption and the output process (such as
// saving to a file, printing over network, ...
Rectangle
{
id: actionPanelWidget
width: UM.Theme.getSize("action_panel_widget").width
height: childrenRect.height + 2 * UM.Theme.getSize("thick_margin").height
color: UM.Theme.getColor("main_background")
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
radius: UM.Theme.getSize("default_radius").width
property bool outputAvailable: UM.Backend.state == UM.Backend.Done || UM.Backend.state == UM.Backend.Disabled
Loader
{
id: loader
anchors
{
top: parent.top
topMargin: UM.Theme.getSize("thick_margin").height
left: parent.left
leftMargin: UM.Theme.getSize("thick_margin").width
right: parent.right
rightMargin: UM.Theme.getSize("thick_margin").width
}
sourceComponent: outputAvailable ? outputProcessWidget : sliceProcessWidget
}
Component
{
id: sliceProcessWidget
SliceProcessWidget { }
}
Component
{
id: outputProcessWidget
OutputProcessWidget { }
}
}

View file

@ -0,0 +1,103 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
import UM 1.1 as UM
import Cura 1.0 as Cura
Item
{
id: widget
Cura.PrimaryButton
{
id: saveToButton
height: parent.height
fixedWidthMode: true
anchors
{
top: parent.top
left: parent.left
right: deviceSelectionMenu.visible ? deviceSelectionMenu.left : parent.right
}
tooltip: UM.OutputDeviceManager.activeDeviceDescription
text: UM.OutputDeviceManager.activeDeviceShortDescription
onClicked:
{
forceActiveFocus();
UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, PrintInformation.jobName,
{ "filter_by_machine": true, "preferred_mimetypes": Cura.MachineManager.activeMachine.preferred_output_file_formats });
}
}
Cura.ActionButton
{
id: deviceSelectionMenu
height: parent.height
shadowEnabled: true
shadowColor: UM.Theme.getColor("primary_shadow")
anchors
{
top: parent.top
right: parent.right
}
tooltip: catalog.i18nc("@info:tooltip", "Select the active output device")
iconSource: popup.opened ? UM.Theme.getIcon("arrow_top") : UM.Theme.getIcon("arrow_bottom")
color: UM.Theme.getColor("action_panel_secondary")
visible: (devicesModel.deviceCount > 1)
onClicked: popup.opened ? popup.close() : popup.open()
Popup
{
id: popup
padding: 0
y: -height
x: parent.width - width
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
contentItem: ColumnLayout
{
Repeater
{
model: devicesModel
delegate: Cura.ActionButton
{
text: model.description
color: "transparent"
cornerRadius: 0
hoverColor: UM.Theme.getColor("primary")
Layout.fillWidth: true
onClicked:
{
UM.OutputDeviceManager.setActiveDevice(model.id)
popup.close()
}
}
}
}
background: Rectangle
{
opacity: visible ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 100 } }
color: UM.Theme.getColor("action_panel_secondary")
}
}
}
UM.OutputDevicesModel { id: devicesModel }
}

View file

@ -0,0 +1,130 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
import UM 1.1 as UM
import Cura 1.0 as Cura
// This element contains all the elements the user needs to visualize the data
// that is gather after the slicing process, such as printint time, material usage, ...
// There are also two buttons: one to previsualize the output layers, and the other to
// select what to do with it (such as print over network, save to file, ...)
Column
{
id: widget
spacing: UM.Theme.getSize("thin_margin").height
property bool preSlicedData: PrintInformation.preSliced
UM.I18nCatalog
{
id: catalog
name: "cura"
}
Item
{
id: information
width: parent.width
height: childrenRect.height
Column
{
id: timeAndCostsInformation
spacing: UM.Theme.getSize("thin_margin").height
anchors
{
left: parent.left
right: printInformationPanel.left
rightMargin: UM.Theme.getSize("thin_margin").height
}
Cura.IconLabel
{
id: estimatedTime
width: parent.width
text: preSlicedData ? catalog.i18nc("@label", "No time estimation available") : PrintInformation.currentPrintTime.getDisplayString(UM.DurationFormat.Long)
source: UM.Theme.getIcon("clock")
font: UM.Theme.getFont("small")
}
Cura.IconLabel
{
id: estimatedCosts
width: parent.width
property var printMaterialLengths: PrintInformation.materialLengths
property var printMaterialWeights: PrintInformation.materialWeights
text:
{
if (preSlicedData)
{
return catalog.i18nc("@label", "No cost estimation available")
}
var totalLengths = 0
var totalWeights = 0
if (printMaterialLengths)
{
for(var index = 0; index < printMaterialLengths.length; index++)
{
if(printMaterialLengths[index] > 0)
{
totalLengths += printMaterialLengths[index]
totalWeights += Math.round(printMaterialWeights[index])
}
}
}
return totalWeights + "g · " + totalLengths.toFixed(2) + "m"
}
source: UM.Theme.getIcon("spool")
font: UM.Theme.getFont("very_small")
}
}
PrintInformationWidget
{
id: printInformationPanel
visible: !preSlicedData
anchors
{
right: parent.right
verticalCenter: timeAndCostsInformation.verticalCenter
}
}
}
Row
{
id: buttonRow
spacing: UM.Theme.getSize("default_margin").width
width: parent.width
Cura.SecondaryButton
{
id: previewStageShortcut
height: UM.Theme.getSize("action_panel_button").height
text: catalog.i18nc("@button", "Preview")
onClicked: UM.Controller.setActiveStage("PreviewStage")
visible: UM.Controller.activeStage != null && UM.Controller.activeStage.stageId != "PreviewStage"
shadowEnabled: true
shadowColor: UM.Theme.getColor("action_button_disabled_shadow")
}
Cura.OutputDevicesActionButton
{
width: previewStageShortcut.visible ? UM.Theme.getSize("action_panel_button").width : parent.width
height: UM.Theme.getSize("action_panel_button").height
}
}
}

View file

@ -0,0 +1,64 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.1
import UM 1.1 as UM
import Cura 1.0 as Cura
UM.RecolorImage
{
id: widget
//implicitHeight: UM.Theme.getSize("section_icon").height
//implicitWidth: UM.Theme.getSize("section_icon").width
source: UM.Theme.getIcon("info")
width: UM.Theme.getSize("section_icon").width
height: UM.Theme.getSize("section_icon").height
sourceSize.width: width
sourceSize.height: height
color: popup.opened ? UM.Theme.getColor("primary") : UM.Theme.getColor("text_medium")
MouseArea
{
anchors.fill: parent
hoverEnabled: true
onEntered: popup.open()
onExited: popup.close()
}
Popup
{
id: popup
y: -(height + UM.Theme.getSize("default_arrow").height + UM.Theme.getSize("thin_margin").height)
x: parent.width - width + UM.Theme.getSize("thin_margin").width
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
opacity: opened ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 100 } }
contentItem: PrintJobInformation
{
id: printJobInformation
width: UM.Theme.getSize("action_panel_information_widget").width
}
background: UM.PointingRectangle
{
color: UM.Theme.getColor("tool_panel_background")
borderColor: UM.Theme.getColor("lining")
borderWidth: UM.Theme.getSize("default_lining").width
target: Qt.point(width - (widget.width / 2) - UM.Theme.getSize("thin_margin").width,
height + UM.Theme.getSize("default_arrow").height - UM.Theme.getSize("thin_margin").height)
arrowSize: UM.Theme.getSize("default_arrow").width
}
}
}

View file

@ -0,0 +1,159 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.1
import UM 1.1 as UM
import Cura 1.0 as Cura
Column
{
id: base
spacing: UM.Theme.getSize("default_margin").width
UM.I18nCatalog
{
id: catalog
name: "cura"
}
Column
{
id: timeSpecification
width: parent.width
topPadding: UM.Theme.getSize("default_margin").height
leftPadding: UM.Theme.getSize("default_margin").width
rightPadding: UM.Theme.getSize("default_margin").width
Label
{
text: catalog.i18nc("@label", "Time specification").toUpperCase()
color: UM.Theme.getColor("primary")
font: UM.Theme.getFont("small")
renderType: Text.NativeRendering
}
Label
{
property var printDuration: PrintInformation.currentPrintTime
text:
{
// All the time information for the different features is achieved
var printTime = PrintInformation.getFeaturePrintTimes()
var totalSeconds = parseInt(printDuration.getDisplayString(UM.DurationFormat.Seconds))
// A message is created and displayed when the user hover the time label
var text = "<table width=\"100%\">"
for(var feature in printTime)
{
if(!printTime[feature].isTotalDurationZero)
{
text += "<tr><td>" + feature + ":</td>" +
"<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1</td>".arg(printTime[feature].getDisplayString(UM.DurationFormat.ISO8601).slice(0,-3)) +
"<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1%</td>".arg(Math.round(100 * parseInt(printTime[feature].getDisplayString(UM.DurationFormat.Seconds)) / totalSeconds)) +
"</tr>"
}
}
text += "</table>"
return text
}
width: parent.width - 2 * UM.Theme.getSize("default_margin").width
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("very_small")
renderType: Text.NativeRendering
textFormat: Text.RichText
}
}
Column
{
id: materialSpecification
width: parent.width
bottomPadding: UM.Theme.getSize("default_margin").height
leftPadding: UM.Theme.getSize("default_margin").width
rightPadding: UM.Theme.getSize("default_margin").width
Label
{
text: catalog.i18nc("@label", "Material specification").toUpperCase()
color: UM.Theme.getColor("primary")
font: UM.Theme.getFont("small")
renderType: Text.NativeRendering
}
Label
{
property var printMaterialLengths: PrintInformation.materialLengths
property var printMaterialWeights: PrintInformation.materialWeights
property var printMaterialCosts: PrintInformation.materialCosts
property var printMaterialNames: PrintInformation.materialNames
function formatRow(items)
{
var rowHTML = "<tr>"
for(var item = 0; item < items.length; item++)
{
if (item == 0)
{
rowHTML += "<td valign=\"bottom\">%1</td>".arg(items[item])
}
else
{
rowHTML += "<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1</td>".arg(items[item])
}
}
rowHTML += "</tr>"
return rowHTML
}
text:
{
var lengths = []
var weights = []
var costs = []
var names = []
if(printMaterialLengths)
{
for(var index = 0; index < printMaterialLengths.length; index++)
{
if(printMaterialLengths[index] > 0)
{
names.push(printMaterialNames[index])
lengths.push(printMaterialLengths[index].toFixed(2))
weights.push(String(Math.round(printMaterialWeights[index])))
var cost = printMaterialCosts[index] == undefined ? 0 : printMaterialCosts[index].toFixed(2)
costs.push(cost)
}
}
}
if(lengths.length == 0)
{
lengths = ["0.00"]
weights = ["0"]
costs = ["0.00"]
}
var text = "<table width=\"100%\">"
for(var index = 0; index < lengths.length; index++)
{
text += formatRow([
"%1:".arg(names[index]),
catalog.i18nc("@label m for meter", "%1m").arg(lengths[index]),
catalog.i18nc("@label g for grams", "%1g").arg(weights[index]),
"%1&nbsp;%2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index]),
])
}
text += "</table>"
return text
}
width: parent.width - 2 * UM.Theme.getSize("default_margin").width
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("very_small")
renderType: Text.NativeRendering
textFormat: Text.RichText
}
}
}

View file

@ -0,0 +1,154 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
import QtQuick.Controls 1.4 as Controls1
import UM 1.1 as UM
import Cura 1.0 as Cura
// This element contains all the elements the user needs to create a printjob from the
// model(s) that is(are) on the buildplate. Mainly the button to start/stop the slicing
// process and a progress bar to see the progress of the process.
Column
{
id: widget
spacing: UM.Theme.getSize("thin_margin").height
UM.I18nCatalog
{
id: catalog
name: "cura"
}
property real progress: UM.Backend.progress
property int backendState: UM.Backend.state
function sliceOrStopSlicing()
{
if (widget.backendState == UM.Backend.NotStarted)
{
CuraApplication.backend.forceSlice()
}
else
{
CuraApplication.backend.stopSlicing()
}
}
Label
{
id: autoSlicingLabel
width: parent.width
visible: prepareButtons.autoSlice && widget.backendState == UM.Backend.Processing
text: catalog.i18nc("@label:PrintjobStatus", "Auto slicing...")
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("very_small")
renderType: Text.NativeRendering
}
Cura.IconLabel
{
id: unableToSliceMessage
width: parent.width
visible: widget.backendState == UM.Backend.Error
text: catalog.i18nc("@label:PrintjobStatus", "Unable to Slice")
source: UM.Theme.getIcon("warning")
color: UM.Theme.getColor("warning")
font: UM.Theme.getFont("very_small")
}
// Progress bar, only visible when the backend is in the process of slice the printjob
ProgressBar
{
id: progressBar
width: parent.width
height: UM.Theme.getSize("progressbar").height
value: progress
visible: widget.backendState == UM.Backend.Processing
background: Rectangle
{
anchors.fill: parent
radius: UM.Theme.getSize("progressbar_radius").width
color: UM.Theme.getColor("progressbar_background")
}
contentItem: Item
{
anchors.fill: parent
Rectangle
{
width: progressBar.visualPosition * parent.width
height: parent.height
radius: UM.Theme.getSize("progressbar_radius").width
color: UM.Theme.getColor("progressbar_control")
}
}
}
Item
{
id: prepareButtons
// Get the current value from the preferences
property bool autoSlice: UM.Preferences.getValue("general/auto_slice")
// Disable the slice process when
width: parent.width
height: UM.Theme.getSize("action_panel_button").height
visible: !autoSlice
Cura.PrimaryButton
{
id: sliceButton
fixedWidthMode: true
anchors.fill: parent
text: catalog.i18nc("@button", "Slice")
enabled: widget.backendState != UM.Backend.Error
visible: widget.backendState == UM.Backend.NotStarted || widget.backendState == UM.Backend.Error
onClicked: sliceOrStopSlicing()
}
Cura.SecondaryButton
{
id: cancelButton
fixedWidthMode: true
anchors.fill: parent
text: catalog.i18nc("@button", "Cancel")
enabled: sliceButton.enabled
visible: !sliceButton.visible
onClicked: sliceOrStopSlicing()
}
}
// React when the user changes the preference of having the auto slice enabled
Connections
{
target: UM.Preferences
onPreferenceChanged:
{
var autoSlice = UM.Preferences.getValue("general/auto_slice")
prepareButtons.autoSlice = autoSlice
}
}
// Shortcut for "slice/stop"
Controls1.Action
{
shortcut: "Ctrl+P"
onTriggered:
{
if (prepareButton.enabled)
{
sliceOrStopSlicing()
}
}
}
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2015 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
pragma Singleton pragma Singleton
@ -23,8 +23,6 @@ Item
property alias viewLeftSideCamera: viewLeftSideCameraAction; property alias viewLeftSideCamera: viewLeftSideCameraAction;
property alias viewRightSideCamera: viewRightSideCameraAction; property alias viewRightSideCamera: viewRightSideCameraAction;
property alias expandSidebar: expandSidebarAction;
property alias deleteSelection: deleteSelectionAction; property alias deleteSelection: deleteSelectionAction;
property alias centerSelection: centerSelectionAction; property alias centerSelection: centerSelectionAction;
property alias multiplySelection: multiplySelectionAction; property alias multiplySelection: multiplySelectionAction;
@ -58,7 +56,6 @@ Item
property alias preferences: preferencesAction; property alias preferences: preferencesAction;
property alias showEngineLog: showEngineLogAction;
property alias showProfileFolder: showProfileFolderAction; property alias showProfileFolder: showProfileFolderAction;
property alias documentation: documentationAction; property alias documentation: documentationAction;
property alias reportBug: reportBugAction; property alias reportBug: reportBugAction;
@ -70,7 +67,7 @@ Item
property alias browsePackages: browsePackagesAction property alias browsePackages: browsePackagesAction
UM.I18nCatalog{id: catalog; name:"cura"} UM.I18nCatalog{id: catalog; name: "cura"}
Action Action
{ {
@ -398,14 +395,6 @@ Item
shortcut: StandardKey.New shortcut: StandardKey.New
} }
Action
{
id: showEngineLogAction;
text: catalog.i18nc("@action:inmenu menubar:help","Show Engine &Log...");
iconName: "view-list-text";
shortcut: StandardKey.WhatsThis;
}
Action Action
{ {
id: showProfileFolderAction; id: showProfileFolderAction;
@ -426,11 +415,4 @@ Item
text: catalog.i18nc("@action:menu", "&Marketplace") text: catalog.i18nc("@action:menu", "&Marketplace")
iconName: "plugins_browse" iconName: "plugins_browse"
} }
Action
{
id: expandSidebarAction;
text: catalog.i18nc("@action:inmenu menubar:view","Expand/Collapse Sidebar");
shortcut: "Ctrl+E";
}
} }

View file

@ -0,0 +1,10 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.0
QtObject
{
property real width: 0
property color color: "black"
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2017 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7 import QtQuick 2.7
@ -6,53 +6,42 @@ import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4 import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
import QtGraphicalEffects 1.0
import UM 1.3 as UM import UM 1.3 as UM
import Cura 1.1 as Cura import Cura 1.1 as Cura
import "Dialogs"
import "Menus" import "Menus"
import "MainWindow"
UM.MainWindow UM.MainWindow
{ {
id: base id: base
//: Cura application window title
title: catalog.i18nc("@title:window","Ultimaker Cura");
viewportRect: Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0)
property bool showPrintMonitor: false
// Cura application window title
title: catalog.i18nc("@title:window", "Ultimaker Cura")
backgroundColor: UM.Theme.getColor("viewport_background") backgroundColor: UM.Theme.getColor("viewport_background")
// This connection is here to support legacy printer output devices that use the showPrintMonitor signal on Application to switch to the monitor stage
// It should be phased out in newer plugin versions. UM.I18nCatalog
Connections
{ {
target: CuraApplication id: catalog
onShowPrintMonitor: { name: "cura"
if (show) {
UM.Controller.setActiveStage("MonitorStage")
} else {
UM.Controller.setActiveStage("PrepareStage")
}
}
} }
onWidthChanged: function showTooltip(item, position, text)
{ {
// If slidebar is collapsed then it should be invisible tooltip.text = text;
// otherwise after the main_window resize the sidebar will be fully re-drawn position = item.mapToItem(backgroundItem, position.x - UM.Theme.getSize("default_arrow").width, position.y);
if (sidebar.collapsed){ tooltip.show(position);
if (sidebar.visible == true){
sidebar.visible = false
sidebar.initialWidth = 0
}
}
else{
if (sidebar.visible == false){
sidebar.visible = true
sidebar.initialWidth = UM.Theme.getSize("sidebar").width
}
}
} }
function hideTooltip()
{
tooltip.hide();
}
Component.onCompleted: Component.onCompleted:
{ {
CuraApplication.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size")) CuraApplication.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size"))
@ -72,12 +61,12 @@ UM.MainWindow
Item Item
{ {
id: backgroundItem; id: backgroundItem
anchors.fill: parent; anchors.fill: parent
UM.I18nCatalog{id: catalog; name:"cura"}
signal hasMesh(string name) //this signal sends the filebase name so it can be used for the JobSpecs.qml signal hasMesh(string name) //this signal sends the filebase name so it can be used for the JobSpecs.qml
function getMeshName(path){ function getMeshName(path)
{
//takes the path the complete path of the meshname and returns only the filebase //takes the path the complete path of the meshname and returns only the filebase
var fileName = path.slice(path.lastIndexOf("/") + 1) var fileName = path.slice(path.lastIndexOf("/") + 1)
var fileBase = fileName.slice(0, fileName.indexOf(".")) var fileBase = fileName.slice(0, fileName.indexOf("."))
@ -85,253 +74,49 @@ UM.MainWindow
} }
//DeleteSelection on the keypress backspace event //DeleteSelection on the keypress backspace event
Keys.onPressed: { Keys.onPressed:
{
if (event.key == Qt.Key_Backspace) if (event.key == Qt.Key_Backspace)
{ {
Cura.Actions.deleteSelection.trigger() Cura.Actions.deleteSelection.trigger()
} }
} }
UM.ApplicationMenu ApplicationMenu
{ {
id: menu id: applicationMenu
window: base window: base
Menu
{
id: fileMenu
title: catalog.i18nc("@title:menu menubar:toplevel","&File");
MenuItem
{
id: newProjectMenu
action: Cura.Actions.newProject;
}
MenuItem
{
id: openMenu
action: Cura.Actions.open;
}
RecentFilesMenu { }
MenuItem
{
id: saveWorkspaceMenu
text: catalog.i18nc("@title:menu menubar:file","&Save...")
onTriggered:
{
var args = { "filter_by_machine": false, "file_type": "workspace", "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml" };
if(UM.Preferences.getValue("cura/dialog_on_project_save"))
{
saveWorkspaceDialog.args = args;
saveWorkspaceDialog.open()
}
else
{
UM.OutputDeviceManager.requestWriteToDevice("local_file", PrintInformation.jobName, args)
}
}
}
MenuSeparator { }
MenuItem
{
id: saveAsMenu
text: catalog.i18nc("@title:menu menubar:file", "&Export...")
onTriggered:
{
var localDeviceId = "local_file";
UM.OutputDeviceManager.requestWriteToDevice(localDeviceId, PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"});
}
}
MenuItem
{
id: exportSelectionMenu
text: catalog.i18nc("@action:inmenu menubar:file", "Export Selection...");
enabled: UM.Selection.hasSelection;
iconName: "document-save-as";
onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"});
}
MenuSeparator { }
MenuItem
{
id: reloadAllMenu
action: Cura.Actions.reloadAll;
}
MenuSeparator { }
MenuItem { action: Cura.Actions.quit; }
}
Menu
{
title: catalog.i18nc("@title:menu menubar:toplevel","&Edit");
MenuItem { action: Cura.Actions.undo; }
MenuItem { action: Cura.Actions.redo; }
MenuSeparator { }
MenuItem { action: Cura.Actions.selectAll; }
MenuItem { action: Cura.Actions.arrangeAll; }
MenuItem { action: Cura.Actions.deleteSelection; }
MenuItem { action: Cura.Actions.deleteAll; }
MenuItem { action: Cura.Actions.resetAllTranslation; }
MenuItem { action: Cura.Actions.resetAll; }
MenuSeparator { }
MenuItem { action: Cura.Actions.groupObjects;}
MenuItem { action: Cura.Actions.mergeObjects;}
MenuItem { action: Cura.Actions.unGroupObjects;}
}
ViewMenu { title: catalog.i18nc("@title:menu", "&View") }
Menu
{
id: settingsMenu
title: catalog.i18nc("@title:menu", "&Settings")
PrinterMenu { title: catalog.i18nc("@title:menu menubar:settings", "&Printer") }
Instantiator
{
model: Cura.ExtrudersModel { simpleNames: true }
Menu {
title: model.name
NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: Cura.MachineManager.hasVariants; extruderIndex: index }
MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: Cura.MachineManager.hasMaterials; extruderIndex: index }
MenuSeparator
{
visible: Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials
}
MenuItem
{
text: catalog.i18nc("@action:inmenu", "Set as Active Extruder")
onTriggered: Cura.MachineManager.setExtruderIndex(model.index)
}
MenuItem
{
text: catalog.i18nc("@action:inmenu", "Enable Extruder")
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true)
visible: !Cura.MachineManager.getExtruder(model.index).isEnabled
}
MenuItem
{
text: catalog.i18nc("@action:inmenu", "Disable Extruder")
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false)
visible: Cura.MachineManager.getExtruder(model.index).isEnabled
enabled: Cura.MachineManager.numberExtrudersEnabled > 1
}
}
onObjectAdded: settingsMenu.insertItem(index, object)
onObjectRemoved: settingsMenu.removeItem(object)
}
// TODO Only show in dev mode. Remove check when feature ready
BuildplateMenu { title: catalog.i18nc("@title:menu", "&Build plate"); visible: CuraSDKVersion == "dev" ? Cura.MachineManager.hasVariantBuildplates : false }
ProfileMenu { title: catalog.i18nc("@title:settings", "&Profile"); }
MenuSeparator { }
MenuItem { action: Cura.Actions.configureSettingVisibility }
}
Menu
{
id: extension_menu
title: catalog.i18nc("@title:menu menubar:toplevel","E&xtensions");
Instantiator
{
id: extensions
model: UM.ExtensionModel { }
Menu
{
id: sub_menu
title: model.name;
visible: actions != null
enabled: actions != null
Instantiator
{
model: actions
MenuItem
{
text: model.text
onTriggered: extensions.model.subMenuTriggered(name, model.text)
}
onObjectAdded: sub_menu.insertItem(index, object)
onObjectRemoved: sub_menu.removeItem(object)
}
}
onObjectAdded: extension_menu.insertItem(index, object)
onObjectRemoved: extension_menu.removeItem(object)
}
}
Menu
{
id: plugin_menu
title: catalog.i18nc("@title:menu menubar:toplevel", "&Marketplace")
MenuItem { action: Cura.Actions.browsePackages }
}
Menu
{
id: preferencesMenu
title: catalog.i18nc("@title:menu menubar:toplevel","P&references");
MenuItem { action: Cura.Actions.preferences; }
}
Menu
{
id: helpMenu
title: catalog.i18nc("@title:menu menubar:toplevel","&Help");
MenuItem { action: Cura.Actions.showProfileFolder; }
MenuItem { action: Cura.Actions.documentation; }
MenuItem { action: Cura.Actions.reportBug; }
MenuSeparator { }
MenuItem { action: Cura.Actions.about; }
}
} }
UM.SettingPropertyProvider MainWindowHeader
{ {
id: machineExtruderCount id: mainWindowHeader
anchors
containerStack: Cura.MachineManager.activeMachine {
key: "machine_extruder_count" left: parent.left
watchedProperties: [ "value" ] right: parent.right
storeIndex: 0 top: applicationMenu.bottom
}
} }
Item Item
{ {
id: contentItem; id: contentItem
y: menu.height anchors
width: parent.width; {
height: parent.height - menu.height; top: mainWindowHeader.bottom
bottom: parent.bottom
left: parent.left
right: parent.right
}
Keys.forwardTo: menu Keys.forwardTo: applicationMenu
DropArea DropArea
{ {
anchors.fill: parent; // The drop area is here to handle files being dropped onto Cura.
anchors.fill: parent
onDropped: onDropped:
{ {
if (drop.urls.length > 0) if (drop.urls.length > 0)
@ -359,156 +144,154 @@ UM.MainWindow
} }
} }
Rectangle
{
id: stageMenuBackground
anchors
{
left: parent.left
right: parent.right
top: parent.top
}
visible: stageMenu.source != ""
height: visible ? Math.round(UM.Theme.getSize("stage_menu").height / 2) : 0
LinearGradient
{
anchors.fill: parent
start: Qt.point(0, 0)
end: Qt.point(parent.width, 0)
gradient: Gradient
{
GradientStop
{
position: 0.0
color: UM.Theme.getColor("main_window_header_background")
}
GradientStop
{
position: 0.5
color: UM.Theme.getColor("main_window_header_background_gradient")
}
GradientStop
{
position: 1.0
color: UM.Theme.getColor("main_window_header_background")
}
}
}
}
Connections
{
target: stageMenu.item
onShowTooltip: base.showTooltip(item, location, text)
onHideTooltip: base.hideTooltip()
}
JobSpecs JobSpecs
{ {
id: jobSpecs id: jobSpecs
anchors anchors
{ {
bottom: parent.bottom; bottom: parent.bottom
right: sidebar.left; bottomMargin: UM.Theme.getSize("default_margin").height
bottomMargin: UM.Theme.getSize("default_margin").height;
rightMargin: UM.Theme.getSize("default_margin").width;
} }
} }
Button
{
id: openFileButton;
text: catalog.i18nc("@action:button","Open File");
iconSource: UM.Theme.getIcon("load")
style: UM.Theme.styles.tool_button
tooltip: ""
anchors
{
top: topbar.bottom;
topMargin: UM.Theme.getSize("default_margin").height;
left: parent.left;
}
action: Cura.Actions.open;
}
Toolbar Toolbar
{ {
id: toolbar; // The toolbar is the left bar that is populated by all the tools (which are dynamicly populated by
// plugins)
id: toolbar
property int mouseX: base.mouseX property int mouseX: base.mouseX
property int mouseY: base.mouseY property int mouseY: base.mouseY
anchors { anchors
top: openFileButton.bottom; {
topMargin: UM.Theme.getSize("window_margin").height; verticalCenter: parent.verticalCenter
left: parent.left; left: parent.left
} }
visible: CuraApplication.platformActivity && !PrintInformation.preSliced
} }
ObjectsList ObjectsList
{ {
id: objectsList; id: objectsList
visible: UM.Preferences.getValue("cura/use_multi_build_plate"); visible: UM.Preferences.getValue("cura/use_multi_build_plate")
anchors anchors
{ {
bottom: parent.bottom; bottom: viewOrientationControls.top
left: parent.left; left: toolbar.right
margins: UM.Theme.getSize("default_margin").width
} }
} }
Topbar ViewOrientationControls
{
id: viewOrientationControls
anchors
{
left: parent.left
margins: UM.Theme.getSize("default_margin").width
bottom: parent.bottom
}
}
Cura.ActionPanelWidget
{ {
id: topbar
anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.bottom: parent.bottom
anchors.rightMargin: UM.Theme.getSize("thick_margin").width
anchors.bottomMargin: UM.Theme.getSize("thick_margin").height
visible: CuraApplication.platformActivity
} }
Loader Loader
{ {
// A stage can control this area. If nothing is set, it will therefore show the 3D view.
id: main id: main
anchors anchors
{ {
top: topbar.bottom top: stageMenuBackground.bottom
bottom: parent.bottom
left: parent.left left: parent.left
right: sidebar.left right: parent.right
bottom: parent.bottom
} }
MouseArea source: UM.Controller.activeStage != null ? UM.Controller.activeStage.mainComponent : ""
{
visible: UM.Controller.activeStage.mainComponent != ""
anchors.fill: parent
acceptedButtons: Qt.AllButtons
onWheel: wheel.accepted = true
}
source: UM.Controller.activeStage.mainComponent
} }
Loader Loader
{ {
id: sidebar // The stage menu is, as the name implies, a menu that is defined by the active stage.
// Note that this menu does not need to be set at all! It's perfectly acceptable to have a stage
property bool collapsed: false; // without this menu!
property var initialWidth: UM.Theme.getSize("sidebar").width; id: stageMenu
function callExpandOrCollapse() {
if (collapsed) {
sidebar.visible = true;
sidebar.initialWidth = UM.Theme.getSize("sidebar").width;
viewportRect = Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0);
expandSidebarAnimation.start();
} else {
viewportRect = Qt.rect(0, 0, 1, 1.0);
collapseSidebarAnimation.start();
}
collapsed = !collapsed;
UM.Preferences.setValue("cura/sidebar_collapsed", collapsed);
}
anchors anchors
{ {
top: topbar.top left: parent.left
bottom: parent.bottom right: parent.right
top: parent.top
} }
width: initialWidth height: UM.Theme.getSize("stage_menu").height
x: base.width - sidebar.width source: UM.Controller.activeStage != null ? UM.Controller.activeStage.stageMenuComponent : ""
source: UM.Controller.activeStage.sidebarComponent
NumberAnimation { // The printSetupSelector is defined here so that the setting list doesn't need to get re-instantiated
id: collapseSidebarAnimation // Every time the stage is changed.
target: sidebar property var printSetupSelector: Cura.PrintSetupSelector
properties: "x"
to: base.width
duration: 100
}
NumberAnimation {
id: expandSidebarAnimation
target: sidebar
properties: "x"
to: base.width - sidebar.width
duration: 100
}
Component.onCompleted:
{ {
var sidebar_collapsed = UM.Preferences.getValue("cura/sidebar_collapsed"); onShowTooltip: base.showTooltip(item, location, text)
onHideTooltip: base.hideTooltip()
if (sidebar_collapsed) width: UM.Theme.getSize("print_setup_widget").width
{ height: UM.Theme.getSize("stage_menu").height
sidebar.collapsed = true; headerCornerSide: RoundedRectangle.Direction.Right
viewportRect = Qt.rect(0, 0, 1, 1.0)
collapseSidebarAnimation.start();
}
}
MouseArea
{
visible: UM.Controller.activeStage.sidebarComponent != ""
anchors.fill: parent
acceptedButtons: Qt.AllButtons
onWheel: wheel.accepted = true
} }
} }
@ -517,20 +300,17 @@ UM.MainWindow
anchors anchors
{ {
horizontalCenter: parent.horizontalCenter horizontalCenter: parent.horizontalCenter
horizontalCenterOffset: -(Math.round(UM.Theme.getSize("sidebar").width / 2)) top: parent.verticalCenter
top: parent.verticalCenter; bottom: parent.bottom
bottom: parent.bottom;
bottomMargin: UM.Theme.getSize("default_margin").height bottomMargin: UM.Theme.getSize("default_margin").height
} }
} }
} }
}
// Expand or collapse sidebar SidebarTooltip
Connections {
{ id: tooltip
target: Cura.Actions.expandSidebar }
onTriggered: sidebar.callExpandOrCollapse()
} }
UM.PreferencesDialog UM.PreferencesDialog
@ -567,13 +347,6 @@ UM.MainWindow
} }
} }
WorkspaceSummaryDialog
{
id: saveWorkspaceDialog
property var args
onYes: UM.OutputDeviceManager.requestWriteToDevice("local_file", PrintInformation.jobName, args)
}
Connections Connections
{ {
target: Cura.Actions.preferences target: Cura.Actions.preferences
@ -586,33 +359,6 @@ UM.MainWindow
onShowPreferencesWindow: preferences.visible = true onShowPreferencesWindow: preferences.visible = true
} }
MessageDialog
{
id: newProjectDialog
modality: Qt.ApplicationModal
title: catalog.i18nc("@title:window", "New project")
text: catalog.i18nc("@info:question", "Are you sure you want to start a new project? This will clear the build plate and any unsaved settings.")
standardButtons: StandardButton.Yes | StandardButton.No
icon: StandardIcon.Question
onYes:
{
CuraApplication.deleteAll();
Cura.Actions.resetProfile.trigger();
}
}
Connections
{
target: Cura.Actions.newProject
onTriggered:
{
if(Printer.platformActivity || Cura.MachineManager.hasUserSettings)
{
newProjectDialog.visible = true
}
}
}
Connections Connections
{ {
target: Cura.Actions.addProfile target: Cura.Actions.addProfile
@ -670,19 +416,6 @@ UM.MainWindow
} }
} }
UM.ExtensionModel {
id: curaExtensions
}
// show the plugin browser dialog
Connections
{
target: Cura.Actions.browsePackages
onTriggered: {
curaExtensions.callExtensionMethod("Toolbox", "browsePackages")
}
}
Timer Timer
{ {
id: createProfileTimer id: createProfileTimer
@ -703,7 +436,8 @@ UM.MainWindow
} }
} }
ContextMenu { ContextMenu
{
id: contextMenu id: contextMenu
} }
@ -870,7 +604,8 @@ UM.MainWindow
modality: Qt.ApplicationModal modality: Qt.ApplicationModal
} }
MessageDialog { MessageDialog
{
id: infoMultipleFilesWithGcodeDialog id: infoMultipleFilesWithGcodeDialog
title: catalog.i18nc("@title:window", "Open File(s)") title: catalog.i18nc("@title:window", "Open File(s)")
icon: StandardIcon.Information icon: StandardIcon.Information
@ -914,11 +649,6 @@ UM.MainWindow
} }
} }
EngineLog
{
id: engineLog;
}
Connections Connections
{ {
target: Cura.Actions.showProfileFolder target: Cura.Actions.showProfileFolder

View file

@ -0,0 +1,357 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Rectangle
{
implicitWidth: parent.width
implicitHeight: parent.height
id: base
color: UM.Theme.getColor("main_background")
// Height has an extra 2x margin for the top & bottom margin.
height: childrenRect.height + 2 * UM.Theme.getSize("default_margin").width
Cura.ExtrudersModel { id: extrudersModel }
ListView
{
// Horizontal list that shows the extruders
id: extrudersList
visible: extrudersModel.items.length > 1
property var index: 0
height: UM.Theme.getSize("configuration_selector_mode_tabs").height
boundsBehavior: Flickable.StopAtBounds
anchors
{
left: parent.left
right: parent.right
top: parent.top
margins: UM.Theme.getSize("thick_margin").width
}
ExclusiveGroup { id: extruderMenuGroup }
orientation: ListView.Horizontal
model: extrudersModel
Connections
{
target: Cura.MachineManager
onGlobalContainerChanged: forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values.
}
delegate: Button
{
height: parent.height
width: Math.round(ListView.view.width / extrudersModel.rowCount())
text: model.name
tooltip: model.name
exclusiveGroup: extruderMenuGroup
checked: Cura.ExtruderManager.activeExtruderIndex == index
property bool extruder_enabled: true
MouseArea // TODO; This really should be fixed. It makes absolutely no sense to have a button AND a mouse area.
{
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked:
{
switch (mouse.button)
{
case Qt.LeftButton:
extruder_enabled = Cura.MachineManager.getExtruder(model.index).isEnabled
if (extruder_enabled)
{
forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values.
Cura.ExtruderManager.setActiveExtruderIndex(index)
}
break
case Qt.RightButton:
extruder_enabled = Cura.MachineManager.getExtruder(model.index).isEnabled
extruderMenu.popup()
break
}
}
}
Menu
{
id: extruderMenu
MenuItem
{
text: catalog.i18nc("@action:inmenu", "Enable Extruder")
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true)
visible: !extruder_enabled // using an intermediate variable prevents an empty popup that occured now and then
}
MenuItem
{
text: catalog.i18nc("@action:inmenu", "Disable Extruder")
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false)
visible: extruder_enabled
enabled: Cura.MachineManager.numberExtrudersEnabled > 1
}
}
style: ButtonStyle
{
background: Rectangle
{
anchors.fill: parent
border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width
border.color:
{
if (Cura.MachineManager.getExtruder(index).isEnabled)
{
if(control.checked || control.pressed)
{
return UM.Theme.getColor("action_button_active_border")
}
else if (control.hovered)
{
return UM.Theme.getColor("action_button_hovered_border")
}
return UM.Theme.getColor("action_button_border")
}
return UM.Theme.getColor("action_button_disabled_border")
}
color:
{
if (Cura.MachineManager.getExtruder(index).isEnabled)
{
if(control.checked || control.pressed)
{
return UM.Theme.getColor("action_button_active");
}
else if (control.hovered)
{
return UM.Theme.getColor("action_button_hovered")
}
return UM.Theme.getColor("action_button")
}
return UM.Theme.getColor("action_button_disabled")
}
Behavior on color { ColorAnimation { duration: 50; } }
Item
{
id: extruderButtonFace
anchors.centerIn: parent
width: childrenRect.width
Label
{
// Static text that holds the "Extruder" label
id: extruderStaticText
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
color:
{
if (Cura.MachineManager.getExtruder(index).isEnabled)
{
if(control.checked || control.pressed)
{
return UM.Theme.getColor("action_button_active_text");
}
else if (control.hovered)
{
return UM.Theme.getColor("action_button_hovered_text")
}
return UM.Theme.getColor("action_button_text")
}
return UM.Theme.getColor("action_button_disabled_text")
}
font: UM.Theme.getFont("large_nonbold")
text: catalog.i18nc("@label", "Extruder")
visible: width < (control.width - extruderIcon.width - UM.Theme.getSize("default_margin").width)
elide: Text.ElideRight
}
ExtruderIcon
{
// Round icon with the extruder number and material color indicator.
id: extruderIcon
anchors.verticalCenter: parent.verticalCenter
anchors.left: extruderStaticText.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
width: control.height - Math.round(UM.Theme.getSize("default_margin").width / 2)
height: width
checked: control.checked
materialColor: model.color
textColor: extruderStaticText.color
}
}
}
label: Item {}
}
}
}
Item
{
id: materialRow
height: UM.Theme.getSize("print_setup_item").height
visible: Cura.MachineManager.hasMaterials
anchors
{
left: parent.left
right: parent.right
top: extrudersList.bottom
margins: UM.Theme.getSize("thick_margin").width
}
Label
{
id: materialLabel
text: catalog.i18nc("@label", "Material");
width: Math.round(parent.width * 0.45 - UM.Theme.getSize("default_margin").width)
height: parent.height
verticalAlignment: Text.AlignVCenter
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
}
ToolButton
{
id: materialSelection
property var activeExtruder: Cura.MachineManager.activeStack
property var hasActiveExtruder: activeExtruder != null
property var currentRootMaterialName: hasActiveExtruder ? activeExtruder.material.name : ""
text: currentRootMaterialName
tooltip: currentRootMaterialName
visible: Cura.MachineManager.hasMaterials
enabled: !extrudersList.visible || Cura.ExtruderManager.activeExtruderIndex > -1
height: UM.Theme.getSize("setting_control").height
width: Math.round(parent.width * 0.7) + UM.Theme.getSize("thick_margin").width
anchors.right: parent.right
style: UM.Theme.styles.sidebar_header_button
activeFocusOnPress: true;
menu: Cura.MaterialMenu
{
extruderIndex: Cura.ExtruderManager.activeExtruderIndex
}
property var valueError: hasActiveExtruder ? Cura.ContainerManager.getContainerMetaDataEntry(activeExtruder.material.id, "compatible", "") != "True" : true
property var valueWarning: ! Cura.MachineManager.isActiveQualitySupported
}
}
Item
{
id: variantRow
height: UM.Theme.getSize("print_setup_item").height
visible: Cura.MachineManager.hasVariants
anchors
{
left: parent.left
right: parent.right
top: materialRow.bottom
margins: UM.Theme.getSize("thick_margin").width
}
Label
{
id: variantLabel
text: Cura.MachineManager.activeDefinitionVariantsName;
width: Math.round(parent.width * 0.45 - UM.Theme.getSize("default_margin").width)
height: parent.height
verticalAlignment: Text.AlignVCenter
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
}
ToolButton
{
id: variantSelection
text: Cura.MachineManager.activeVariantName
tooltip: Cura.MachineManager.activeVariantName;
visible: Cura.MachineManager.hasVariants
height: UM.Theme.getSize("setting_control").height
width: Math.round(parent.width * 0.7 + UM.Theme.getSize("thick_margin").width)
anchors.right: parent.right
style: UM.Theme.styles.sidebar_header_button
activeFocusOnPress: true;
menu: Cura.NozzleMenu { extruderIndex: Cura.ExtruderManager.activeExtruderIndex }
}
}
Item
{
id: materialCompatibilityLink
height: UM.Theme.getSize("print_setup_item").height
anchors.right: parent.right
anchors.top: variantRow.bottom
anchors.margins: UM.Theme.getSize("thick_margin").width
UM.RecolorImage
{
id: warningImage
anchors.right: materialInfoLabel.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width
source: UM.Theme.getIcon("warning")
width: UM.Theme.getSize("section_icon").width
height: UM.Theme.getSize("section_icon").height
sourceSize.width: width
sourceSize.height: height
color: UM.Theme.getColor("material_compatibility_warning")
visible: !Cura.MachineManager.isCurrentSetupSupported
}
Label
{
id: materialInfoLabel
wrapMode: Text.WordWrap
text: "<a href='%1'>" + catalog.i18nc("@label", "Check compatibility") + "</a>"
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
linkColor: UM.Theme.getColor("text_link")
verticalAlignment: Text.AlignTop
anchors.right: parent.right
MouseArea
{
anchors.fill: parent
onClicked:
{
// open the material URL with web browser
Qt.openUrlExternally("https://ultimaker.com/incoming-links/cura/material-compatibilty");
}
}
}
}
}

View file

@ -0,0 +1,170 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.1
import UM 1.1 as UM
UM.Dialog
{
id: base
//: About dialog title
title: catalog.i18nc("@title:window","About Cura")
minimumWidth: 500 * screenScaleFactor
minimumHeight: 650 * screenScaleFactor
width: minimumWidth
height: minimumHeight
Rectangle
{
width: parent.width + 2 * margin // margin from Dialog.qml
height: version.y + version.height + margin
anchors.top: parent.top
anchors.topMargin: - margin
anchors.horizontalCenter: parent.horizontalCenter
color: UM.Theme.getColor("viewport_background")
}
Image
{
id: logo
width: (base.minimumWidth * 0.85) | 0
height: (width * (1/4.25)) | 0
source: UM.Theme.getImage("logo")
sourceSize.width: width
sourceSize.height: height
anchors.top: parent.top
anchors.topMargin: ((base.minimumWidth - width) / 2) | 0
anchors.horizontalCenter: parent.horizontalCenter
UM.I18nCatalog{id: catalog; name: "cura"}
}
Label
{
id: version
text: catalog.i18nc("@label","version: %1").arg(UM.Application.version)
font: UM.Theme.getFont("large")
color: UM.Theme.getColor("text")
anchors.right : logo.right
anchors.top: logo.bottom
anchors.topMargin: (UM.Theme.getSize("default_margin").height / 2) | 0
}
Label
{
id: description
width: parent.width
//: About dialog application description
text: catalog.i18nc("@label","End-to-end solution for fused filament 3D printing.")
font: UM.Theme.getFont("system")
wrapMode: Text.WordWrap
anchors.top: version.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
}
Label
{
id: creditsNotes
width: parent.width
//: About dialog application author note
text: catalog.i18nc("@info:credit","Cura is developed by Ultimaker B.V. in cooperation with the community.\nCura proudly uses the following open source projects:")
font: UM.Theme.getFont("system")
wrapMode: Text.WordWrap
anchors.top: description.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
}
ScrollView
{
id: credits
anchors.top: creditsNotes.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width
height: base.height - y - (2 * UM.Theme.getSize("default_margin").height + closeButton.height)
ListView
{
id: projectsList
width: parent.width
delegate: Row
{
Label
{
text: "<a href='%1' title='%2'>%2</a>".arg(model.url).arg(model.name)
width: (projectsList.width * 0.25) | 0
elide: Text.ElideRight
onLinkActivated: Qt.openUrlExternally(link)
}
Label
{
text: model.description
elide: Text.ElideRight
width: (projectsList.width * 0.6) | 0
}
Label
{
text: model.license
elide: Text.ElideRight
width: (projectsList.width * 0.15) | 0
}
}
model: ListModel
{
id: projectsModel
}
Component.onCompleted:
{
projectsModel.append({ name: "Cura", description: catalog.i18nc("@label", "Graphical user interface"), license: "LGPLv3", url: "https://github.com/Ultimaker/Cura" });
projectsModel.append({ name: "Uranium", description: catalog.i18nc("@label", "Application framework"), license: "LGPLv3", url: "https://github.com/Ultimaker/Uranium" });
projectsModel.append({ name: "CuraEngine", description: catalog.i18nc("@label", "G-code generator"), license: "AGPLv3", url: "https://github.com/Ultimaker/CuraEngine" });
projectsModel.append({ name: "libArcus", description: catalog.i18nc("@label", "Interprocess communication library"), license: "LGPLv3", url: "https://github.com/Ultimaker/libArcus" });
projectsModel.append({ name: "Python", description: catalog.i18nc("@label", "Programming language"), license: "Python", url: "http://python.org/" });
projectsModel.append({ name: "Qt5", description: catalog.i18nc("@label", "GUI framework"), license: "LGPLv3", url: "https://www.qt.io/" });
projectsModel.append({ name: "PyQt", description: catalog.i18nc("@label", "GUI framework bindings"), license: "GPL", url: "https://riverbankcomputing.com/software/pyqt" });
projectsModel.append({ name: "SIP", description: catalog.i18nc("@label", "C/C++ Binding library"), license: "GPL", url: "https://riverbankcomputing.com/software/sip" });
projectsModel.append({ name: "Protobuf", description: catalog.i18nc("@label", "Data interchange format"), license: "BSD", url: "https://developers.google.com/protocol-buffers" });
projectsModel.append({ name: "SciPy", description: catalog.i18nc("@label", "Support library for scientific computing"), license: "BSD-new", url: "https://www.scipy.org/" });
projectsModel.append({ name: "NumPy", description: catalog.i18nc("@label", "Support library for faster math"), license: "BSD", url: "http://www.numpy.org/" });
projectsModel.append({ name: "NumPy-STL", description: catalog.i18nc("@label", "Support library for handling STL files"), license: "BSD", url: "https://github.com/WoLpH/numpy-stl" });
projectsModel.append({ name: "Shapely", description: catalog.i18nc("@label", "Support library for handling planar objects"), license: "BSD", url: "https://github.com/Toblerity/Shapely" });
projectsModel.append({ name: "Trimesh", description: catalog.i18nc("@label", "Support library for handling triangular meshes"), license: "MIT", url: "https://trimsh.org" });
projectsModel.append({ name: "NetworkX", description: catalog.i18nc("@label", "Support library for analysis of complex networks"), license: "3-clause BSD", url: "https://networkx.github.io/" });
projectsModel.append({ name: "libSavitar", description: catalog.i18nc("@label", "Support library for handling 3MF files"), license: "LGPLv3", url: "https://github.com/ultimaker/libsavitar" });
projectsModel.append({ name: "libCharon", description: catalog.i18nc("@label", "Support library for file metadata and streaming"), license: "LGPLv3", url: "https://github.com/ultimaker/libcharon" });
projectsModel.append({ name: "PySerial", description: catalog.i18nc("@label", "Serial communication library"), license: "Python", url: "http://pyserial.sourceforge.net/" });
projectsModel.append({ name: "python-zeroconf", description: catalog.i18nc("@label", "ZeroConf discovery library"), license: "LGPL", url: "https://github.com/jstasiak/python-zeroconf" });
projectsModel.append({ name: "Clipper", description: catalog.i18nc("@label", "Polygon clipping library"), license: "Boost", url: "http://www.angusj.com/delphi/clipper.php" });
projectsModel.append({ name: "Requests", description: catalog.i18nc("@Label", "Python HTTP library"), license: "GPL", url: "http://docs.python-requests.org" });
projectsModel.append({ name: "Noto Sans", description: catalog.i18nc("@label", "Font"), license: "Apache 2.0", url: "https://www.google.com/get/noto/" });
projectsModel.append({ name: "Font-Awesome-SVG-PNG", description: catalog.i18nc("@label", "SVG icons"), license: "SIL OFL 1.1", url: "https://github.com/encharm/Font-Awesome-SVG-PNG" });
projectsModel.append({ name: "AppImageKit", description: catalog.i18nc("@label", "Linux cross-distribution application deployment"), license: "MIT", url: "https://github.com/AppImage/AppImageKit" });
}
}
}
rightButtons: Button
{
//: Close about dialog button
id: closeButton
text: catalog.i18nc("@action:button","Close");
onClicked: base.visible = false;
}
}

View file

@ -213,28 +213,6 @@ UM.Dialog
PropertyChanges { target: machineButton; opacity: 0; height: 0; } PropertyChanges { target: machineButton; opacity: 0; height: 0; }
} }
transitions:
[
Transition
{
to: "collapsed";
SequentialAnimation
{
NumberAnimation { property: "opacity"; duration: 75; }
NumberAnimation { property: "height"; duration: 75; }
}
},
Transition
{
from: "collapsed";
SequentialAnimation
{
NumberAnimation { property: "height"; duration: 75; }
NumberAnimation { property: "opacity"; duration: 75; }
}
}
]
} }
} }
} }
@ -298,7 +276,6 @@ UM.Dialog
id: machineName id: machineName
text: getMachineName() text: getMachineName()
width: Math.floor(parent.width * 0.75) width: Math.floor(parent.width * 0.75)
implicitWidth: UM.Theme.getSize("standard_list_input").width
maximumLength: 40 maximumLength: 40
//validator: Cura.MachineNameValidator { } //TODO: Gives a segfault in PyQt5.6. For now, we must use a signal on text changed. //validator: Cura.MachineNameValidator { } //TODO: Gives a segfault in PyQt5.6. For now, we must use a signal on text changed.
validator: RegExpValidator validator: RegExpValidator

View file

@ -1,53 +0,0 @@
// Copyright (c) 2015 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import UM 1.1 as UM
UM.Dialog
{
id: dialog;
//: Engine Log dialog title
title: catalog.i18nc("@title:window","Engine Log");
modality: Qt.NonModal;
TextArea
{
id: textArea
anchors.fill: parent;
Timer
{
id: updateTimer;
interval: 1000;
running: false;
repeat: true;
onTriggered: textArea.text = CuraApplication.getEngineLog();
}
UM.I18nCatalog{id: catalog; name:"cura"}
}
rightButtons: Button
{
//: Close engine log button
text: catalog.i18nc("@action:button","Close");
onClicked: dialog.visible = false;
}
onVisibleChanged:
{
if(visible)
{
textArea.text = CuraApplication.getEngineLog();
updateTimer.start();
} else
{
updateTimer.stop();
}
}
}

View file

@ -0,0 +1,196 @@
import QtQuick 2.7
import QtQuick.Controls 2.3
import UM 1.2 as UM
import Cura 1.0 as Cura
import QtGraphicalEffects 1.0 // For the dropshadow
// The expandable component has 3 major sub components:
// * The headerItem; Always visible and should hold some info about what happens if the component is expanded
// * The popupItem; The content that needs to be shown if the component is expanded.
// * The icon; An icon that is displayed on the right of the drawer.
Item
{
id: base
// Enumeration with the different possible alignments of the popup with respect of the headerItem
enum PopupAlignment
{
AlignLeft,
AlignRight
}
// The headerItem holds the QML item that is always displayed.
property alias headerItem: headerItemLoader.sourceComponent
// The popupItem holds the QML item that is shown when the "open" button is pressed
property var popupItem
property color popupBackgroundColor: UM.Theme.getColor("action_button")
property color headerBackgroundColor: UM.Theme.getColor("action_button")
property color headerHoverColor: UM.Theme.getColor("action_button_hovered")
// Defines the alignment of the popup with respect of the headerItem, by default to the right
property int popupAlignment: ExpandableComponent.PopupAlignment.AlignRight
// How much spacing is needed around the popupItem
property alias popupPadding: popup.padding
// How much padding is needed around the header & button
property alias headerPadding: background.padding
// What icon should be displayed on the right.
property alias iconSource: collapseButton.source
property alias iconColor: collapseButton.color
// The icon size (it's always drawn as a square)
property alias iconSize: collapseButton.height
// Is the "drawer" open?
readonly property alias expanded: popup.visible
property alias expandedHighlightColor: expandedHighlight.color
// What should the radius of the header be. This is also influenced by the headerCornerSide
property alias headerRadius: background.radius
// On what side should the header corners be shown? 1 is down, 2 is left, 3 is up and 4 is right.
property alias headerCornerSide: background.cornerSide
property alias headerShadowColor: shadow.color
property alias enableHeaderShadow: shadow.visible
property int shadowOffset: 2
function togglePopup()
{
if(popup.visible)
{
popup.close()
}
else
{
popup.open()
}
}
onPopupItemChanged:
{
// Since we want the size of the popup to be set by the size of the content,
// we need to do it like this.
popup.width = popupItem.width + 2 * popup.padding
popup.height = popupItem.height + 2 * popup.padding
popup.contentItem = popupItem
}
Connections
{
// Since it could be that the popup is dynamically populated, we should also take these changes into account.
target: popupItem
onWidthChanged: popup.width = popupItem.width + 2 * popup.padding
onHeightChanged: popup.height = popupItem.height + 2 * popup.padding
}
implicitHeight: 100 * screenScaleFactor
implicitWidth: 400 * screenScaleFactor
RoundedRectangle
{
id: background
property real padding: UM.Theme.getSize("default_margin").width
color: headerBackgroundColor
anchors.fill: parent
Loader
{
id: headerItemLoader
anchors
{
left: parent.left
right: collapseButton.visible ? collapseButton.left : parent.right
top: parent.top
bottom: parent.bottom
margins: background.padding
}
}
// A highlight that is shown when the popup is expanded
Rectangle
{
id: expandedHighlight
width: parent.width
height: UM.Theme.getSize("thick_lining").height
color: UM.Theme.getColor("primary")
visible: expanded
anchors.bottom: parent.bottom
}
UM.RecolorImage
{
id: collapseButton
anchors
{
right: parent.right
verticalCenter: parent.verticalCenter
margins: background.padding
}
sourceSize.width: width
sourceSize.height: height
visible: source != ""
width: height
height: Math.round(0.2 * base.height)
color: UM.Theme.getColor("text")
}
MouseArea
{
id: mouseArea
anchors.fill: parent
onClicked: togglePopup()
hoverEnabled: true
onEntered: background.color = headerHoverColor
onExited: background.color = headerBackgroundColor
}
}
DropShadow
{
id: shadow
// Don't blur the shadow
radius: 0
anchors.fill: background
source: background
verticalOffset: base.shadowOffset
visible: true
color: UM.Theme.getColor("action_button_shadow")
// Should always be drawn behind the background.
z: background.z - 1
}
Popup
{
id: popup
// Ensure that the popup is located directly below the headerItem
y: headerItemLoader.height + 2 * background.padding + base.shadowOffset
// Make the popup aligned with the rest, using the property popupAlignment to decide whether is right or left.
// In case of right alignment, the 3x padding is due to left, right and padding between the button & text.
x: popupAlignment == ExpandableComponent.PopupAlignment.AlignRight ? -width + collapseButton.width + headerItemLoader.width + 3 * background.padding : 0
padding: UM.Theme.getSize("default_margin").width
closePolicy: Popup.CloseOnPressOutsideParent
background: Cura.RoundedRectangle
{
cornerSide: Cura.RoundedRectangle.Direction.Down
color: popupBackgroundColor
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
radius: UM.Theme.getSize("default_radius").width
}
}
}

View file

@ -2,80 +2,32 @@
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 2.0
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Button Cura.ToolbarButton
{ {
id: base id: base
property var extruder; property var extruder
text: catalog.i18ncp("@label %1 is filled in with the name of an extruder", "Print Selected Model with %1", "Print Selected Models with %1", UM.Selection.selectionCount).arg(extruder.name) text: catalog.i18ncp("@label %1 is filled in with the name of an extruder", "Print Selected Model with %1", "Print Selected Models with %1", UM.Selection.selectionCount).arg(extruder.name)
style: UM.Theme.styles.tool_button;
iconSource: UM.Theme.getIcon("extruder_button")
checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(extruder.id) != -1 checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(extruder.id) != -1
enabled: UM.Selection.hasSelection && extruder.stack.isEnabled enabled: UM.Selection.hasSelection && extruder.stack.isEnabled
property color customColor: base.hovered ? UM.Theme.getColor("button_hover") : UM.Theme.getColor("button"); toolItem: ExtruderIcon
Rectangle
{ {
anchors.fill: parent materialColor: extruder.color
anchors.margins: UM.Theme.getSize("default_lining").width; extruderEnabled: extruder.stack.isEnabled
property int index: extruder.index
color: "transparent"
border.width: base.checked ? UM.Theme.getSize("default_lining").width : 0;
border.color: UM.Theme.getColor("button_text")
}
Item
{
anchors.centerIn: parent
width: UM.Theme.getSize("default_margin").width
height: UM.Theme.getSize("default_margin").height
Label
{
anchors.centerIn: parent;
text: index + 1;
color: parent.enabled ? UM.Theme.getColor("button_text") : UM.Theme.getColor("button_disabled_text")
font: UM.Theme.getFont("default_bold");
}
}
// Material colour circle
// Only draw the filling colour of the material inside the SVG border.
Rectangle
{
anchors
{
right: parent.right
top: parent.top
rightMargin: UM.Theme.getSize("extruder_button_material_margin").width
topMargin: UM.Theme.getSize("extruder_button_material_margin").height
}
color: model.color
width: UM.Theme.getSize("extruder_button_material").width
height: UM.Theme.getSize("extruder_button_material").height
radius: Math.round(width / 2)
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("extruder_button_material_border")
opacity: !base.enabled ? 0.2 : 1.0
} }
onClicked: onClicked:
{ {
forceActiveFocus() //First grab focus, so all the text fields are updated forceActiveFocus() //First grab focus, so all the text fields are updated
CuraActions.setExtruderForSelection(extruder.id); CuraActions.setExtruderForSelection(extruder.id)
} }
} }

View file

@ -0,0 +1,72 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 1.1
import UM 1.2 as UM
Item
{
id: extruderIconItem
implicitWidth: UM.Theme.getSize("extruder_icon").width
implicitHeight: UM.Theme.getSize("extruder_icon").height
property bool checked: true
property color materialColor
property alias textColor: extruderNumberText.color
property bool extruderEnabled: true
UM.RecolorImage
{
id: mainIcon
anchors.fill: parent
sourceSize.width: parent.width
sourceSize.height: parent.height
source: UM.Theme.getIcon("extruder_button")
color: extruderEnabled ? materialColor: "gray"
}
Rectangle
{
id: extruderNumberCircle
width: height
height: Math.round(parent.height / 2)
radius: Math.round(width / 2)
color: UM.Theme.getColor("toolbar_background")
anchors
{
horizontalCenter: parent.horizontalCenter
top: parent.top
// The circle needs to be slightly off center (so it sits in the middle of the square bit of the icon)
topMargin: (parent.height - height) / 2 - 0.1 * parent.height
}
Label
{
id: extruderNumberText
anchors.centerIn: parent
text: index + 1
font: UM.Theme.getFont("extruder_icon")
visible: extruderEnabled
renderType: Text.NativeRendering
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
UM.RecolorImage
{
id: disabledIcon
anchors.fill: parent
anchors.margins: UM.Theme.getSize("thick_lining").width
sourceSize.width: width
sourceSize.height: width
source: UM.Theme.getIcon("cross1")
visible: !extruderEnabled
color: "black"
}
}
}

View file

@ -0,0 +1,54 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
import UM 1.1 as UM
// This item will show a label with a squared icon in the left
Item
{
id: container
property alias text: label.text
property alias source: icon.source
property alias color: label.color
property alias font: label.font
property alias iconSize: icon.width
implicitHeight: icon.height
UM.RecolorImage
{
id: icon
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
source: ""
width: UM.Theme.getSize("section_icon").width
height: width
sourceSize.width: width
sourceSize.height: height
color: label.color
visible: source != ""
}
Label
{
id: label
anchors.left: icon.visible ? icon.right : parent.left
anchors.right: parent.right
anchors.leftMargin: UM.Theme.getSize("thin_margin").width
anchors.verticalCenter: icon.verticalCenter
text: "Empty label"
elide: Text.ElideRight
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("very_small")
renderType: Text.NativeRendering
}
}

View file

@ -0,0 +1,70 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
import UM 1.2 as UM
import Cura 1.0 as Cura
// Reusable component that holds an (re-colorable) icon on the left with some text on the right.
// This component is also designed to be used with layouts. It will use the width of the text + icon as preferred width
// It sets the icon size + half of the content as its minium width (in which case it will elide the text)
Item
{
property alias iconColor: icon.color
property alias source: icon.source
property alias text: label.text
property real margin: UM.Theme.getSize("narrow_margin").width
// These properties can be used in combination with layouts.
readonly property real contentWidth: icon.width + margin + label.contentWidth
readonly property real minContentWidth: Math.round(icon.width + margin + 0.5 * label.contentWidth)
Layout.minimumWidth: minContentWidth
Layout.preferredWidth: contentWidth
Layout.fillHeight: true
Layout.fillWidth: true
implicitWidth: icon.width + 100
implicitHeight: icon.height
UM.RecolorImage
{
id: icon
width: UM.Theme.getSize("section_icon").width
height: UM.Theme.getSize("section_icon").height
sourceSize.width: width
sourceSize.height: height
color: "black"
anchors
{
left: parent.left
verticalCenter: parent.verticalCenter
}
}
Label
{
id: label
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
renderType: Text.NativeRendering
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
anchors
{
left: icon.right
right: parent.right
top: parent.top
bottom: parent.bottom
rightMargin: 0
margins: margin
}
}
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2017 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
@ -15,7 +15,7 @@ Item {
property bool activity: CuraApplication.platformActivity property bool activity: CuraApplication.platformActivity
property string fileBaseName: PrintInformation.baseName property string fileBaseName: PrintInformation.baseName
UM.I18nCatalog { id: catalog; name:"cura"} UM.I18nCatalog { id: catalog; name: "cura"}
height: childrenRect.height height: childrenRect.height

View file

@ -1,86 +0,0 @@
// Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
import "Menus"
ToolButton
{
id: base
property bool isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != ""
property bool printerConnected: Cura.MachineManager.printerConnected
property var printerStatus: Cura.MachineManager.printerConnected ? "connected" : "disconnected"
text: isNetworkPrinter ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName
tooltip: Cura.MachineManager.activeMachineName
style: ButtonStyle
{
background: Rectangle
{
color:
{
if (control.pressed) {
return UM.Theme.getColor("sidebar_header_active");
}
else if (control.hovered) {
return UM.Theme.getColor("sidebar_header_hover");
}
else {
return UM.Theme.getColor("sidebar_header_bar");
}
}
Behavior on color { ColorAnimation { duration: 50; } }
UM.RecolorImage
{
id: downArrow
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
width: UM.Theme.getSize("standard_arrow").width
height: UM.Theme.getSize("standard_arrow").height
sourceSize.width: width
sourceSize.height: width
color: UM.Theme.getColor("text_emphasis")
source: UM.Theme.getIcon("arrow_bottom")
}
PrinterStatusIcon
{
id: printerStatusIcon
visible: printerConnected || isNetworkPrinter
status: printerStatus
anchors
{
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: UM.Theme.getSize("sidebar_margin").width
}
}
Label
{
id: sidebarComboBoxLabel
color: UM.Theme.getColor("sidebar_header_text_active")
text: control.text;
elide: Text.ElideRight;
anchors.left: printerStatusIcon.visible ? printerStatusIcon.right : parent.left;
anchors.leftMargin: printerStatusIcon.visible ? UM.Theme.getSize("sidebar_lining").width : UM.Theme.getSize("sidebar_margin").width
anchors.right: downArrow.left;
anchors.rightMargin: control.rightMargin;
anchors.verticalCenter: parent.verticalCenter;
font: UM.Theme.getFont("medium_bold")
}
}
label: Label {}
}
menu: PrinterMenu { }
}

View file

@ -0,0 +1,171 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura 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 QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.2
import UM 1.3 as UM
import Cura 1.1 as Cura
import "../Menus"
import "../Dialogs"
Item
{
id: menu
width: applicationMenu.width
height: applicationMenu.height
property alias window: applicationMenu.window
UM.ApplicationMenu
{
id: applicationMenu
FileMenu { title: catalog.i18nc("@title:menu menubar:toplevel", "&File") }
Menu
{
title: catalog.i18nc("@title:menu menubar:toplevel", "&Edit")
MenuItem { action: Cura.Actions.undo }
MenuItem { action: Cura.Actions.redo }
MenuSeparator { }
MenuItem { action: Cura.Actions.selectAll }
MenuItem { action: Cura.Actions.arrangeAll }
MenuItem { action: Cura.Actions.deleteSelection }
MenuItem { action: Cura.Actions.deleteAll }
MenuItem { action: Cura.Actions.resetAllTranslation }
MenuItem { action: Cura.Actions.resetAll }
MenuSeparator { }
MenuItem { action: Cura.Actions.groupObjects }
MenuItem { action: Cura.Actions.mergeObjects }
MenuItem { action: Cura.Actions.unGroupObjects }
}
ViewMenu { title: catalog.i18nc("@title:menu menubar:toplevel", "&View") }
SettingsMenu { title: catalog.i18nc("@title:menu menubar:toplevel", "&Settings") }
Menu
{
id: extensionMenu
title: catalog.i18nc("@title:menu menubar:toplevel", "E&xtensions")
Instantiator
{
id: extensions
model: UM.ExtensionModel { }
Menu
{
id: sub_menu
title: model.name;
visible: actions != null
enabled: actions != null
Instantiator
{
model: actions
MenuItem
{
text: model.text
onTriggered: extensions.model.subMenuTriggered(name, model.text)
}
onObjectAdded: sub_menu.insertItem(index, object)
onObjectRemoved: sub_menu.removeItem(object)
}
}
onObjectAdded: extensionMenu.insertItem(index, object)
onObjectRemoved: extensionMenu.removeItem(object)
}
}
Menu
{
id: plugin_menu
title: catalog.i18nc("@title:menu menubar:toplevel", "&Marketplace")
MenuItem { action: Cura.Actions.browsePackages }
}
Menu
{
id: preferencesMenu
title: catalog.i18nc("@title:menu menubar:toplevel", "P&references")
MenuItem { action: Cura.Actions.preferences }
}
Menu
{
id: helpMenu
title: catalog.i18nc("@title:menu menubar:toplevel", "&Help")
MenuItem { action: Cura.Actions.showProfileFolder }
MenuItem { action: Cura.Actions.documentation }
MenuItem { action: Cura.Actions.reportBug }
MenuSeparator { }
MenuItem { action: Cura.Actions.about }
}
}
// ###############################################################################################
// Definition of other components that are linked to the menus
// ###############################################################################################
WorkspaceSummaryDialog
{
id: saveWorkspaceDialog
property var args
onYes: UM.OutputDeviceManager.requestWriteToDevice("local_file", PrintInformation.jobName, args)
}
MessageDialog
{
id: newProjectDialog
modality: Qt.ApplicationModal
title: catalog.i18nc("@title:window", "New project")
text: catalog.i18nc("@info:question", "Are you sure you want to start a new project? This will clear the build plate and any unsaved settings.")
standardButtons: StandardButton.Yes | StandardButton.No
icon: StandardIcon.Question
onYes:
{
CuraApplication.deleteAll();
Cura.Actions.resetProfile.trigger();
}
}
UM.ExtensionModel
{
id: curaExtensions
}
// ###############################################################################################
// Definition of all the connections
// ###############################################################################################
Connections
{
target: Cura.Actions.newProject
onTriggered:
{
if(Printer.platformActivity || Cura.MachineManager.hasUserSettings)
{
newProjectDialog.visible = true
}
}
}
// show the plugin browser dialog
Connections
{
target: Cura.Actions.browsePackages
onTriggered:
{
curaExtensions.callExtensionMethod("Toolbox", "browsePackages")
}
}
}

View file

@ -0,0 +1,146 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.0 as Controls2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.1
import UM 1.4 as UM
import Cura 1.0 as Cura
import QtGraphicalEffects 1.0
import "../Account"
Rectangle
{
id: base
implicitHeight: UM.Theme.getSize("main_window_header").height
implicitWidth: UM.Theme.getSize("main_window_header").width
LinearGradient
{
anchors.fill: parent
start: Qt.point(0, 0)
end: Qt.point(parent.width, 0)
gradient: Gradient
{
GradientStop
{
position: 0.0
color: UM.Theme.getColor("main_window_header_background")
}
GradientStop
{
position: 0.5
color: UM.Theme.getColor("main_window_header_background_gradient")
}
GradientStop
{
position: 1.0
color: UM.Theme.getColor("main_window_header_background")
}
}
}
Image
{
id: logo
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter
source: UM.Theme.getImage("logo")
width: UM.Theme.getSize("logo").width
height: UM.Theme.getSize("logo").height
sourceSize.width: width
sourceSize.height: height
}
Row
{
id: stagesListContainer
spacing: Math.round(UM.Theme.getSize("default_margin").width / 2)
anchors
{
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
leftMargin: UM.Theme.getSize("default_margin").width
}
// The main window header is dynamically filled with all available stages
Repeater
{
id: stagesHeader
model: UM.StageModel { }
delegate: Button
{
text: model.name.toUpperCase()
checkable: true
checked: model.active
anchors.verticalCenter: parent.verticalCenter
exclusiveGroup: mainWindowHeaderMenuGroup
style: UM.Theme.styles.main_window_header_tab
height: UM.Theme.getSize("main_window_header_button").height
onClicked: UM.Controller.setActiveStage(model.id)
iconSource: model.stage.iconSource
property color overlayColor: "transparent"
property string overlayIconSource: ""
}
}
ExclusiveGroup { id: mainWindowHeaderMenuGroup }
}
// Shortcut button to quick access the Toolbox
Controls2.Button
{
id: marketplaceButton
text: catalog.i18nc("@action:button", "Marketplace")
height: Math.round(0.5 * UM.Theme.getSize("main_window_header").height)
onClicked: Cura.Actions.browsePackages.trigger()
hoverEnabled: true
background: Rectangle
{
radius: UM.Theme.getSize("action_button_radius").width
color: marketplaceButton.hovered ? UM.Theme.getColor("primary_text") : UM.Theme.getColor("main_window_header_background")
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("primary_text")
}
contentItem: Label
{
id: label
text: marketplaceButton.text
color: marketplaceButton.hovered ? UM.Theme.getColor("main_window_header_background") : UM.Theme.getColor("primary_text")
width: contentWidth
verticalAlignment: Text.AlignVCenter
renderType: Text.NativeRendering
}
anchors
{
right: accountWidget.left
rightMargin: UM.Theme.getSize("default_margin").width
verticalCenter: parent.verticalCenter
}
}
AccountWidget
{
id: accountWidget
anchors
{
right: parent.right
rightMargin: UM.Theme.getSize("default_margin").width
}
}
}

View file

@ -63,7 +63,7 @@ Rectangle
visible: buildplateInformation.visible visible: buildplateInformation.visible
width: parent.width - 2 * parent.padding width: parent.width - 2 * parent.padding
height: visible ? Math.round(UM.Theme.getSize("sidebar_lining_thin").height / 2) : 0 height: visible ? Math.round(UM.Theme.getSize("thick_lining").height / 2) : 0
color: textColor color: textColor
} }
@ -77,8 +77,8 @@ Rectangle
UM.RecolorImage { UM.RecolorImage {
id: buildplateIcon id: buildplateIcon
anchors.left: parent.left anchors.left: parent.left
width: UM.Theme.getSize("topbar_button_icon").width width: UM.Theme.getSize("main_window_header_button_icon").width
height: UM.Theme.getSize("topbar_button_icon").height height: UM.Theme.getSize("main_window_header_button_icon").height
sourceSize.width: width sourceSize.width: width
sourceSize.height: height sourceSize.height: height
source: UM.Theme.getIcon("buildplate") source: UM.Theme.getIcon("buildplate")
@ -110,7 +110,7 @@ Rectangle
parent.border.color = UM.Theme.getColor("configuration_item_border_hover") parent.border.color = UM.Theme.getColor("configuration_item_border_hover")
if (configurationItem.selected == false) if (configurationItem.selected == false)
{ {
configurationItem.color = UM.Theme.getColor("sidebar_lining") configurationItem.color = UM.Theme.getColor("wide_lining")
} }
} }
onExited: onExited:

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