Merge branch 'master' of https://github.com/Ultimaker/Cura into master-using-platform

This commit is contained in:
Thomas Karl Pietrowski 2016-06-15 14:59:34 +02:00
commit 536e0f489a
33 changed files with 531 additions and 255 deletions

@ -199,7 +199,6 @@ class BuildVolume(SceneNode):
disallowed_areas = self._active_container_stack.getProperty("machine_disallowed_areas", "value")
areas = []
skirt_size = 0.0
skirt_size = self._getSkirtSize(self._active_container_stack)
if disallowed_areas:

@ -5,17 +5,33 @@ import webbrowser
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, QCoreApplication
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit
from UM.Logger import Logger
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
# List of exceptions that should be considered "fatal" and abort the program.
# These are primarily some exception types that we simply cannot really recover from
# (MemoryError and SystemError) and exceptions that indicate grave errors in the
# code that cause the Python interpreter to fail (SyntaxError, ImportError).
fatal_exception_types = [
MemoryError,
SyntaxError,
ImportError,
SystemError,
]
def show(exception_type, value, tb):
debug_mode = False
if QCoreApplication.instance():
debug_mode = QCoreApplication.instance().getCommandLineOption("debug-mode", False)
traceback.print_exception(exception_type, value, tb)
Logger.log("c", "An uncaught exception has occurred!")
for line in traceback.format_exception(exception_type, value, tb):
for part in line.rstrip("\n").split("\n"):
Logger.log("c", part)
if not debug_mode:
if not debug_mode and exception_type not in fatal_exception_types:
return
application = QCoreApplication.instance()
@ -29,7 +45,7 @@ def show(exception_type, value, tb):
label = QLabel(dialog)
layout.addWidget(label)
label.setText(catalog.i18nc("@label", "<p>An uncaught exception has occurred!</p><p>Please use the information below to post a bug report at <a href=\"http://github.com/Ultimaker/Cura/issues\">http://github.com/Ultimaker/Cura/issues</a></p>"))
label.setText(catalog.i18nc("@label", "<p>A fatal exception has occurred that we could not recover from!</p><p>Please use the information below to post a bug report at <a href=\"http://github.com/Ultimaker/Cura/issues\">http://github.com/Ultimaker/Cura/issues</a></p>"))
textarea = QTextEdit(dialog)
layout.addWidget(textarea)

@ -0,0 +1,208 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
import os
import os.path
import re
from PyQt5.QtWidgets import QMessageBox
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Application import Application
from UM.Logger import Logger
from UM.Message import Message
from UM.Platform import Platform
from UM.PluginRegistry import PluginRegistry #For getting the possible profile writers to write with.
from UM.Util import parseBool
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
class CuraContainerRegistry(ContainerRegistry):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
## Create a name that is not empty and unique
# \param container_type \type{string} Type of the container (machine, quality, ...)
# \param current_name \type{} Current name of the container, which may be an acceptable option
# \param new_name \type{string} Base name, which may not be unique
# \param fallback_name \type{string} Name to use when (stripped) new_name is empty
# \return \type{string} Name that is unique for the specified type and name/id
def createUniqueName(self, container_type, current_name, new_name, fallback_name):
new_name = new_name.strip()
num_check = re.compile("(.*?)\s*#\d+$").match(new_name)
if num_check:
new_name = num_check.group(1)
if new_name == "":
new_name = fallback_name
unique_name = new_name
i = 1
# In case we are renaming, the current name of the container is also a valid end-result
while self._containerExists(container_type, unique_name) and unique_name != current_name:
i += 1
unique_name = "%s #%d" % (new_name, i)
return unique_name
## Check if a container with of a certain type and a certain name or id exists
# Both the id and the name are checked, because they may not be the same and it is better if they are both unique
# \param container_type \type{string} Type of the container (machine, quality, ...)
# \param container_name \type{string} Name to check
def _containerExists(self, container_type, container_name):
container_class = ContainerStack if container_type == "machine" else InstanceContainer
return self.findContainers(container_class, id = container_name, type = container_type) or \
self.findContainers(container_class, name = container_name, type = container_type)
## Exports an profile to a file
#
# \param instance_id \type{str} the ID of the profile to export.
# \param file_name \type{str} the full path and filename to export to.
# \param file_type \type{str} the file type with the format "<description> (*.<extension>)"
def exportProfile(self, instance_id, file_name, file_type):
Logger.log('d', 'exportProfile instance_id: '+str(instance_id))
# Parse the fileType to deduce what plugin can save the file format.
# fileType has the format "<description> (*.<extension>)"
split = file_type.rfind(" (*.") # Find where the description ends and the extension starts.
if split < 0: # Not found. Invalid format.
Logger.log("e", "Invalid file format identifier %s", file_type)
return
description = file_type[:split]
extension = file_type[split + 4:-1] # Leave out the " (*." and ")".
if not file_name.endswith("." + extension): # Auto-fill the extension if the user did not provide any.
file_name += "." + extension
# On Windows, QML FileDialog properly asks for overwrite confirm, but not on other platforms, so handle those ourself.
if not Platform.isWindows():
if os.path.exists(file_name):
result = QMessageBox.question(None, catalog.i18nc("@title:window", "File Already Exists"),
catalog.i18nc("@label", "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?").format(file_name))
if result == QMessageBox.No:
return
containers = ContainerRegistry.getInstance().findInstanceContainers(id=instance_id)
if not containers:
return
container = containers[0]
profile_writer = self._findProfileWriter(extension, description)
try:
success = profile_writer.write(file_name, container)
except Exception as e:
Logger.log("e", "Failed to export profile to %s: %s", file_name, str(e))
m = Message(catalog.i18nc("@info:status", "Failed to export profile to <filename>{0}</filename>: <message>{1}</message>", file_name, str(e)), lifetime = 0)
m.show()
return
if not success:
Logger.log("w", "Failed to export profile to %s: Writer plugin reported failure.", file_name)
m = Message(catalog.i18nc("@info:status", "Failed to export profile to <filename>{0}</filename>: Writer plugin reported failure.", file_name), lifetime = 0)
m.show()
return
m = Message(catalog.i18nc("@info:status", "Exported profile to <filename>{0}</filename>", file_name))
m.show()
## Gets the plugin object matching the criteria
# \param extension
# \param description
# \return The plugin object matching the given extension and description.
def _findProfileWriter(self, extension, description):
pr = PluginRegistry.getInstance()
for plugin_id, meta_data in self._getIOPlugins("profile_writer"):
for supported_type in meta_data["profile_writer"]: # All file types this plugin can supposedly write.
supported_extension = supported_type.get("extension", None)
if supported_extension == extension: # This plugin supports a file type with the same extension.
supported_description = supported_type.get("description", None)
if supported_description == description: # The description is also identical. Assume it's the same file type.
return pr.getPluginObject(plugin_id)
return None
## Imports a profile from a file
#
# \param file_name \type{str} the full path and filename of the profile to import
# \return \type{Dict} dict with a 'status' key containing the string 'ok' or 'error', and a 'message' key
# containing a message for the user
def importProfile(self, file_name):
if not file_name:
return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path")}
pr = PluginRegistry.getInstance()
for plugin_id, meta_data in self._getIOPlugins("profile_reader"):
profile_reader = pr.getPluginObject(plugin_id)
try:
profile = profile_reader.read(file_name) #Try to open the file with the profile reader.
except Exception as e:
#Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None.
Logger.log("e", "Failed to import profile from %s: %s", file_name, str(e))
return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e))}
if profile: #Success!
profile.setReadOnly(False)
new_name = self.createUniqueName("quality", "", os.path.splitext(os.path.basename(file_name))[0],
catalog.i18nc("@label", "Custom profile"))
profile.setName(new_name)
if self._machineHasOwnQualities():
profile.setDefinition(self._activeDefinition())
if self._machineHasOwnMaterials():
profile.addMetaDataEntry("material", self._activeMaterialId())
else:
profile.setDefinition(ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0])
ContainerRegistry.getInstance().addContainer(profile)
return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) }
#If it hasn't returned by now, none of the plugins loaded the profile successfully.
return { "status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type.", file_name)}
## Gets a list of profile writer plugins
# \return List of tuples of (plugin_id, meta_data).
def _getIOPlugins(self, io_type):
pr = PluginRegistry.getInstance()
active_plugin_ids = pr.getActivePlugins()
result = []
for plugin_id in active_plugin_ids:
meta_data = pr.getMetaData(plugin_id)
if io_type in meta_data:
result.append( (plugin_id, meta_data) )
return result
## Gets the active definition
# \return the active definition object or None if there is no definition
def _activeDefinition(self):
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
definition = global_container_stack.getBottom()
if definition:
return definition
return None
## Returns true if the current machine requires its own materials
# \return True if the current machine requires its own materials
def _machineHasOwnMaterials(self):
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
return global_container_stack.getMetaDataEntry("has_materials", False)
return False
## Gets the ID of the active material
# \return the ID of the active material or the empty string
def _activeMaterialId(self):
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
material = global_container_stack.findContainer({"type": "material"})
if material:
return material.getId()
return ""
## Returns true if the current machien requires its own quality profiles
# \return true if the current machien requires its own quality profiles
def _machineHasOwnQualities(self):
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
return parseBool(global_container_stack.getMetaDataEntry("has_machine_quality", False))
return False

