Merge branch '4.0' into unify_font_types

This commit is contained in:
Ghostkeeper 2018-12-28 15:51:54 +01:00
commit b54312fb9b
No known key found for this signature in database
GPG key ID: 86BEF881AE2CF276
30 changed files with 266 additions and 114 deletions

View file

@ -36,12 +36,12 @@ class CuraActions(QObject):
# Starting a web browser from a signal handler connected to a menu will crash on windows. # Starting a web browser from a signal handler connected to a menu will crash on windows.
# So instead, defer the call to the next run of the event loop, since that does work. # So instead, defer the call to the next run of the event loop, since that does work.
# Note that weirdly enough, only signal handlers that open a web browser fail like that. # Note that weirdly enough, only signal handlers that open a web browser fail like that.
event = CallFunctionEvent(self._openUrl, [QUrl("http://ultimaker.com/en/support/software")], {}) event = CallFunctionEvent(self._openUrl, [QUrl("https://ultimaker.com/en/resources/manuals/software")], {})
cura.CuraApplication.CuraApplication.getInstance().functionEvent(event) cura.CuraApplication.CuraApplication.getInstance().functionEvent(event)
@pyqtSlot() @pyqtSlot()
def openBugReportPage(self) -> None: def openBugReportPage(self) -> None:
event = CallFunctionEvent(self._openUrl, [QUrl("http://github.com/Ultimaker/Cura/issues")], {}) event = CallFunctionEvent(self._openUrl, [QUrl("https://github.com/Ultimaker/Cura/issues")], {})
cura.CuraApplication.CuraApplication.getInstance().functionEvent(event) cura.CuraApplication.CuraApplication.getInstance().functionEvent(event)
## Reset camera position and direction to default ## Reset camera position and direction to default

View file

@ -1,7 +1,7 @@
# 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.
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt, QTimer
from UM.Application import Application from UM.Application import Application
from UM.Logger import Logger from UM.Logger import Logger
@ -39,15 +39,23 @@ class QualityProfilesDropDownMenuModel(ListModel):
self._machine_manager = self._application.getMachineManager() self._machine_manager = self._application.getMachineManager()
self._quality_manager = Application.getInstance().getQualityManager() self._quality_manager = Application.getInstance().getQualityManager()
self._application.globalContainerStackChanged.connect(self._update) self._application.globalContainerStackChanged.connect(self._onChange)
self._machine_manager.activeQualityGroupChanged.connect(self._update) self._machine_manager.activeQualityGroupChanged.connect(self._onChange)
self._machine_manager.extruderChanged.connect(self._update) self._machine_manager.extruderChanged.connect(self._onChange)
self._quality_manager.qualitiesUpdated.connect(self._update) self._quality_manager.qualitiesUpdated.connect(self._onChange)
self._layer_height_unit = "" # This is cached self._layer_height_unit = "" # This is cached
self._update_timer = QTimer() # type: QTimer
self._update_timer.setInterval(100)
self._update_timer.setSingleShot(True)
self._update_timer.timeout.connect(self._update)
self._update() self._update()
def _onChange(self) -> None:
self._update_timer.start()
def _update(self): def _update(self):
Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__))

View file

@ -6,6 +6,7 @@ from typing import Optional, List
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from UM.Logger import Logger from UM.Logger import Logger
from UM.Preferences import Preferences
from UM.Resources import Resources from UM.Resources import Resources
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
@ -18,14 +19,20 @@ class SettingVisibilityPresetsModel(QObject):
onItemsChanged = pyqtSignal() onItemsChanged = pyqtSignal()
activePresetChanged = pyqtSignal() activePresetChanged = pyqtSignal()
def __init__(self, preferences, parent = None): def __init__(self, preferences: Preferences, parent = None) -> None:
super().__init__(parent) super().__init__(parent)
self._items = [] # type: List[SettingVisibilityPreset] self._items = [] # type: List[SettingVisibilityPreset]
self._custom_preset = SettingVisibilityPreset(preset_id = "custom", name = "Custom selection", weight = -100)
self._populate() self._populate()
basic_item = self.getVisibilityPresetById("basic") basic_item = self.getVisibilityPresetById("basic")
basic_visibile_settings = ";".join(basic_item.settings) if basic_item is not None:
basic_visibile_settings = ";".join(basic_item.settings)
else:
Logger.log("w", "Unable to find the basic visiblity preset.")
basic_visibile_settings = ""
self._preferences = preferences self._preferences = preferences
@ -42,7 +49,8 @@ class SettingVisibilityPresetsModel(QObject):
visible_settings = self._preferences.getValue("general/visible_settings") visible_settings = self._preferences.getValue("general/visible_settings")
if not visible_settings: if not visible_settings:
self._preferences.setValue("general/visible_settings", ";".join(self._active_preset_item.settings)) new_visible_settings = self._active_preset_item.settings if self._active_preset_item is not None else []
self._preferences.setValue("general/visible_settings", ";".join(new_visible_settings))
else: else:
self._onPreferencesChanged("general/visible_settings") self._onPreferencesChanged("general/visible_settings")
@ -59,9 +67,7 @@ class SettingVisibilityPresetsModel(QObject):
def _populate(self) -> None: def _populate(self) -> None:
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
items = [] # type: List[SettingVisibilityPreset] items = [] # type: List[SettingVisibilityPreset]
items.append(self._custom_preset)
custom_preset = SettingVisibilityPreset(preset_id="custom", name ="Custom selection", weight = -100)
items.append(custom_preset)
for file_path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.SettingVisibilityPreset): for file_path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.SettingVisibilityPreset):
setting_visibility_preset = SettingVisibilityPreset() setting_visibility_preset = SettingVisibilityPreset()
try: try:
@ -77,7 +83,7 @@ class SettingVisibilityPresetsModel(QObject):
self.setItems(items) self.setItems(items)
@pyqtProperty("QVariantList", notify = onItemsChanged) @pyqtProperty("QVariantList", notify = onItemsChanged)
def items(self): def items(self) -> List[SettingVisibilityPreset]:
return self._items return self._items
def setItems(self, items: List[SettingVisibilityPreset]) -> None: def setItems(self, items: List[SettingVisibilityPreset]) -> None:
@ -87,7 +93,7 @@ class SettingVisibilityPresetsModel(QObject):
@pyqtSlot(str) @pyqtSlot(str)
def setActivePreset(self, preset_id: str) -> None: def setActivePreset(self, preset_id: str) -> None:
if preset_id == self._active_preset_item.presetId: if self._active_preset_item is not None and preset_id == self._active_preset_item.presetId:
Logger.log("d", "Same setting visibility preset [%s] selected, do nothing.", preset_id) Logger.log("d", "Same setting visibility preset [%s] selected, do nothing.", preset_id)
return return
@ -96,7 +102,7 @@ class SettingVisibilityPresetsModel(QObject):
Logger.log("w", "Tried to set active preset to unknown id [%s]", preset_id) Logger.log("w", "Tried to set active preset to unknown id [%s]", preset_id)
return return
need_to_save_to_custom = self._active_preset_item.presetId == "custom" and preset_id != "custom" need_to_save_to_custom = self._active_preset_item is None or (self._active_preset_item.presetId == "custom" and preset_id != "custom")
if need_to_save_to_custom: if need_to_save_to_custom:
# Save the current visibility settings to custom # Save the current visibility settings to custom
current_visibility_string = self._preferences.getValue("general/visible_settings") current_visibility_string = self._preferences.getValue("general/visible_settings")
@ -117,7 +123,9 @@ class SettingVisibilityPresetsModel(QObject):
@pyqtProperty(str, notify = activePresetChanged) @pyqtProperty(str, notify = activePresetChanged)
def activePreset(self) -> str: def activePreset(self) -> str:
return self._active_preset_item.presetId if self._active_preset_item is not None:
return self._active_preset_item.presetId
return ""
def _onPreferencesChanged(self, name: str) -> None: def _onPreferencesChanged(self, name: str) -> None:
if name != "general/visible_settings": if name != "general/visible_settings":
@ -149,7 +157,12 @@ class SettingVisibilityPresetsModel(QObject):
else: else:
item_to_set = matching_preset_item item_to_set = matching_preset_item
# If we didn't find a matching preset, fallback to custom.
if item_to_set is None:
item_to_set = self._custom_preset
if self._active_preset_item is None or self._active_preset_item.presetId != item_to_set.presetId: if self._active_preset_item is None or self._active_preset_item.presetId != item_to_set.presetId:
self._active_preset_item = item_to_set self._active_preset_item = item_to_set
self._preferences.setValue("cura/active_setting_visibility_preset", self._active_preset_item.presetId) if self._active_preset_item is not None:
self._preferences.setValue("cura/active_setting_visibility_preset", self._active_preset_item.presetId)
self.activePresetChanged.emit() self.activePresetChanged.emit()

View file

@ -83,9 +83,11 @@ class AuthorizationService:
if not self.getUserProfile(): if not self.getUserProfile():
# We check if we can get the user profile. # We check if we can get the user profile.
# If we can't get it, that means the access token (JWT) was invalid or expired. # If we can't get it, that means the access token (JWT) was invalid or expired.
Logger.log("w", "Unable to get the user profile.")
return None return None
if self._auth_data is None: if self._auth_data is None:
Logger.log("d", "No auth data to retrieve the access_token from")
return None return None
return self._auth_data.access_token return self._auth_data.access_token

View file