@ -18,7 +18,7 @@ class ExtruderManager(QObject):
## Notify when the user switches the currently active extruder.
activeExtruderChanged = pyqtSignal()
## Registers listeners and such to listen to chafnges to the extruders.
## Registers listeners and such to listen to changes to the extruders.
def __init__(self, parent = None):
super().__init__(parent)
self._extruder_trains = { } #Per machine, a dictionary of extruder container stack IDs.
@ -67,12 +67,14 @@ class ExtruderManager(QObject):
self.activeExtruderChanged.emit()
def getActiveExtruderStack(self):
try:
return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getBottom().getId()][str(self._active_extruder_index)]
except AttributeError:
return None
except KeyError:
return None
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
if global_container_stack:
global_definition_container = UM.Application.getInstance().getGlobalContainerStack().getBottom()
if global_definition_container:
if global_definition_container.getId() in self._extruder_trains:
if str(self._active_extruder_index) in self._extruder_trains[global_definition_container.getId()]:
return self._extruder_trains[global_definition_container.getId()][str(self._active_extruder_index)]
## Adds all extruders of a specific machine definition to the extruder
# manager.
@ -100,7 +102,7 @@ class ExtruderManager(QObject):
for extruder_train in extruder_trains:
self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train
## Ensure that the extruder train stacks are linked to global stack.
#Ensure that the extruder train stacks are linked to global stack.
extruder_train.setNextStack(UM.Application.getInstance().getGlobalContainerStack())
if extruder_trains:
@ -180,7 +182,7 @@ class ExtruderManager(QObject):
quality = qualities[0]
preferred_quality_id = machine_definition.getMetaDataEntry("preferred_quality")
if preferred_quality_id:
preferred_quality = container_registry.findInstanceContainers(id = preferred_quality_id.lower(), type = "quality")
preferred_quality = container_registry.findInstanceContainers(id = preferred_quality_id, type = "quality")
if len(preferred_quality) >= 1:
quality = preferred_quality[0]
else:

@ -28,9 +28,9 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
# containers.
IndexRole = Qt.UserRole + 4
## Colour 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.
defaultColour = "#FFFF00"
defaultColours = ["#ffc924", "#86ec21", "#22eeee", "#245bff", "#9124ff", "#ff24c8"]
## Initialises the extruders model, defining the roles and listening for
# changes in the data.
@ -75,7 +75,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
if self._add_global:
material = global_container_stack.findContainer({ "type": "material" })
colour = material.getMetaDataEntry("color_code", default = self.defaultColour) if material else self.defaultColour
colour = material.getMetaDataEntry("color_code", default = self.defaultColours[0]) if material else self.defaultColours[0]
item = {
"id": global_container_stack.getId(),
"name": "Global",
@ -86,12 +86,13 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
for extruder in manager.getMachineExtruders(global_container_stack.getBottom().getId()):
material = extruder.findContainer({ "type": "material" })
colour = material.getMetaDataEntry("color_code", default = self.defaultColour) if material else self.defaultColour
position = extruder.getBottom().getMetaDataEntry("position", default = "0") #Position in the definition.
try:
position = int(position)
except ValueError: #Not a proper int.
position = -1
default_colour = self.defaultColours[position] if position >= 0 and position < len(self.defaultColours) else defaultColours[0]
colour = material.getMetaDataEntry("color_code", default = default_colour) if material else default_colour
item = { #Construct an item with only the relevant information.
"id": extruder.getId(),
"name": extruder.getName(),

@ -1,5 +1,5 @@
import re
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal
from UM.Application import Application
@ -8,6 +8,8 @@ from UM.Preferences import Preferences
import UM.Settings
from UM.Settings.Validator import ValidatorState
from UM.Settings.InstanceContainer import InstanceContainer
from cura.PrinterOutputDevice import PrinterOutputDevice
from UM.Settings.ContainerStack import ContainerStack
from . import ExtruderManager
from UM.i18n import i18nCatalog
@ -49,6 +51,8 @@ class MachineManagerModel(QObject):
active_machine_id = Preferences.getInstance().getValue("cura/active_machine")
Application.getInstance().getOutputDeviceManager().outputDevicesChanged.connect(self._onOutputDevicesChanged)
if active_machine_id != "":
# An active machine was saved, so restore it.
self.setActiveMachine(active_machine_id)
@ -61,16 +65,14 @@ class MachineManagerModel(QObject):
activeStackChanged = pyqtSignal()
globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed.
globalValidationChanged = pyqtSignal() # Emitted whenever a validation inside global container is changed.
globalValidationChanged = pyqtSignal() # Emitted whenever a validation inside global container is changed
@pyqtProperty("QVariantMap", notify = globalContainerChanged)
def extrudersIds(self):
## Find all extruders that reference the new stack
extruders = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(**{"machine": self._global_container_stack.getId()})
result = {}
for extruder in extruders:
result[extruder.getMetaDataEntry("position")] = extruder.getId()
return result
blurSettings = pyqtSignal() # Emitted to force fields in the advanced sidebar to un-focus, so they update properly
outputDevicesChanged = pyqtSignal()
def _onOutputDevicesChanged(self):
self.outputDevicesChanged.emit()
def _onGlobalPropertyChanged(self, key, property_name):
if property_name == "value":
@ -102,8 +104,15 @@ class MachineManagerModel(QObject):
self._global_stack_valid = not self._checkStackForErrors(self._global_container_stack)
def _onActiveExtruderStackChanged(self):
if self._active_container_stack and self._active_container_stack != self._global_container_stack:
self._active_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged)
self._active_container_stack.propertyChanged.disconnect(self._onGlobalPropertyChanged)
self._active_container_stack = ExtruderManager.ExtruderManager.getInstance().getActiveExtruderStack()
if not self._active_container_stack:
if self._active_container_stack:
self._active_container_stack.containersChanged.connect(self._onInstanceContainersChanged)
self._active_container_stack.propertyChanged.connect(self._onGlobalPropertyChanged)
else:
self._active_container_stack = self._global_container_stack
def _onInstanceContainersChanged(self, container):
@ -155,6 +164,10 @@ class MachineManagerModel(QObject):
Application.getInstance().setGlobalContainerStack(new_global_stack)
@pyqtProperty("QVariantList", notify = outputDevicesChanged)
def printerOutputDevices(self):
return [printer_output_device for printer_output_device in Application.getInstance().getOutputDeviceManager().getOutputDevices() if isinstance(printer_output_device, PrinterOutputDevice)]
## Create a name that is not empty and unique
# \param container_type \type{string} Type of the container (machine, quality, ...)
# \param current_name \type{} Current name of the container, which may be an acceptable option
@ -162,31 +175,7 @@ class MachineManagerModel(QObject):
# \param fallback_name \type{string} Name to use when (stripped) new_name is empty
# \return \type{string} Name that is unique for the specified type and name/id
def _createUniqueName(self, container_type, current_name, new_name, fallback_name):
new_name = new_name.strip()
num_check = re.compile("(.*?)\s*#\d+$").match(new_name)
if num_check:
new_name = num_check.group(1)
if new_name == "":
new_name = fallback_name
unique_name = new_name
i = 1
# In case we are renaming, the current name of the container is also a valid end-result
while self._containerExists(container_type, unique_name) and unique_name != current_name:
i += 1
unique_name = "%s #%d" % (new_name, i)
return unique_name
## Check if a container with of a certain type and a certain name or id exists
# Both the id and the name are checked, because they may not be the same and it is better if they are both unique
# \param container_type \type{string} Type of the container (machine, quality, ...)
# \param container_name \type{string} Name to check
def _containerExists(self, container_type, container_name):
container_class = ContainerStack if container_type == "machine" else InstanceContainer
return UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, id = container_name, type = container_type) or \
UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, name = container_name, type = container_type)
return UM.Settings.ContainerRegistry.getInstance().createUniqueName(container_type, current_name, new_name, fallback_name)
## Convenience function to check if a stack has errors.
def _checkStackForErrors(self, stack):
@ -205,6 +194,7 @@ class MachineManagerModel(QObject):
if not self._active_container_stack:
return
self.blurSettings.emit()
user_settings = self._active_container_stack.getTop()
user_settings.clear()
@ -292,6 +282,7 @@ class MachineManagerModel(QObject):
new_container_id = self.duplicateContainer(self.activeQualityId)
if new_container_id == "":
return
self.blurSettings.emit()
self.setActiveQuality(new_container_id)
self.updateQualityContainerFromUserContainer()
@ -435,7 +426,7 @@ class MachineManagerModel(QObject):
@pyqtProperty(str, notify = globalContainerChanged)
def activeDefinitionId(self):
if self._active_container_stack:
if self._global_container_stack:
definition = self._global_container_stack.getBottom()
if definition:
return definition.id
@ -469,15 +460,15 @@ class MachineManagerModel(QObject):
@pyqtProperty(bool, notify = globalContainerChanged)
def hasMaterials(self):
if self._active_container_stack:
return bool(self._active_container_stack.getMetaDataEntry("has_materials", False))
if self._global_container_stack:
return bool(self._global_container_stack.getMetaDataEntry("has_materials", False))
return False
@pyqtProperty(bool, notify = globalContainerChanged)
def hasVariants(self):
if self._active_container_stack:
return bool(self._active_container_stack.getMetaDataEntry("has_variants", False))
if self._global_container_stack:
return bool(self._global_container_stack.getMetaDataEntry("has_variants", False))
return False