@ -230,7 +230,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
# Returns the unique configurations of the printers within this output device # Returns the unique configurations of the printers within this output device
@pyqtProperty("QStringList", notify = uniqueConfigurationsChanged) @pyqtProperty("QStringList", notify = uniqueConfigurationsChanged)
def uniquePrinterTypes(self) -> List[str]: def uniquePrinterTypes(self) -> List[str]:
return list(set([configuration.printerType for configuration in self._unique_configurations])) return list(sorted(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:

View file

@ -299,6 +299,7 @@ class MachineManager(QObject):
self.activeMaterialChanged.emit() self.activeMaterialChanged.emit()
self.rootMaterialChanged.emit() self.rootMaterialChanged.emit()
self.numberExtrudersEnabledChanged.emit()
def _onContainersChanged(self, container: ContainerInterface) -> None: def _onContainersChanged(self, container: ContainerInterface) -> None:
self._instance_container_timer.start() self._instance_container_timer.start()

View file

@ -86,8 +86,8 @@ class CuraEngineBackend(QObject, Backend):
self._layer_view_active = False #type: bool self._layer_view_active = False #type: bool
self._onActiveViewChanged() self._onActiveViewChanged()
self._stored_layer_data = [] #type: List[Arcus.PythonMessage] self._stored_layer_data = [] # type: List[Arcus.PythonMessage]
self._stored_optimized_layer_data = {} #type: Dict[int, List[Arcus.PythonMessage]] # key is build plate number, then arrays are stored until they go to the ProcessSlicesLayersJob self._stored_optimized_layer_data = {} # type: Dict[int, List[Arcus.PythonMessage]] # key is build plate number, then arrays are stored until they go to the ProcessSlicesLayersJob
self._scene = self._application.getController().getScene() #type: Scene self._scene = self._application.getController().getScene() #type: Scene
self._scene.sceneChanged.connect(self._onSceneChanged) self._scene.sceneChanged.connect(self._onSceneChanged)
@ -229,6 +229,7 @@ class CuraEngineBackend(QObject, Backend):
if not self._build_plates_to_be_sliced: if not self._build_plates_to_be_sliced:
self.processingProgress.emit(1.0) self.processingProgress.emit(1.0)
Logger.log("w", "Slice unnecessary, nothing has changed that needs reslicing.") Logger.log("w", "Slice unnecessary, nothing has changed that needs reslicing.")
self.setState(BackendState.Done)
return return
if self._process_layers_job: if self._process_layers_job:
@ -245,7 +246,7 @@ class CuraEngineBackend(QObject, Backend):
num_objects = self._numObjectsPerBuildPlate() num_objects = self._numObjectsPerBuildPlate()
self._stored_layer_data = [] self._stored_layer_data = []
self._stored_optimized_layer_data[build_plate_to_be_sliced] = []
if build_plate_to_be_sliced not in num_objects or num_objects[build_plate_to_be_sliced] == 0: if build_plate_to_be_sliced not in num_objects or num_objects[build_plate_to_be_sliced] == 0:
self._scene.gcode_dict[build_plate_to_be_sliced] = [] #type: ignore #Because we created this attribute above. self._scene.gcode_dict[build_plate_to_be_sliced] = [] #type: ignore #Because we created this attribute above.
@ -253,7 +254,7 @@ class CuraEngineBackend(QObject, Backend):
if self._build_plates_to_be_sliced: if self._build_plates_to_be_sliced:
self.slice() self.slice()
return return
self._stored_optimized_layer_data[build_plate_to_be_sliced] = []
if self._application.getPrintInformation() and build_plate_to_be_sliced == active_build_plate: if self._application.getPrintInformation() and build_plate_to_be_sliced == active_build_plate:
self._application.getPrintInformation().setToZeroPrintInformation(build_plate_to_be_sliced) self._application.getPrintInformation().setToZeroPrintInformation(build_plate_to_be_sliced)
@ -410,7 +411,7 @@ class CuraEngineBackend(QObject, Backend):
if job.getResult() == StartJobResult.NothingToSlice: if job.getResult() == StartJobResult.NothingToSlice:
if self._application.platformActivity: if self._application.platformActivity:
self._error_message = Message(catalog.i18nc("@info:status", "Nothing to slice because none of the models fit the build volume. Please scale or rotate models to fit."), self._error_message = Message(catalog.i18nc("@info:status", "Nothing to slice because none of the models fit the build volume or are assigned to a disabled extruder. Please scale or rotate models to fit, or enable an extruder."),
title = catalog.i18nc("@info:title", "Unable to slice")) title = catalog.i18nc("@info:title", "Unable to slice"))
self._error_message.show() self._error_message.show()
self.setState(BackendState.Error) self.setState(BackendState.Error)

View file

@ -13,7 +13,8 @@ import Cura 1.0 as Cura
Cura.MachineAction Cura.MachineAction
{ {
id: base id: base
property var extrudersModel: CuraApplication.getExtrudersModel() property var extrudersModel: Cura.ExtrudersModel{} // Do not retrieve the Model from a backend. Otherwise the tabs
// in tabView will not removed/updated. Probably QML bug
property int extruderTabsCount: 0 property int extruderTabsCount: 0
property var activeMachineId: Cura.MachineManager.activeMachine != null ? Cura.MachineManager.activeMachine.id : "" property var activeMachineId: Cura.MachineManager.activeMachine != null ? Cura.MachineManager.activeMachine.id : ""

View file

@ -16,12 +16,20 @@ Item
color: UM.Theme.getColor("viewport_overlay") color: UM.Theme.getColor("viewport_overlay")
anchors.fill: parent anchors.fill: parent
// This mouse area is to prevent mouse clicks to be passed onto the scene.
MouseArea MouseArea
{ {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.AllButtons acceptedButtons: Qt.AllButtons
onWheel: wheel.accepted = true onWheel: wheel.accepted = true
} }
// Disable dropping files into Cura when the monitor page is active
DropArea
{
anchors.fill: parent
}
} }
Loader Loader

View file

@ -25,7 +25,7 @@ UM.Dialog
{ {
if(!visible) //Whenever the window is closed (either via the "Close" button or the X on the window frame), we want to update it in the stack. if(!visible) //Whenever the window is closed (either via the "Close" button or the X on the window frame), we want to update it in the stack.
{ {
manager.writeScriptsToStack(); manager.writeScriptsToStack()
} }
} }
@ -67,12 +67,17 @@ UM.Dialog
ListView ListView
{ {
id: activeScriptsList id: activeScriptsList
anchors.top: activeScriptsHeader.bottom
anchors.topMargin: base.textMargin anchors
anchors.left: parent.left {
anchors.leftMargin: UM.Theme.getSize("default_margin").width top: activeScriptsHeader.bottom
anchors.right: parent.right left: parent.left
anchors.rightMargin: base.textMargin right: parent.right
rightMargin: base.textMargin
topMargin: base.textMargin
leftMargin: UM.Theme.getSize("default_margin").width
}
height: childrenRect.height height: childrenRect.height
model: manager.scriptList model: manager.scriptList
delegate: Item delegate: Item
@ -84,8 +89,12 @@ UM.Dialog
id: activeScriptButton id: activeScriptButton
text: manager.getScriptLabelByKey(modelData.toString()) text: manager.getScriptLabelByKey(modelData.toString())
exclusiveGroup: selectedScriptGroup exclusiveGroup: selectedScriptGroup
width: parent.width
height: UM.Theme.getSize("setting").height
checkable: true checkable: true
checked: {
checked:
{
if (manager.selectedScriptIndex == index) if (manager.selectedScriptIndex == index)
{ {
base.activeScriptName = manager.getScriptLabelByKey(modelData.toString()) base.activeScriptName = manager.getScriptLabelByKey(modelData.toString())
@ -102,8 +111,7 @@ UM.Dialog
manager.setSelectedScriptIndex(index) manager.setSelectedScriptIndex(index)
base.activeScriptName = manager.getScriptLabelByKey(modelData.toString()) base.activeScriptName = manager.getScriptLabelByKey(modelData.toString())
} }
width: parent.width
height: UM.Theme.getSize("setting").height
style: ButtonStyle style: ButtonStyle
{ {
background: Rectangle background: Rectangle
@ -121,6 +129,7 @@ UM.Dialog
} }
} }
} }
Button Button
{ {
id: removeButton id: removeButton
@ -249,8 +258,8 @@ UM.Dialog
onTriggered: manager.addScriptToList(modelData.toString()) onTriggered: manager.addScriptToList(modelData.toString())
} }
onObjectAdded: scriptsMenu.insertItem(index, object); onObjectAdded: scriptsMenu.insertItem(index, object)
onObjectRemoved: scriptsMenu.removeItem(object); onObjectRemoved: scriptsMenu.removeItem(object)
} }
} }
} }
@ -268,12 +277,16 @@ UM.Dialog
{ {
id: scriptSpecsHeader id: scriptSpecsHeader
text: manager.selectedScriptIndex == -1 ? catalog.i18nc("@label", "Settings") : base.activeScriptName text: manager.selectedScriptIndex == -1 ? catalog.i18nc("@label", "Settings") : base.activeScriptName
anchors.top: parent.top anchors
anchors.topMargin: base.textMargin {
anchors.left: parent.left top: parent.top
anchors.leftMargin: base.textMargin topMargin: base.textMargin
anchors.right: parent.right left: parent.left
anchors.rightMargin: base.textMargin leftMargin: base.textMargin
right: parent.right
rightMargin: base.textMargin
}
elide: Text.ElideRight elide: Text.ElideRight
height: 20 * screenScaleFactor height: 20 * screenScaleFactor
font: UM.Theme.getFont("large_bold") font: UM.Theme.getFont("large_bold")
@ -283,11 +296,16 @@ UM.Dialog
ScrollView ScrollView
{ {
id: scrollView id: scrollView
anchors.top: scriptSpecsHeader.bottom anchors
anchors.topMargin: settingsPanel.textMargin {
anchors.left: parent.left top: scriptSpecsHeader.bottom
anchors.right: parent.right topMargin: settingsPanel.textMargin
anchors.bottom: parent.bottom left: parent.left
leftMargin: UM.Theme.getSize("default_margin").width
right: parent.right
bottom: parent.bottom
}
visible: manager.selectedScriptDefinitionId != "" visible: manager.selectedScriptDefinitionId != ""
style: UM.Theme.styles.scrollview; style: UM.Theme.styles.scrollview;
@ -297,11 +315,12 @@ UM.Dialog
spacing: UM.Theme.getSize("default_lining").height spacing: UM.Theme.getSize("default_lining").height
model: UM.SettingDefinitionsModel model: UM.SettingDefinitionsModel
{ {
id: definitionsModel; id: definitionsModel
containerId: manager.selectedScriptDefinitionId containerId: manager.selectedScriptDefinitionId
showAll: true showAll: true
} }
delegate:Loader
delegate: Loader
{ {
id: settingLoader id: settingLoader
@ -312,23 +331,24 @@ UM.Dialog
{ {
if(model.type != undefined) if(model.type != undefined)
{ {
return UM.Theme.getSize("section").height; return UM.Theme.getSize("section").height
} }
else else
{ {
return 0; return 0
} }
} }
else else
{ {
return 0; return 0
} }
} }
Behavior on height { NumberAnimation { duration: 100 } } Behavior on height { NumberAnimation { duration: 100 } }
opacity: provider.properties.enabled == "True" ? 1 : 0 opacity: provider.properties.enabled == "True" ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 100 } } Behavior on opacity { NumberAnimation { duration: 100 } }
enabled: opacity > 0 enabled: opacity > 0
property var definition: model property var definition: model
property var settingDefinitionsModel: definitionsModel property var settingDefinitionsModel: definitionsModel
property var propertyProvider: provider property var propertyProvider: provider
@ -339,11 +359,12 @@ UM.Dialog
//causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
asynchronous: model.type != "enum" && model.type != "extruder" asynchronous: model.type != "enum" && model.type != "extruder"
onLoaded: { onLoaded:
{
settingLoader.item.showRevertButton = false settingLoader.item.showRevertButton = false
settingLoader.item.showInheritButton = false settingLoader.item.showInheritButton = false
settingLoader.item.showLinkedSettingIcon = false settingLoader.item.showLinkedSettingIcon = false
settingLoader.item.doDepthIndentation = true settingLoader.item.doDepthIndentation = false
settingLoader.item.doQualityUserSettingEmphasis = false settingLoader.item.doQualityUserSettingEmphasis = false
} }
@ -395,18 +416,14 @@ UM.Dialog
onShowTooltip: onShowTooltip:
{ {
tooltip.text = text; tooltip.text = text
var position = settingLoader.mapToItem(settingsPanel, settingsPanel.x, 0); var position = settingLoader.mapToItem(settingsPanel, settingsPanel.x, 0)
tooltip.show(position); tooltip.show(position)
tooltip.target.x = position.x + 1 tooltip.target.x = position.x + 1
} }
onHideTooltip: onHideTooltip: tooltip.hide()
{
tooltip.hide();
}
} }
} }
} }
} }
@ -459,6 +476,7 @@ UM.Dialog
Cura.SettingUnknown { } Cura.SettingUnknown { }
} }
} }
rightButtons: Button rightButtons: Button
{ {
text: catalog.i18nc("@action:button", "Close") text: catalog.i18nc("@action:button", "Close")
@ -466,7 +484,8 @@ UM.Dialog
onClicked: dialog.accept() onClicked: dialog.accept()
} }
Button { Button
{
objectName: "postProcessingSaveAreaButton" objectName: "postProcessingSaveAreaButton"
visible: activeScriptsList.count > 0 visible: activeScriptsList.count > 0
height: UM.Theme.getSize("save_button_save_to_button").height height: UM.Theme.getSize("save_button_save_to_button").height
@ -474,8 +493,10 @@ UM.Dialog
tooltip: catalog.i18nc("@info:tooltip", "Change active post-processing scripts") tooltip: catalog.i18nc("@info:tooltip", "Change active post-processing scripts")
onClicked: dialog.show() onClicked: dialog.show()
style: ButtonStyle { style: ButtonStyle
background: Rectangle { {
background: Rectangle
{
id: deviceSelectionIcon id: deviceSelectionIcon
border.width: UM.Theme.getSize("default_lining").width border.width: UM.Theme.getSize("default_lining").width
border.color: !control.enabled ? UM.Theme.getColor("action_button_disabled_border") : border.color: !control.enabled ? UM.Theme.getColor("action_button_disabled_border") :
@ -485,12 +506,15 @@ UM.Dialog
control.pressed ? UM.Theme.getColor("action_button_active") : control.pressed ? UM.Theme.getColor("action_button_active") :
control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button") control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button")
Behavior on color { ColorAnimation { duration: 50; } } Behavior on color { ColorAnimation { duration: 50; } }
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: Math.round(UM.Theme.getSize("save_button_text_margin").width / 2); anchors.leftMargin: Math.round(UM.Theme.getSize("save_button_text_margin").width / 2)
width: parent.height width: parent.height
height: parent.height height: parent.height
UM.RecolorImage { UM.RecolorImage
{
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
width: Math.round(parent.width / 2) width: Math.round(parent.width / 2)
@ -498,11 +522,11 @@ UM.Dialog
sourceSize.height: height sourceSize.height: height
color: !control.enabled ? UM.Theme.getColor("action_button_disabled_text") : color: !control.enabled ? UM.Theme.getColor("action_button_disabled_text") :
control.pressed ? UM.Theme.getColor("action_button_active_text") : control.pressed ? UM.Theme.getColor("action_button_active_text") :
control.hovered ? UM.Theme.getColor("action_button_hovered_text") : UM.Theme.getColor("action_button_text"); control.hovered ? UM.Theme.getColor("action_button_hovered_text") : UM.Theme.getColor("action_button_text")
source: "postprocessing.svg" source: "postprocessing.svg"
} }
} }
label: Label{ } label: Label { }
} }
} }
} }