@ -3,6 +3,7 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from enum import IntEnum # For the connection state tracking.
from UM.Logger import Logger
from UM.Signal import signalemitter
## Printer output device adds extra interface options on top of output device.
#
@ -13,7 +14,8 @@ from UM.Logger import Logger
# functions to actually have the implementation.
#
# For all other uses it should be used in the same way as a "regular" OutputDevice.
class PrinterOutputDevice(OutputDevice, QObject):
@signalemitter
class PrinterOutputDevice(QObject, OutputDevice):
def __init__(self, device_id, parent = None):
super().__init__(device_id = device_id, parent = parent)

@ -51,8 +51,8 @@ class SettingOverrideDecorator(SceneNodeDecorator):
def getActiveExtruder(self):
return self._extruder_stack
def _onSettingChanged(self, instance, property):
if property == "value": # Only reslice if the value has changed.
def _onSettingChanged(self, instance, property_name): # Reminder: 'property' is a built-in function
if property_name == "value": # Only reslice if the value has changed.
Application.getInstance().getBackend().forceSlice()
## Makes sure that the stack upon which the container stack is placed is
@ -78,4 +78,4 @@ class SettingOverrideDecorator(SceneNodeDecorator):
self.activeExtruderChanged.emit()
def getStack(self):
return self._stack
return self._stack

@ -35,6 +35,7 @@ sys.excepthook = exceptHook
import Arcus #@UnusedImport
from UM.Platform import Platform
import cura.CuraApplication
import cura.CuraContainerRegistry
if Platform.isWindows() and hasattr(sys, "frozen"):
dirpath = os.path.expanduser("~/AppData/Local/cura/")
@ -42,5 +43,8 @@ if Platform.isWindows() and hasattr(sys, "frozen"):
sys.stdout = open(os.path.join(dirpath, "stdout.log"), "w")
sys.stderr = open(os.path.join(dirpath, "stderr.log"), "w")
# Force an instance of CuraContainerRegistry to be created and reused later.
cura.CuraContainerRegistry.CuraContainerRegistry.getInstance()
app = cura.CuraApplication.CuraApplication.getInstance()
app.run()

@ -113,9 +113,6 @@ class CuraEngineBackend(Backend):
json_path = Resources.getPath(Resources.DefinitionContainers, "fdmprinter.def.json")
return [Preferences.getInstance().getValue("backend/location"), "connect", "127.0.0.1:{0}".format(self._port), "-j", json_path, "-vv"]
def close(self):
self._terminate() # Forcefully shutdown the backend.
## Emitted when we get a message containing print duration and material amount. This also implies the slicing has finished.
# \param time The amount of time the print will take.
# \param material_amount The amount of material the print will use.

@ -61,7 +61,7 @@ Item {
}
else
{
return extruders_model.getItem(extruderSelector.currentIndex).colour;
return UM.Theme.getColor("setting_control");
}
}
border.width: UM.Theme.getSize("default_lining").width
@ -69,9 +69,22 @@ Item {
}
label: Item
{
Rectangle
{
id: swatch
height: UM.Theme.getSize("setting_control").height / 2
width: height
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_lining").width
anchors.verticalCenter: parent.verticalCenter
color: extruders_model.getItem(extruderSelector.currentIndex).colour
border.width: UM.Theme.getSize("default_lining").width
border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : UM.Theme.getColor("setting_control_border")
}
Label
{
anchors.left: parent.left
anchors.left: swatch.right
anchors.leftMargin: UM.Theme.getSize("default_lining").width
anchors.right: downArrow.left
anchors.rightMargin: UM.Theme.getSize("default_lining").width
@ -79,7 +92,7 @@ Item {
text: extruderSelector.currentText
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("setting_control_disabled_text")
color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text")
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter

@ -24,19 +24,12 @@ class PerObjectSettingsTool(Tool):
return False
def getSelectedObjectId(self):
try:
selected_object = Selection.getSelectedObject(0)
if selected_object.getParent().callDecoration("isGroup"):
selected_object = selected_object.getParent()
except:
selected_object = None
selected_object = Selection.getSelectedObject(0)
selected_object_id = id(selected_object)
return selected_object_id
def getContainerID(self):
selected_object = Selection.getSelectedObject(0)
if selected_object.getParent().callDecoration("isGroup"):
selected_object = selected_object.getParent()
try:
return selected_object.callDecoration("getStack").getId()
except AttributeError:

@ -256,7 +256,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
if not self.setBaudRate(baud_rate):
continue # Could not set the baud rate, go to the next
time.sleep(1.5) # Ensure that we are not talking to the bootloader. 1.5 sec seems to be the magic number
time.sleep(1.5) # Ensure that we are not talking to the bootloader. 1.5 seconds seems to be the magic number
sucesfull_responses = 0
timeout_time = time.time() + 5
self._serial.write(b"\n")

@ -10,18 +10,12 @@
"category": "Other",
"file_formats": "text/x-gcode",
"platform": "bq_hephestos_platform.stl",
"platform_offset": {
"value": [
0,
-82,
0
]
}
"platform_offset": [ 0, -82, 0]
},
"overrides": {
"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 X0 Y0 ;move to the X/Y origin (Home)\nG28 Z0 ;move to the Z origin (Home)\nG1 Z15.0 F1200 ;move Z to position 15.0 mm\nG92 E0 ;zero the extruded length\nG1 E20 F200 ;extrude 20mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F7200 ;set feedrate to 120 mm/sec\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 X0 Y0 ;move to the X/Y origin (Home)\nG28 Z0 ;move to the Z origin (Home)\nG1 Z15.0 F1200 ;move Z to position 15.0 mm\nG92 E0 ;zero the extruded length\nG1 E20 F200 ;extrude 20mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F7200 ;set feedrate to 120 mm/s\n; -- end of START GCODE --"
},
"machine_end_gcode": {
"default_value": "; -- END GCODE --\nM104 S0 ;set extruder temperature to zero (turned off)\nG91 ;set to relative positioning\nG1 E-20 F300 ;retract the filament a bit to release some of the pressure\nG1 Z10 ;move extruder up 10 mm\nG90 ;set to absolute positioning\nG1 X0 Y180 F1200 ;expose the platform\nM84 ;turn off steppers\n; -- end of END GCODE --"

@ -9,7 +9,7 @@
"manufacturer": "BQ",
"category": "Other",
"platform": "bq_hephestos_2_platform.stl",
"platform_offset": { "value": [6, 1320, 0 ] },
"platform_offset": [6, 1320, 0 ],
"file_formats": "text/x-gcode"
},

@ -10,18 +10,12 @@
"category": "Other",
"file_formats": "text/x-code",
"platform": "bq_hephestos_platform.stl",
"platform_offset": {
"value": [
0,
-82,
0
]
}
"platform_offset": [ 0, -82, 0]
},
"overrides": {
"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 X0 Y0 ;move to the X/Y origin (Home)\nG28 Z0 ;move to the Z origin (Home)\nG1 Z15.0 F1200 ;move Z to position 15.0 mm\nG92 E0 ;zero the extruded length\nG1 E20 F200 ;extrude 20mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F7200 ;set feedrate to 120 mm/sec\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 X0 Y0 ;move to the X/Y origin (Home)\nG28 Z0 ;move to the Z origin (Home)\nG1 Z15.0 F1200 ;move Z to position 15.0 mm\nG92 E0 ;zero the extruded length\nG1 E20 F200 ;extrude 20mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F7200 ;set feedrate to 120 mm/s\n; -- end of START GCODE --"
},
"machine_end_gcode": {
"default_value": "; -- END GCODE --\nM104 S0 ;set extruder temperature to zero (turned off)\nG91 ;set to relative positioning\nG1 E-20 F300 ;retract the filament a bit to release some of the pressure\nG1 Z10 ;move extruder up 10 mm\nG90 ;set to absolute positioning\nG1 X0 Y180 F1200 ;expose the platform\nM84 ;turn off steppers\n; -- end of END GCODE --"

@ -10,18 +10,12 @@
"category": "Other",
"file_formats": "text/x-gcode",
"platform": "bq_witbox_platform.stl",
"platform_offset": {
"value": [
0,
-145,
-38
]
}
"platform_offset": [ 0, -145, -38]
},
"overrides": {
"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 X0 Y0 ;move to the X/Y origin (Home)\nG28 Z0 ;move to the Z origin (Home)\nG1 Z15.0 F1200 ;move Z to position 15.0 mm\nG92 E0 ;zero the extruded length\nG1 E20 F200 ;extrude 20mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F7200 ;set feedrate to 120 mm/sec\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 X0 Y0 ;move to the X/Y origin (Home)\nG28 Z0 ;move to the Z origin (Home)\nG1 Z15.0 F1200 ;move Z to position 15.0 mm\nG92 E0 ;zero the extruded length\nG1 E20 F200 ;extrude 20mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F7200 ;set feedrate to 120 mm/s\n; -- end of START GCODE --"
},
"machine_end_gcode": {
"default_value": "; -- END GCODE --\nM104 S0 ;set extruder temperature to zero (turned off)\nG91 ;set to relative positioning\nG1 E-20 F300 ;retract the filament a bit to release some of the pressure\nG90 ;set to absolute positioning\nG1 Z200 ;move the platform to the bottom\nG28 X0 Y0 ;move to the X/Y origin (Home)\nM84 ;turn off steppers\n; -- end of END GCODE --"

@ -23,8 +23,7 @@
"label": "Extruder",
"description": "The extruder train used for printing. This is used in multi-extrusion.",
"type": "extruder",
"default_value": 0,
"minimum_value": "0",
"default_value": "0",
"settable_per_mesh": true,
"settable_per_extruder": false,
"settable_per_meshgroup": false,

@ -1802,7 +1802,7 @@
{
"label": "Regular/Maximum Fan Speed Threshold",
"description": "The layer time which sets the threshold between regular fan speed and maximum fan speed. Layers that print slower than this time use regular fan speed. For faster layers the fan speed gradually increases towards the maximum fan speed.",
"unit": "sec",
"unit": "s",
"type": "float",
"default_value": 10,
"minimum_value": "cool_min_layer_time",
@ -1842,7 +1842,7 @@
{
"label": "Minimum Layer Time",
"description": "The minimum time spent in a layer. This forces the printer to slow down, to at least spend the time set here in one layer. This allows the printed material to cool down properly before printing the next layer.",
"unit": "sec",
"unit": "s",
"type": "float",
"default_value": 5,
"minimum_value": "0",
@ -2751,6 +2751,7 @@
"value": "support_extruder_nr",
"minimum_value": "0",
"maximum_value": "machine_extruder_count - 1",
"enabled": "support_enable",
"settable_per_mesh": false,
"settable_per_extruder": false
},
@ -2763,6 +2764,7 @@
"value": "support_extruder_nr",
"minimum_value": "0",
"maximum_value": "machine_extruder_count - 1",
"enabled": "support_enable",
"settable_per_mesh": false,
"settable_per_extruder": false
},
@ -2775,6 +2777,7 @@
"value": "support_extruder_nr",
"minimum_value": "0",
"maximum_value": "machine_extruder_count - 1",
"enabled": "support_enable",
"settable_per_mesh": false,
"settable_per_extruder": false
}
@ -3392,7 +3395,7 @@
{
"label": "WP Top Delay",
"description": "Delay time after an upward move, so that the upward line can harden. Only applies to Wire Printing.",
"unit": "sec",
"unit": "s",
"type": "float",
"default_value": 0,
"minimum_value": "0",
@ -3406,7 +3409,7 @@
{
"label": "WP Bottom Delay",
"description": "Delay time after a downward move. Only applies to Wire Printing.",
"unit": "sec",
"unit": "s",
"type": "float",
"default_value": 0,
"minimum_value": "0",
@ -3420,7 +3423,7 @@
{
"label": "WP Flat Delay",
"description": "Delay time between two horizontal segments. Introducing such a delay can cause better adhesion to previous layers at the connection points, while too long delays cause sagging. Only applies to Wire Printing.",
"unit": "sec",
"unit": "s",
"type": "float",
"default_value": 0.1,
"minimum_value": "0",
@ -3550,7 +3553,7 @@
"label": "WP Roof Outer Delay",
"description": "Time spent at the outer perimeters of hole which is to become a roof. Longer times can ensure a better connection. Only applies to Wire Printing.",
"type": "float",
"unit": "sec",
"unit": "s",
"default_value": 0.2,
"minimum_value": "0",
"maximum_value_warning": "2.0",

@ -154,7 +154,7 @@ UM.Dialog
Button
{
text:"save"
text: catalog.i18nc("@action:button", "Add Printer")
anchors.bottom: parent.bottom
anchors.right: parent.right
onClicked:

@ -545,16 +545,13 @@ UM.MainWindow
{
//; Remove & re-add the general page as we want to use our own instead of uranium standard.
removePage(0);
insertPage(0, catalog.i18nc("@title:tab","General"), Qt.resolvedUrl("GeneralPage.qml"));
insertPage(0, catalog.i18nc("@title:tab","General"), Qt.resolvedUrl("Preferences/GeneralPage.qml"));
//: View preferences page title
insertPage(1, catalog.i18nc("@title:tab","View"), Qt.resolvedUrl("ViewPage.qml"));
insertPage(2, catalog.i18nc("@title:tab", "Printers"), Qt.resolvedUrl("Preferences/MachinesPage.qml"));
insertPage(3, catalog.i18nc("@title:tab", "Printers"), Qt.resolvedUrl("MachinesPage.qml"));
insertPage(3, catalog.i18nc("@title:tab", "Materials"), Qt.resolvedUrl("Preferences/MaterialsPage.qml"));
insertPage(4, catalog.i18nc("@title:tab", "Materials"), Qt.resolvedUrl("Preferences/MaterialsPage.qml"));
insertPage(5, catalog.i18nc("@title:tab", "Profiles"), Qt.resolvedUrl("Preferences/ProfilesPage.qml"));
insertPage(4, catalog.i18nc("@title:tab", "Profiles"), Qt.resolvedUrl("Preferences/ProfilesPage.qml"));
//Force refresh
setPage(0);
@ -583,7 +580,7 @@ UM.MainWindow
onTriggered:
{
Cura.MachineManager.newQualityContainerFromQualityAndUser();
preferences.setPage(5);
preferences.setPage(4);
preferences.show();
// Show the renameDialog after a very short delay so the preference page has time to initiate
@ -597,7 +594,7 @@ UM.MainWindow
onTriggered:
{
preferences.visible = true;
preferences.setPage(3);
preferences.setPage(2);
}
}
@ -607,7 +604,7 @@ UM.MainWindow
onTriggered:
{
preferences.visible = true;
preferences.setPage(5);
preferences.setPage(4);
}
}
@ -617,7 +614,7 @@ UM.MainWindow
onTriggered:
{
preferences.visible = true;
preferences.setPage(2);
preferences.setPage(1);
preferences.getCurrentItem().scrollToSection(source.key);
}
}

@ -39,6 +39,12 @@ UM.PreferencesPage
scaleTinyCheckbox.checked = boolCheck(UM.Preferences.getValue("mesh/scale_tiny_meshes"))
UM.Preferences.resetPreference("cura/jobname_prefix")
prefixJobNameCheckbox.checked = boolCheck(UM.Preferences.getValue("cura/jobname_prefix"))
UM.Preferences.resetPreference("view/show_overhang");
showOverhangCheckbox.checked = boolCheck(UM.Preferences.getValue("view/show_overhang"))
UM.Preferences.resetPreference("view/center_on_select");
centerOnSelectCheckbox.checked = boolCheck(UM.Preferences.getValue("view/center_on_select"))
UM.Preferences.resetPreference("view/top_layer_count");
topLayerCountCheckbox.checked = boolCheck(UM.Preferences.getValue("view/top_layer_count"))
if (plugins.model.find("id", "SliceInfoPlugin") > -1) {
UM.Preferences.resetPreference("info/send_slice_info")
@ -50,17 +56,24 @@ UM.PreferencesPage
}
}
ColumnLayout
Column
{
//: Language selection label
UM.I18nCatalog{id: catalog; name:"cura"}
RowLayout
Label
{
font.bold: true
text: catalog.i18nc("@label","Interface")
}
Row
{
Label
{
id: languageLabel
text: catalog.i18nc("@label","Language:")
anchors.verticalCenter: languageComboBox.verticalCenter
}
ComboBox
@ -120,6 +133,51 @@ UM.PreferencesPage
font.italic: true
}
Item
{
//: Spacer
height: UM.Theme.getSize("default_margin").height
width: UM.Theme.getSize("default_margin").width
}
Label
{
font.bold: true
text: catalog.i18nc("@label","Viewport behavior")
}
UM.TooltipArea
{
width: childrenRect.width;
height: childrenRect.height;
text: catalog.i18nc("@info:tooltip","Highlight unsupported areas of the model in red. Without support these areas will not print properly.")
CheckBox
{
id: showOverhangCheckbox
checked: boolCheck(UM.Preferences.getValue("view/show_overhang"))
onClicked: UM.Preferences.setValue("view/show_overhang", checked)
text: catalog.i18nc("@option:check","Display overhang");
}
}
UM.TooltipArea {
width: childrenRect.width;
height: childrenRect.height;
text: catalog.i18nc("@info:tooltip","Moves the camera so the object is in the center of the view when an object is selected")
CheckBox
{
id: centerOnSelectCheckbox
text: catalog.i18nc("@action:button","Center camera when item is selected");
checked: boolCheck(UM.Preferences.getValue("view/center_on_select"))
onClicked: UM.Preferences.setValue("view/center_on_select", checked)
}
}
UM.TooltipArea {
width: childrenRect.width
height: childrenRect.height
@ -134,15 +192,52 @@ UM.PreferencesPage
}
}
UM.TooltipArea {
width: childrenRect.width;
height: childrenRect.height;
text: catalog.i18nc("@info:tooltip","Display 5 top layers in layer view or only the top-most layer. Rendering 5 layers takes longer, but may show more information.")
CheckBox
{
id: topLayerCountCheckbox
text: catalog.i18nc("@action:button","Display five top layers in layer view");
checked: UM.Preferences.getValue("view/top_layer_count") == 5
onClicked:
{
if(UM.Preferences.getValue("view/top_layer_count") == 5)
{
UM.Preferences.setValue("view/top_layer_count", 1)
}
else
{
UM.Preferences.setValue("view/top_layer_count", 5)
}
}
}
}
Item
{
//: Spacer
height: UM.Theme.getSize("default_margin").height
width: UM.Theme.getSize("default_margin").height
}
Label
{
font.bold: true
text: catalog.i18nc("@label","Opening files")
}
UM.TooltipArea {
width: childrenRect.width
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","Should opened files be scaled to the build volume if they are too large?")
text: catalog.i18nc("@info:tooltip","Should objects be scaled to the build volume if they are too large?")
CheckBox
{
id: scaleToFitCheckbox
text: catalog.i18nc("@option:check","Scale large files")
text: catalog.i18nc("@option:check","Scale large objects")
checked: boolCheck(UM.Preferences.getValue("mesh/scale_to_fit"))
onCheckedChanged: UM.Preferences.setValue("mesh/scale_to_fit", checked)
}
@ -151,17 +246,45 @@ UM.PreferencesPage
UM.TooltipArea {
width: childrenRect.width
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","Should opened files be scaled up if they are extremely small?")
text: catalog.i18nc("@info:tooltip","Should objects be scaled up if they are extremely small?")
CheckBox
{
id: scaleTinyCheckbox
text: catalog.i18nc("@option:check","Scale extremely small files")
text: catalog.i18nc("@option:check","Scale extremely small objects")
checked: boolCheck(UM.Preferences.getValue("mesh/scale_tiny_meshes"))
onCheckedChanged: UM.Preferences.setValue("mesh/scale_tiny_meshes", checked)
}
}
UM.TooltipArea {
width: childrenRect.width
height: childrenRect.height
text: catalog.i18nc("@info:tooltip", "Should a prefix based on the printer name be added to the print job name automatically?")
CheckBox
{
id: prefixJobNameCheckbox
text: catalog.i18nc("@option:check", "Add machine prefix to job name")
checked: boolCheck(UM.Preferences.getValue("cura/jobname_prefix"))
onCheckedChanged: UM.Preferences.setValue("cura/jobname_prefix", checked)
}
}
Item
{
//: Spacer
height: UM.Theme.getSize("default_margin").height
width: UM.Theme.getSize("default_margin").height
}
Label
{
font.bold: true
visible: checkUpdatesCheckbox.visible || sendDataCheckbox.visible
text: catalog.i18nc("@label","Privacy")
}
UM.TooltipArea {
visible: plugins.model.find("id", "UpdateChecker") > -1
width: childrenRect.width
@ -192,20 +315,7 @@ UM.PreferencesPage
}
}
UM.TooltipArea {
width: childrenRect.width
height: childrenRect.height
text: catalog.i18nc("@info:tooltip", "Should a prefix based on the printer name be added to the print job name automatically?")
CheckBox
{
id: prefixJobNameCheckbox
text: catalog.i18nc("@option:check", "Add machine prefix to job name")
checked: boolCheck(UM.Preferences.getValue("cura/jobname_prefix"))
onCheckedChanged: UM.Preferences.setValue("cura/jobname_prefix", checked)
}
}
//: Invisible list used to check if a plugin exists
ListView
{
id: plugins

@ -39,7 +39,6 @@ UM.ManagementPage
section.property: "readOnly"
section.delegate: Rectangle
{
width: objectListContainer.viewport.width;
height: childrenRect.height;
Label
@ -265,7 +264,7 @@ UM.ManagementPage
id: importDialog;
title: catalog.i18nc("@title:window", "Import Profile");
selectExisting: true;
nameFilters: base.model.getFileNameFiltersRead()
nameFilters: base.model.getFileNameFilters("profile_reader")
folder: base.model.getDefaultPath()
onAccepted:
{
@ -292,7 +291,7 @@ UM.ManagementPage
id: exportDialog;
title: catalog.i18nc("@title:window", "Export Profile");
selectExisting: false;
nameFilters: base.model.getFileNameFiltersWrite()
nameFilters: base.model.getFileNameFilters("profile_writer")
folder: base.model.getDefaultPath()
onAccepted:
{

@ -24,9 +24,10 @@ Button {
checkable: true
checked: definition.expanded
onClicked: definition.expanded ? settingDefinitionsModel.collapse(definition.key) : settingDefinitionsModel.expandAll(definition.key)
onClicked: { forceActiveFocus(); definition.expanded ? settingDefinitionsModel.collapse(definition.key) : settingDefinitionsModel.expandAll(definition.key) }
UM.SimpleButton {
UM.SimpleButton
{
id: settingsButton
visible: base.hovered || settingsButton.hovered
@ -60,7 +61,8 @@ Button {
height: parent.height / 2
width: height
onClicked: {
onClicked:
{
base.showAllHiddenInheritedSettings()
}
@ -68,11 +70,13 @@ Button {
hoverColor: UM.Theme.getColor("setting_control_button_hover")
iconSource: UM.Theme.getIcon("notice")
onEntered: {
onEntered:
{
base.showTooltip(catalog.i18nc("@label","Some hidden settings use values different from their normal calculated value.\n\nClick to make these settings visible."))
}
onExited: {
onExited:
{
base.hideTooltip();
}

@ -31,7 +31,7 @@ SettingItem
}
}
onClicked: propertyProvider.setPropertyValue("value", !checked)
onClicked: { forceActiveFocus(); propertyProvider.setPropertyValue("value", !checked) }
Rectangle
{

@ -86,7 +86,7 @@ SettingItem
}
}
onActivated: provider.setPropertyValue("value", definition.options[index].key)
onActivated: { forceActiveFocus(); provider.setPropertyValue("value", definition.options[index].key) }
onModelChanged: updateCurrentIndex();
Connections

@ -47,7 +47,7 @@ SettingItem
}
else
{
return extruders_model.getItem(index).colour;
return UM.Theme.getColor("setting_control");
}
}
border.width: UM.Theme.getSize("default_lining").width
@ -55,9 +55,22 @@ SettingItem
}
label: Item
{
Rectangle
{
id: swatch
height: UM.Theme.getSize("setting_control").height / 2
width: height
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_lining").width
anchors.verticalCenter: parent.verticalCenter
color: extruders_model.getItem(control.currentIndex).colour
border.width: UM.Theme.getSize("default_lining").width
border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : UM.Theme.getColor("setting_control_border")
}
Label
{
anchors.left: parent.left
anchors.left: swatch.right
anchors.leftMargin: UM.Theme.getSize("default_lining").width
anchors.right: downArrow.left
anchors.rightMargin: UM.Theme.getSize("default_lining").width
@ -65,7 +78,7 @@ SettingItem
text: control.currentText
font: UM.Theme.getFont("default")
color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : extruders_model.getItem(index).colour
color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text")
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
@ -89,7 +102,11 @@ SettingItem
}
}
onActivated: provider.setPropertyValue("value", extruders_model.getItem(index).index);
onActivated:
{
forceActiveFocus();
provider.setPropertyValue("value", extruders_model.getItem(index).index)
}
onModelChanged: updateCurrentIndex();
Connections

@ -7,6 +7,7 @@ import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import UM 1.1 as UM
import Cura 1.0 as Cura
import "."
@ -245,5 +246,14 @@ Item {
}
}
Connections
{
target: Cura.MachineManager
onBlurSettings:
{
revertButton.focus = true
}
}
UM.I18nCatalog { id: catalog; name: "cura" }
}

@ -7,6 +7,7 @@ import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import UM 1.1 as UM
import Cura 1.0 as Cura
Rectangle
{
@ -14,6 +15,9 @@ Rectangle
property int currentModeIndex;
// Is there an output device for this printer?
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
color: UM.Theme.getColor("sidebar");
UM.I18nCatalog { id: catalog; name:"cura"}

@ -141,15 +141,35 @@ Column
control.hovered ? UM.Theme.getColor("toggle_hovered") : UM.Theme.getColor("toggle_unchecked")
Behavior on color { ColorAnimation { duration: 50; } }
Rectangle
{
id: swatch
height: UM.Theme.getSize("setting_control").height / 2
width: height
anchors.left: parent.left
anchors.leftMargin: (parent.height - height) / 2
anchors.verticalCenter: parent.verticalCenter
color: model.colour
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("toggle_checked")
}
Label
{
anchors.centerIn: parent
anchors.verticalCenter: parent.verticalCenter
anchors.left: swatch.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width / 2
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width / 2
color: control.checked ? UM.Theme.getColor("toggle_checked_text") :
control.pressed ? UM.Theme.getColor("toggle_active_text") :
control.hovered ? UM.Theme.getColor("toggle_hovered_text") : UM.Theme.getColor("toggle_unchecked_text")
font: UM.Theme.getFont("default")
text: control.text;
text: control.text
elide: Text.ElideRight
}
}
label: Item { }

@ -1,96 +0,0 @@
// Copyright (c) 2015 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import UM 1.1 as UM
UM.PreferencesPage
{
id: preferencesPage
//: View configuration page title
title: catalog.i18nc("@title:window","View");
function reset()
{
UM.Preferences.resetPreference("view/show_overhang");
UM.Preferences.resetPreference("view/center_on_select");
UM.Preferences.resetPreference("view/top_layer_count");
}
Column
{
UM.I18nCatalog { id: catalog; name:"cura"}
UM.TooltipArea
{
width: childrenRect.width;
height: childrenRect.height;
text: catalog.i18nc("@info:tooltip","Highlight unsupported areas of the model in red. Without support these areas will not print properly.")
CheckBox
{
id: overhangCheckbox
checked: boolCheck(UM.Preferences.getValue("view/show_overhang"))
onClicked: UM.Preferences.setValue("view/show_overhang", checked)
text: catalog.i18nc("@option:check","Display overhang");
}
}
UM.TooltipArea {
width: childrenRect.width;
height: childrenRect.height;
text: catalog.i18nc("@info:tooltip","Moves the camera so the object is in the center of the view when an object is selected")
CheckBox
{
id: centerCheckbox
text: catalog.i18nc("@action:button","Center camera when item is selected");
checked: boolCheck(UM.Preferences.getValue("view/center_on_select"))
onClicked: UM.Preferences.setValue("view/center_on_select", checked)
}
}
UM.TooltipArea {
width: childrenRect.width;
height: childrenRect.height;
text: catalog.i18nc("@info:tooltip","Display 5 top layers in layer view or only the top-most layer. Rendering 5 layers takes longer, but may show more information.")
CheckBox
{
id: topLayerCheckbox
text: catalog.i18nc("@action:button","Display five top layers in layer view.");
checked: UM.Preferences.getValue("view/top_layer_count") == 5
onClicked:
{
if(UM.Preferences.getValue("view/top_layer_count") == 5)
{
UM.Preferences.setValue("view/top_layer_count", 1)
}
else
{
UM.Preferences.setValue("view/top_layer_count", 5)
}
}
}
}
Connections {
target: UM.Preferences
onPreferenceChanged:
{
overhangCheckbox.checked = boolCheck(UM.Preferences.getValue("view/show_overhang"))
centerCheckbox.checked = boolCheck(UM.Preferences.getValue("view/center_on_select"))
topLayerCheckbox = UM.Preferences.getValue("view/top_layer_count") == 5
}
}
}
}

@ -74,6 +74,7 @@ u_viewProjectionMatrix = view_projection_matrix
u_normalMatrix = normal_matrix
u_viewPosition = view_position
u_lightPosition = light_0_position
u_diffuseColor = diffuse_color
[attributes]
a_vertex = vertex