View file

@ -342,12 +342,16 @@ class SimulationView(CuraView):
return self._extruder_count return self._extruder_count
def getMinFeedrate(self) -> float: def getMinFeedrate(self) -> float:
if abs(self._min_feedrate - sys.float_info.max) < 10: # Some lenience due to floating point rounding.
return 0.0 # If it's still max-float, there are no measurements. Use 0 then.
return self._min_feedrate return self._min_feedrate
def getMaxFeedrate(self) -> float: def getMaxFeedrate(self) -> float:
return self._max_feedrate return self._max_feedrate
def getMinThickness(self) -> float: def getMinThickness(self) -> float:
if abs(self._min_thickness - sys.float_info.max) < 10: # Some lenience due to floating point rounding.
return 0.0 # If it's still max-float, there are no measurements. Use 0 then.
return self._min_thickness return self._min_thickness
def getMaxThickness(self) -> float: def getMaxThickness(self) -> float:

View file

@ -358,7 +358,7 @@ Cura.ExpandableComponent
width: parent.width width: parent.width
height: UM.Theme.getSize("layerview_row").height height: UM.Theme.getSize("layerview_row").height
Label Label //Minimum value.
{ {
text: text:
{ {
@ -383,9 +383,10 @@ Cura.ExpandableComponent
renderType: Text.NativeRendering renderType: Text.NativeRendering
} }
Label Label //Unit in the middle.
{ {
text: { text:
{
if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) if (UM.SimulationView.layerActivity && CuraApplication.platformActivity)
{ {
// Feedrate selected // Feedrate selected
@ -407,7 +408,7 @@ Cura.ExpandableComponent
font: UM.Theme.getFont("default") font: UM.Theme.getFont("default")
} }
Label Label //Maximum value.
{ {
text: { text: {
if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) if (UM.SimulationView.layerActivity && CuraApplication.platformActivity)

View file

@ -18,6 +18,10 @@ Item
height: centerSection.height height: centerSection.height
width: maximumWidth width: maximumWidth
// Enable keyboard navigation
Keys.onLeftPressed: navigateTo(currentIndex - 1)
Keys.onRightPressed: navigateTo(currentIndex + 1)
Item Item
{ {

View file

@ -24,6 +24,11 @@ Component
} }
} }
width: maximumWidth width: maximumWidth
// Enable keyboard navigation. NOTE: This is done here so that we can also potentially
// forward to the queue items in the future. (Deleting selected print job, etc.)
Keys.forwardTo: carousel
Component.onCompleted: forceActiveFocus()
UM.I18nCatalog UM.I18nCatalog
{ {
@ -59,7 +64,9 @@ Component
} }
width: parent.width width: parent.width
height: 264 * screenScaleFactor // TODO: Theme! height: 264 * screenScaleFactor // TODO: Theme!
MonitorCarousel {} MonitorCarousel {
id: carousel
}
} }
MonitorQueue MonitorQueue

View file

@ -47,7 +47,7 @@ def getMetaData() -> Dict[str, Any]:
}, },
"user": { "user": {
"get_version": upgrade.getCfgVersion, "get_version": upgrade.getCfgVersion,
"location": {"./user"} "location": {"./user", "./materials/*"}
}, },
"variant": { "variant": {
"get_version": upgrade.getCfgVersion, "get_version": upgrade.getCfgVersion,

View file

@ -16,7 +16,7 @@ Button
property alias iconSource: buttonIconLeft.source property alias iconSource: buttonIconLeft.source
property alias textFont: buttonText.font property alias textFont: buttonText.font
property alias cornerRadius: backgroundRect.radius property alias cornerRadius: backgroundRect.radius
property alias tooltip: tooltip.text property alias tooltip: tooltip.tooltipText
property alias cornerSide: backgroundRect.cornerSide property alias cornerSide: backgroundRect.cornerSide
property color color: UM.Theme.getColor("primary") property color color: UM.Theme.getColor("primary")
@ -31,6 +31,8 @@ Button
property alias shadowColor: shadow.color property alias shadowColor: shadow.color
property alias shadowEnabled: shadow.visible property alias shadowEnabled: shadow.visible
property alias toolTipContentAlignment: tooltip.contentAlignment
// This property is used to indicate whether the button has a fixed width or the width would depend on the contents // 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, // 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. // we elide the text to the right so the text will be cut off with the three dots at the end.
@ -110,11 +112,9 @@ Button
z: backgroundRect.z - 1 z: backgroundRect.z - 1
} }
ToolTip Cura.ToolTip
{ {
id: tooltip id: tooltip
text: "" visible: button.hovered
delay: 500
visible: text != "" && button.hovered
} }
} }

View file

@ -60,7 +60,6 @@ Item
leftPadding: UM.Theme.getSize("narrow_margin").width //Need more space than usual here for wide text. leftPadding: UM.Theme.getSize("narrow_margin").width //Need more space than usual here for wide text.
rightPadding: UM.Theme.getSize("narrow_margin").width rightPadding: UM.Theme.getSize("narrow_margin").width
tooltip: popup.opened ? "" : catalog.i18nc("@info:tooltip", "Select the active output device")
iconSource: popup.opened ? UM.Theme.getIcon("arrow_top") : UM.Theme.getIcon("arrow_bottom") iconSource: popup.opened ? UM.Theme.getIcon("arrow_top") : UM.Theme.getIcon("arrow_bottom")
color: UM.Theme.getColor("action_panel_secondary") color: UM.Theme.getColor("action_panel_secondary")
visible: (devicesModel.deviceCount > 1) visible: (devicesModel.deviceCount > 1)

View file

@ -123,6 +123,8 @@ Column
tooltip: text tooltip: text
fixedWidthMode: true fixedWidthMode: true
toolTipContentAlignment: Cura.ToolTip.ContentAlignment.AlignLeft
onClicked: UM.Controller.setActiveStage("PreviewStage") onClicked: UM.Controller.setActiveStage("PreviewStage")
visible: UM.Controller.activeStage != null && UM.Controller.activeStage.stageId != "PreviewStage" visible: UM.Controller.activeStage != null && UM.Controller.activeStage.stageId != "PreviewStage"

View file

@ -109,6 +109,7 @@ Column
fixedWidthMode: true fixedWidthMode: true
anchors.fill: parent anchors.fill: parent
text: catalog.i18nc("@button", "Slice") text: catalog.i18nc("@button", "Slice")
tooltip: catalog.i18nc("@label", "Start the slicing process")
enabled: widget.backendState != UM.Backend.Error enabled: widget.backendState != UM.Backend.Error
visible: widget.backendState == UM.Backend.NotStarted || widget.backendState == UM.Backend.Error visible: widget.backendState == UM.Backend.NotStarted || widget.backendState == UM.Backend.Error
onClicked: sliceOrStopSlicing() onClicked: sliceOrStopSlicing()
@ -134,10 +135,13 @@ Column
onPreferenceChanged: onPreferenceChanged:
{ {
var autoSlice = UM.Preferences.getValue("general/auto_slice") var autoSlice = UM.Preferences.getValue("general/auto_slice")
prepareButtons.autoSlice = autoSlice if(prepareButtons.autoSlice != autoSlice)
if(autoSlice)
{ {
CuraApplication.backend.forceSlice() prepareButtons.autoSlice = autoSlice
if(autoSlice)
{
CuraApplication.backend.forceSlice()
}
} }
} }
} }

View file

@ -29,6 +29,9 @@ Item
source: UM.Theme.getImage("logo") source: UM.Theme.getImage("logo")
width: UM.Theme.getSize("logo").width width: UM.Theme.getSize("logo").width
height: UM.Theme.getSize("logo").height height: UM.Theme.getSize("logo").height
sourceSize.width: width
sourceSize.height: height
} }
Row Row

View file

@ -7,16 +7,18 @@ import QtQuick.Controls 1.4
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Instantiator { Instantiator
model: UM.ContainerStacksModel { {
filter: {"type": "machine", "um_network_key": null} model: Cura.PrintersModel {}
}
MenuItem { MenuItem
text: model.name; {
checkable: true; text: model.name
checkable: true
checked: Cura.MachineManager.activeMachineId == model.id checked: Cura.MachineManager.activeMachineId == model.id
exclusiveGroup: group; exclusiveGroup: group
onTriggered: Cura.MachineManager.setActiveMachine(model.id); visible: !model.hasRemoteConnection
onTriggered: Cura.MachineManager.setActiveMachine(model.id)
} }
onObjectAdded: menu.insertItem(index, object) onObjectAdded: menu.insertItem(index, object)
onObjectRemoved: menu.removeItem(object) onObjectRemoved: menu.removeItem(object)

View file

@ -7,18 +7,17 @@ import QtQuick.Controls 1.4
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Instantiator { Instantiator
model: UM.ContainerStacksModel { {
filter: {"type": "machine", "um_network_key": "*", "hidden": "False"} model: Cura.PrintersModel {}
} MenuItem
MenuItem { {
// TODO: Use printer_group icon when it's a cluster. Not use it for now since it doesn't look as expected
// iconSource: UM.Theme.getIcon("printer_single")
text: model.metadata["connect_group_name"] text: model.metadata["connect_group_name"]
checkable: true; checkable: true
visible: model.hasRemoteConnection
checked: Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"] checked: Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"]
exclusiveGroup: group; exclusiveGroup: group
onTriggered: Cura.MachineManager.setActiveMachine(model.id); onTriggered: Cura.MachineManager.setActiveMachine(model.id)
} }
onObjectAdded: menu.insertItem(index, object) onObjectAdded: menu.insertItem(index, object)
onObjectRemoved: menu.removeItem(object) onObjectRemoved: menu.removeItem(object)

View file

@ -10,7 +10,7 @@ import QtQuick.Dialogs 1.2
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Rectangle Item
{ {
id: brand_section id: brand_section

View file

@ -15,7 +15,7 @@ Rectangle
id: materialSlot id: materialSlot
property var material: null property var material: null
property var hovered: false property var hovered: false
property var is_favorite: material != null ? material.is_favorite : false property var is_favorite: material != null && material.is_favorite
height: UM.Theme.getSize("favorites_row").height height: UM.Theme.getSize("favorites_row").height
width: parent.width width: parent.width
@ -73,11 +73,9 @@ Rectangle
if (materialSlot.is_favorite) if (materialSlot.is_favorite)
{ {
base.materialManager.removeFavorite(material.root_material_id) base.materialManager.removeFavorite(material.root_material_id)
materialSlot.is_favorite = false
return return
} }
base.materialManager.addFavorite(material.root_material_id) base.materialManager.addFavorite(material.root_material_id)
materialSlot.is_favorite = true
return return
} }
style: ButtonStyle style: ButtonStyle

View file

@ -10,7 +10,7 @@ import QtQuick.Dialogs 1.2
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Rectangle Item
{ {
id: material_type_section id: material_type_section
property var materialType property var materialType

View file

@ -2,9 +2,7 @@
// 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
import QtQuick.Controls 1.1 import QtQuick.Controls 2.3
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import UM 1.0 as UM import UM 1.0 as UM
@ -57,5 +55,6 @@ UM.PointingRectangle {
textFormat: Text.RichText textFormat: Text.RichText
font: UM.Theme.getFont("default"); font: UM.Theme.getFont("default");
color: UM.Theme.getColor("tooltip_text"); color: UM.Theme.getColor("tooltip_text");
renderType: Text.NativeRendering
} }
} }

63
resources/qml/ToolTip.qml Normal file
View file

@ -0,0 +1,63 @@
// 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.0 as UM
import Cura 1.0 as Cura
ToolTip
{
enum ContentAlignment
{
AlignLeft,
AlignRight
}
// Defines the alignment of the content, by default to the left
property int contentAlignment: Cura.ToolTip.ContentAlignment.AlignRight
property alias tooltipText: tooltip.text
property var targetPoint: Qt.point(parent.x, y + Math.round(height/2))
id: tooltip
text: ""
delay: 500
font: UM.Theme.getFont("default")
// If the text is not set, just set the height to 0 to prevent it from showing
height: text != "" ? label.contentHeight + 2 * UM.Theme.getSize("thin_margin").width: 0
x:
{
if (contentAlignment == Cura.ToolTip.ContentAlignment.AlignLeft)
{
return (label.width + Math.round(UM.Theme.getSize("default_arrow").width * 1.2) + padding * 2) * -1
}
return parent.width + Math.round(UM.Theme.getSize("default_arrow").width * 1.2 + padding)
}
y: Math.round(parent.height / 2 - label.height / 2 ) - padding
padding: UM.Theme.getSize("thin_margin").width
background: UM.PointingRectangle
{
id: backgroundRect
color: UM.Theme.getColor("tooltip")
target: Qt.point(targetPoint.x - tooltip.x, targetPoint.y - tooltip.y)
arrowSize: UM.Theme.getSize("default_arrow").width
}
contentItem: Label
{
id: label
text: tooltip.text
font: tooltip.font
wrapMode: Text.Wrap
textFormat: Text.RichText
color: UM.Theme.getColor("tooltip_text")
renderType: Text.NativeRendering
}
}

View file

@ -96,4 +96,11 @@ Button
height: UM.Theme.getSize("button_icon").height height: UM.Theme.getSize("button_icon").height
} }
} }
Cura.ToolTip
{
id: tooltip
tooltipText: base.text
visible: base.hovered
}
} }

View file

@ -14,4 +14,5 @@ PrinterTypeLabel 1.0 PrinterTypeLabel.qml
ViewsSelector 1.0 ViewsSelector.qml ViewsSelector 1.0 ViewsSelector.qml
ToolbarButton 1.0 ToolbarButton.qml ToolbarButton 1.0 ToolbarButton.qml
SettingView 1.0 SettingView.qml SettingView 1.0 SettingView.qml
ProfileMenu 1.0 ProfileMenu.qml ProfileMenu 1.0 ProfileMenu.qml
ToolTip 1.0 ToolTip.qml

View file

@ -28,6 +28,7 @@
"machine_selector_bar": [39, 44, 48, 255], "machine_selector_bar": [39, 44, 48, 255],
"machine_selector_active": [39, 44, 48, 255], "machine_selector_active": [39, 44, 48, 255],
"machine_selector_printer_icon": [204, 204, 204, 255],
"text": [255, 255, 255, 204], "text": [255, 255, 255, 204],
"text_detail": [255, 255, 255, 172], "text_detail": [255, 255, 255, 172],