mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-25 15:44:04 -06:00
Merge branch '4.0' into CURA-6004_missing_tooltips
This commit is contained in:
commit
17cddac024
214 changed files with 2873 additions and 5497 deletions
|
@ -44,7 +44,7 @@ class Account(QObject):
|
|||
OAUTH_SERVER_URL= self._oauth_root,
|
||||
CALLBACK_PORT=self._callback_port,
|
||||
CALLBACK_URL="http://localhost:{}/callback".format(self._callback_port),
|
||||
CLIENT_ID="um---------------ultimaker_cura_drive_plugin",
|
||||
CLIENT_ID="um----------------------------ultimaker_cura",
|
||||
CLIENT_SCOPES="account.user.read drive.backup.read drive.backup.write packages.download packages.rating.read packages.rating.write",
|
||||
AUTH_DATA_PREFERENCE_KEY="general/ultimaker_auth_data",
|
||||
AUTH_SUCCESS_REDIRECT="{}/app/auth-success".format(self._oauth_root),
|
||||
|
|
|
@ -83,7 +83,14 @@ class BuildVolume(SceneNode):
|
|||
" with printed models."), title = catalog.i18nc("@info:title", "Build Volume"))
|
||||
|
||||
self._global_container_stack = None
|
||||
|
||||
self._stack_change_timer = QTimer()
|
||||
self._stack_change_timer.setInterval(100)
|
||||
self._stack_change_timer.setSingleShot(True)
|
||||
self._stack_change_timer.timeout.connect(self._onStackChangeTimerFinished)
|
||||
|
||||
self._application.globalContainerStackChanged.connect(self._onStackChanged)
|
||||
|
||||
self._onStackChanged()
|
||||
|
||||
self._engine_ready = False
|
||||
|
@ -105,6 +112,8 @@ class BuildVolume(SceneNode):
|
|||
self._setting_change_timer.setSingleShot(True)
|
||||
self._setting_change_timer.timeout.connect(self._onSettingChangeTimerFinished)
|
||||
|
||||
|
||||
|
||||
# Must be after setting _build_volume_message, apparently that is used in getMachineManager.
|
||||
# activeQualityChanged is always emitted after setActiveVariant, setActiveMaterial and setActiveQuality.
|
||||
# Therefore this works.
|
||||
|
@ -479,6 +488,8 @@ class BuildVolume(SceneNode):
|
|||
maximum = Vector(max_w - bed_adhesion_size - 1, max_h - self._raft_thickness - self._extra_z_clearance, max_d - disallowed_area_size + bed_adhesion_size - 1)
|
||||
)
|
||||
|
||||
self._application.getController().getScene()._maximum_bounds = scale_to_max_bounds
|
||||
|
||||
self.updateNodeBoundaryCheck()
|
||||
|
||||
def getBoundingBox(self) -> AxisAlignedBox:
|
||||
|
@ -524,8 +535,11 @@ class BuildVolume(SceneNode):
|
|||
if extra_z != self._extra_z_clearance:
|
||||
self._extra_z_clearance = extra_z
|
||||
|
||||
## Update the build volume visualization
|
||||
def _onStackChanged(self):
|
||||
self._stack_change_timer.start()
|
||||
|
||||
## Update the build volume visualization
|
||||
def _onStackChangeTimerFinished(self):
|
||||
if self._global_container_stack:
|
||||
self._global_container_stack.propertyChanged.disconnect(self._onSettingPropertyChanged)
|
||||
extruders = ExtruderManager.getInstance().getActiveExtruderStacks()
|
||||
|
|
|
@ -36,18 +36,14 @@ else:
|
|||
except ImportError:
|
||||
CuraDebugMode = False # [CodeStyle: Reflecting imported value]
|
||||
|
||||
# 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,
|
||||
# List of exceptions that should not be considered "fatal" and abort the program.
|
||||
# These are primarily some exception types that we simply skip
|
||||
skip_exception_types = [
|
||||
SystemExit,
|
||||
KeyboardInterrupt,
|
||||
GeneratorExit
|
||||
]
|
||||
|
||||
|
||||
class CrashHandler:
|
||||
crash_url = "https://stats.ultimaker.com/api/cura"
|
||||
|
||||
|
@ -70,7 +66,7 @@ class CrashHandler:
|
|||
# If Cura has fully started, we only show fatal errors.
|
||||
# If Cura has not fully started yet, we always show the early crash dialog. Otherwise, Cura will just crash
|
||||
# without any information.
|
||||
if has_started and exception_type not in fatal_exception_types:
|
||||
if has_started and exception_type in skip_exception_types:
|
||||
return
|
||||
|
||||
if not has_started:
|
||||
|
@ -387,7 +383,7 @@ class CrashHandler:
|
|||
Application.getInstance().callLater(self._show)
|
||||
|
||||
def _show(self):
|
||||
# When the exception is not in the fatal_exception_types list, the dialog is not created, so we don't need to show it
|
||||
# When the exception is in the skip_exception_types list, the dialog is not created, so we don't need to show it
|
||||
if self.dialog:
|
||||
self.dialog.exec_()
|
||||
os._exit(1)
|
||||
|
|
|
@ -134,7 +134,7 @@ except ImportError:
|
|||
CuraVersion = "master" # [CodeStyle: Reflecting imported value]
|
||||
CuraBuildType = ""
|
||||
CuraDebugMode = False
|
||||
CuraSDKVersion = "5.0.0"
|
||||
CuraSDKVersion = "6.0.0"
|
||||
|
||||
|
||||
class CuraApplication(QtApplication):
|
||||
|
@ -181,7 +181,6 @@ class CuraApplication(QtApplication):
|
|||
# Variables set from CLI
|
||||
self._files_to_open = []
|
||||
self._use_single_instance = False
|
||||
self._trigger_early_crash = False # For debug only
|
||||
|
||||
self._single_instance = None
|
||||
|
||||
|
@ -206,6 +205,8 @@ class CuraApplication(QtApplication):
|
|||
self._container_manager = None
|
||||
|
||||
self._object_manager = None
|
||||
self._extruders_model = None
|
||||
self._extruders_model_with_optional = None
|
||||
self._build_plate_model = None
|
||||
self._multi_build_plate_model = None
|
||||
self._setting_visibility_presets_model = None
|
||||
|
@ -292,7 +293,10 @@ class CuraApplication(QtApplication):
|
|||
sys.exit(0)
|
||||
|
||||
self._use_single_instance = self._cli_args.single_instance
|
||||
self._trigger_early_crash = self._cli_args.trigger_early_crash
|
||||
# FOR TESTING ONLY
|
||||
if self._cli_args.trigger_early_crash:
|
||||
assert not "This crash is triggered by the trigger_early_crash command line argument."
|
||||
|
||||
for filename in self._cli_args.file:
|
||||
self._files_to_open.append(os.path.abspath(filename))
|
||||
|
||||
|
@ -860,6 +864,19 @@ class CuraApplication(QtApplication):
|
|||
self._object_manager = ObjectsModel.createObjectsModel()
|
||||
return self._object_manager
|
||||
|
||||
@pyqtSlot(result = QObject)
|
||||
def getExtrudersModel(self, *args) -> "ExtrudersModel":
|
||||
if self._extruders_model is None:
|
||||
self._extruders_model = ExtrudersModel(self)
|
||||
return self._extruders_model
|
||||
|
||||
@pyqtSlot(result = QObject)
|
||||
def getExtrudersModelWithOptional(self, *args) -> "ExtrudersModel":
|
||||
if self._extruders_model_with_optional is None:
|
||||
self._extruders_model_with_optional = ExtrudersModel(self)
|
||||
self._extruders_model_with_optional.setAddOptionalExtruder(True)
|
||||
return self._extruders_model_with_optional
|
||||
|
||||
@pyqtSlot(result = QObject)
|
||||
def getMultiBuildPlateModel(self, *args) -> MultiBuildPlateModel:
|
||||
if self._multi_build_plate_model is None:
|
||||
|
|
|
@ -64,21 +64,21 @@ class MachineErrorChecker(QObject):
|
|||
|
||||
def _onMachineChanged(self) -> None:
|
||||
if self._global_stack:
|
||||
self._global_stack.propertyChanged.disconnect(self.startErrorCheck)
|
||||
self._global_stack.propertyChanged.disconnect(self.startErrorCheckPropertyChanged)
|
||||
self._global_stack.containersChanged.disconnect(self.startErrorCheck)
|
||||
|
||||
for extruder in self._global_stack.extruders.values():
|
||||
extruder.propertyChanged.disconnect(self.startErrorCheck)
|
||||
extruder.propertyChanged.disconnect(self.startErrorCheckPropertyChanged)
|
||||
extruder.containersChanged.disconnect(self.startErrorCheck)
|
||||
|
||||
self._global_stack = self._machine_manager.activeMachine
|
||||
|
||||
if self._global_stack:
|
||||
self._global_stack.propertyChanged.connect(self.startErrorCheck)
|
||||
self._global_stack.propertyChanged.connect(self.startErrorCheckPropertyChanged)
|
||||
self._global_stack.containersChanged.connect(self.startErrorCheck)
|
||||
|
||||
for extruder in self._global_stack.extruders.values():
|
||||
extruder.propertyChanged.connect(self.startErrorCheck)
|
||||
extruder.propertyChanged.connect(self.startErrorCheckPropertyChanged)
|
||||
extruder.containersChanged.connect(self.startErrorCheck)
|
||||
|
||||
hasErrorUpdated = pyqtSignal()
|
||||
|
@ -93,6 +93,13 @@ class MachineErrorChecker(QObject):
|
|||
def needToWaitForResult(self) -> bool:
|
||||
return self._need_to_check or self._check_in_progress
|
||||
|
||||
# Start the error check for property changed
|
||||
# this is seperate from the startErrorCheck because it ignores a number property types
|
||||
def startErrorCheckPropertyChanged(self, key, property_name):
|
||||
if property_name != "value":
|
||||
return
|
||||
self.startErrorCheck()
|
||||
|
||||
# Starts the error check timer to schedule a new error check.
|
||||
def startErrorCheck(self, *args) -> None:
|
||||
if not self._check_in_progress:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
from typing import Optional, Dict, Set
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty
|
||||
from UM.Qt.ListModel import ListModel
|
||||
|
@ -9,6 +10,9 @@ from UM.Qt.ListModel import ListModel
|
|||
# Those 2 models are used by the material drop down menu to show generic materials and branded materials separately.
|
||||
# The extruder position defined here is being used to bound a menu to the correct extruder. This is used in the top
|
||||
# bar menu "Settings" -> "Extruder nr" -> "Material" -> this menu
|
||||
from cura.Machines.MaterialNode import MaterialNode
|
||||
|
||||
|
||||
class BaseMaterialsModel(ListModel):
|
||||
|
||||
extruderPositionChanged = pyqtSignal()
|
||||
|
@ -54,8 +58,8 @@ class BaseMaterialsModel(ListModel):
|
|||
self._extruder_position = 0
|
||||
self._extruder_stack = None
|
||||
|
||||
self._available_materials = None
|
||||
self._favorite_ids = None
|
||||
self._available_materials = None # type: Optional[Dict[str, MaterialNode]]
|
||||
self._favorite_ids = set() # type: Set[str]
|
||||
|
||||
def _updateExtruderStack(self):
|
||||
global_stack = self._machine_manager.activeMachine
|
||||
|
@ -102,8 +106,10 @@ class BaseMaterialsModel(ListModel):
|
|||
return False
|
||||
|
||||
extruder_stack = global_stack.extruders[extruder_position]
|
||||
|
||||
self._available_materials = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack, extruder_stack)
|
||||
available_materials = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack, extruder_stack)
|
||||
if available_materials == self._available_materials:
|
||||
return False
|
||||
self._available_materials = available_materials
|
||||
if self._available_materials is None:
|
||||
return False
|
||||
|
||||
|
|
|
@ -4,17 +4,14 @@
|
|||
from UM.Logger import Logger
|
||||
from cura.Machines.Models.BaseMaterialsModel import BaseMaterialsModel
|
||||
|
||||
class FavoriteMaterialsModel(BaseMaterialsModel):
|
||||
|
||||
class FavoriteMaterialsModel(BaseMaterialsModel):
|
||||
def __init__(self, parent = None):
|
||||
super().__init__(parent)
|
||||
self._update()
|
||||
|
||||
def _update(self):
|
||||
|
||||
# Perform standard check and reset if the check fails
|
||||
if not self._canUpdate():
|
||||
self.setItems([])
|
||||
return
|
||||
|
||||
# Get updated list of favorites
|
||||
|
|
|
@ -11,10 +11,7 @@ class GenericMaterialsModel(BaseMaterialsModel):
|
|||
self._update()
|
||||
|
||||
def _update(self):
|
||||
|
||||
# Perform standard check and reset if the check fails
|
||||
if not self._canUpdate():
|
||||
self.setItems([])
|
||||
return
|
||||
|
||||
# Get updated list of favorites
|
||||
|
|
|
@ -28,12 +28,8 @@ class MaterialBrandsModel(BaseMaterialsModel):
|
|||
self._update()
|
||||
|
||||
def _update(self):
|
||||
|
||||
# Perform standard check and reset if the check fails
|
||||
if not self._canUpdate():
|
||||
self.setItems([])
|
||||
return
|
||||
|
||||
# Get updated list of favorites
|
||||
self._favorite_ids = self._material_manager.getFavorites()
|
||||
|
||||
|
|
|
@ -33,8 +33,6 @@ class NozzleModel(ListModel):
|
|||
def _update(self):
|
||||
Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__))
|
||||
|
||||
self.items.clear()
|
||||
|
||||
global_stack = self._machine_manager.activeMachine
|
||||
if global_stack is None:
|
||||
self.setItems([])
|
||||
|
|
|
@ -81,9 +81,14 @@ class AuthorizationHelpers:
|
|||
# \param access_token: The encoded JWT token.
|
||||
# \return: Dict containing some profile data.
|
||||
def parseJWT(self, access_token: str) -> Optional["UserProfile"]:
|
||||
try:
|
||||
token_request = requests.get("{}/check-token".format(self._settings.OAUTH_SERVER_URL), headers = {
|
||||
"Authorization": "Bearer {}".format(access_token)
|
||||
})
|
||||
except ConnectionError:
|
||||
# Connection was suddenly dropped. Nothing we can do about that.
|
||||
Logger.logException("e", "Something failed while attempting to parse the JWT token")
|
||||
return None
|
||||
if token_request.status_code not in (200, 201):
|
||||
Logger.log("w", "Could not retrieve token data from auth server: %s", token_request.text)
|
||||
return None
|
||||
|
|
|
@ -187,7 +187,10 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
|||
for child in self._node.getChildren():
|
||||
child_hull = child.callDecoration("_compute2DConvexHull")
|
||||
if child_hull:
|
||||
try:
|
||||
points = numpy.append(points, child_hull.getPoints(), axis = 0)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if points.size < 3:
|
||||
return None
|
||||
|
|
|
@ -83,6 +83,7 @@ class ExtruderManager(QObject):
|
|||
# \param index The index of the new active extruder.
|
||||
@pyqtSlot(int)
|
||||
def setActiveExtruderIndex(self, index: int) -> None:
|
||||
if self._active_extruder_index != index:
|
||||
self._active_extruder_index = index
|
||||
self.activeExtruderChanged.emit()
|
||||
|
||||
|
@ -344,6 +345,7 @@ class ExtruderManager(QObject):
|
|||
if extruders_changed:
|
||||
self.extrudersChanged.emit(global_stack_id)
|
||||
self.setActiveExtruderIndex(0)
|
||||
self.activeExtruderChanged.emit()
|
||||
|
||||
# After 3.4, all single-extrusion machines have their own extruder definition files instead of reusing
|
||||
# "fdmextruder". We need to check a machine here so its extruder definition is correct according to this.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot, pyqtProperty, QTimer
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty, QTimer
|
||||
from typing import Iterable
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
|
@ -78,8 +78,6 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
|||
self._update_extruder_timer.setSingleShot(True)
|
||||
self._update_extruder_timer.timeout.connect(self.__updateExtruders)
|
||||
|
||||
self._simple_names = False
|
||||
|
||||
self._active_machine_extruders = [] # type: Iterable[ExtruderStack]
|
||||
self._add_optional_extruder = False
|
||||
|
||||
|
@ -101,21 +99,6 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
|||
def addOptionalExtruder(self):
|
||||
return self._add_optional_extruder
|
||||
|
||||
## Set the simpleNames property.
|
||||
def setSimpleNames(self, simple_names):
|
||||
if simple_names != self._simple_names:
|
||||
self._simple_names = simple_names
|
||||
self.simpleNamesChanged.emit()
|
||||
self._updateExtruders()
|
||||
|
||||
## Emitted when the simpleNames property changes.
|
||||
simpleNamesChanged = pyqtSignal()
|
||||
|
||||
## Whether or not the model should show all definitions regardless of visibility.
|
||||
@pyqtProperty(bool, fset = setSimpleNames, notify = simpleNamesChanged)
|
||||
def simpleNames(self):
|
||||
return self._simple_names
|
||||
|
||||
## Links to the stack-changed signal of the new extruders when an extruder
|
||||
# is swapped out or added in the current machine.
|
||||
#
|
||||
|
@ -221,9 +204,14 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
|||
"enabled": True,
|
||||
"color": "#ffffff",
|
||||
"index": -1,
|
||||
"definition": ""
|
||||
"definition": "",
|
||||
"material": "",
|
||||
"variant": "",
|
||||
"stack": None,
|
||||
"material_brand": "",
|
||||
"color_name": "",
|
||||
}
|
||||
items.append(item)
|
||||
|
||||
if self._items != items:
|
||||
self.setItems(items)
|
||||
self.modelChanged.emit()
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
from collections import defaultdict
|
||||
import threading
|
||||
from typing import Any, Dict, Optional, Set, TYPE_CHECKING
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSlot
|
||||
from typing import Any, Dict, Optional, Set, TYPE_CHECKING, List
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSlot, pyqtSignal
|
||||
|
||||
from UM.Decorators import override
|
||||
from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
|
||||
|
@ -42,13 +42,23 @@ class GlobalStack(CuraContainerStack):
|
|||
# Per thread we have our own resolving_settings, or strange things sometimes occur.
|
||||
self._resolving_settings = defaultdict(set) #type: Dict[str, Set[str]] # keys are thread names
|
||||
|
||||
extrudersChanged = pyqtSignal()
|
||||
|
||||
## Get the list of extruders of this stack.
|
||||
#
|
||||
# \return The extruders registered with this stack.
|
||||
@pyqtProperty("QVariantMap")
|
||||
@pyqtProperty("QVariantMap", notify = extrudersChanged)
|
||||
def extruders(self) -> Dict[str, "ExtruderStack"]:
|
||||
return self._extruders
|
||||
|
||||
@pyqtProperty("QVariantList", notify = extrudersChanged)
|
||||
def extruderList(self) -> List["ExtruderStack"]:
|
||||
result_tuple_list = sorted(list(self.extruders.items()), key=lambda x: int(x[0]))
|
||||
result_list = [item[1] for item in result_tuple_list]
|
||||
|
||||
machine_extruder_count = self.getProperty("machine_extruder_count", "value")
|
||||
return result_list[:machine_extruder_count]
|
||||
|
||||
@classmethod
|
||||
def getLoadingPriority(cls) -> int:
|
||||
return 2
|
||||
|
|
|
@ -88,12 +88,14 @@ class MachineManager(QObject):
|
|||
|
||||
self._onGlobalContainerChanged()
|
||||
|
||||
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged)
|
||||
extruder_manager = self._application.getExtruderManager()
|
||||
|
||||
extruder_manager.activeExtruderChanged.connect(self._onActiveExtruderStackChanged)
|
||||
self._onActiveExtruderStackChanged()
|
||||
|
||||
ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeMaterialChanged)
|
||||
ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeVariantChanged)
|
||||
ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeQualityChanged)
|
||||
extruder_manager.activeExtruderChanged.connect(self.activeMaterialChanged)
|
||||
extruder_manager.activeExtruderChanged.connect(self.activeVariantChanged)
|
||||
extruder_manager.activeExtruderChanged.connect(self.activeQualityChanged)
|
||||
|
||||
self.globalContainerChanged.connect(self.activeStackChanged)
|
||||
self.globalValueChanged.connect(self.activeStackValueChanged)
|
||||
|
@ -1527,6 +1529,10 @@ class MachineManager(QObject):
|
|||
def activeQualityChangesGroup(self) -> Optional["QualityChangesGroup"]:
|
||||
return self._current_quality_changes_group
|
||||
|
||||
@pyqtProperty(bool, notify = activeQualityChangesGroupChanged)
|
||||
def hasCustomQuality(self) -> bool:
|
||||
return self._current_quality_changes_group is not None
|
||||
|
||||
@pyqtProperty(str, notify = activeQualityGroupChanged)
|
||||
def activeQualityOrQualityChangesName(self) -> str:
|
||||
name = empty_quality_container.getName()
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
from typing import Set
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty
|
||||
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot
|
||||
|
||||
from UM.Application import Application
|
||||
|
||||
|
@ -16,15 +17,11 @@ class SimpleModeSettingsManager(QObject):
|
|||
self._is_profile_user_created = False # True when profile was custom created by user
|
||||
|
||||
self._machine_manager.activeStackValueChanged.connect(self._updateIsProfileCustomized)
|
||||
self._machine_manager.activeQualityGroupChanged.connect(self._updateIsProfileUserCreated)
|
||||
self._machine_manager.activeQualityChangesGroupChanged.connect(self._updateIsProfileUserCreated)
|
||||
|
||||
# update on create as the activeQualityChanged signal is emitted before this manager is created when Cura starts
|
||||
self._updateIsProfileCustomized()
|
||||
self._updateIsProfileUserCreated()
|
||||
|
||||
isProfileCustomizedChanged = pyqtSignal()
|
||||
isProfileUserCreatedChanged = pyqtSignal()
|
||||
|
||||
@pyqtProperty(bool, notify = isProfileCustomizedChanged)
|
||||
def isProfileCustomized(self):
|
||||
|
@ -57,33 +54,6 @@ class SimpleModeSettingsManager(QObject):
|
|||
self._is_profile_customized = has_customized_user_settings
|
||||
self.isProfileCustomizedChanged.emit()
|
||||
|
||||
@pyqtProperty(bool, notify = isProfileUserCreatedChanged)
|
||||
def isProfileUserCreated(self):
|
||||
return self._is_profile_user_created
|
||||
|
||||
def _updateIsProfileUserCreated(self):
|
||||
quality_changes_keys = set()
|
||||
|
||||
if not self._machine_manager.activeMachine:
|
||||
return False
|
||||
|
||||
global_stack = self._machine_manager.activeMachine
|
||||
|
||||
# check quality changes settings in the global stack
|
||||
quality_changes_keys.update(global_stack.qualityChanges.getAllKeys())
|
||||
|
||||
# check quality changes settings in the extruder stacks
|
||||
if global_stack.extruders:
|
||||
for extruder_stack in global_stack.extruders.values():
|
||||
quality_changes_keys.update(extruder_stack.qualityChanges.getAllKeys())
|
||||
|
||||
# check if the qualityChanges container is not empty (meaning it is a user created profile)
|
||||
has_quality_changes = len(quality_changes_keys) > 0
|
||||
|
||||
if has_quality_changes != self._is_profile_user_created:
|
||||
self._is_profile_user_created = has_quality_changes
|
||||
self.isProfileUserCreatedChanged.emit()
|
||||
|
||||
# These are the settings included in the Simple ("Recommended") Mode, so only when the other settings have been
|
||||
# changed, we consider it as a user customized profile in the Simple ("Recommended") Mode.
|
||||
__ignored_custom_setting_keys = ["support_enable",
|
||||
|
|
|
@ -24,10 +24,6 @@ class CuraStage(Stage):
|
|||
def mainComponent(self) -> QUrl:
|
||||
return self.getDisplayComponent("main")
|
||||
|
||||
@pyqtProperty(QUrl, constant = True)
|
||||
def sidebarComponent(self) -> QUrl:
|
||||
return self.getDisplayComponent("sidebar")
|
||||
|
||||
@pyqtProperty(QUrl, constant = True)
|
||||
def stageMenuComponent(self) -> QUrl:
|
||||
return self.getDisplayComponent("menu")
|
|
@ -17,12 +17,6 @@ parser.add_argument("--debug",
|
|||
default = False,
|
||||
help = "Turn on the debug mode by setting this option."
|
||||
)
|
||||
parser.add_argument("--trigger-early-crash",
|
||||
dest = "trigger_early_crash",
|
||||
action = "store_true",
|
||||
default = False,
|
||||
help = "FOR TESTING ONLY. Trigger an early crash to show the crash dialog."
|
||||
)
|
||||
known_args = vars(parser.parse_known_args()[0])
|
||||
|
||||
if not known_args["debug"]:
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "3MF Reader",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides support for reading 3MF files.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "3MF Writer",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides support for writing 3MF files.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Changelog",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Shows changes since latest checked version.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -203,7 +203,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||
|
||||
@pyqtSlot()
|
||||
def stopSlicing(self) -> None:
|
||||
self.backendStateChange.emit(BackendState.NotStarted)
|
||||
self.setState(BackendState.NotStarted)
|
||||
if self._slicing: # We were already slicing. Stop the old job.
|
||||
self._terminate()
|
||||
self._createSocket()
|
||||
|
@ -322,7 +322,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._start_slice_job = None
|
||||
|
||||
if job.isCancelled() or job.getError() or job.getResult() == StartJobResult.Error:
|
||||
self.backendStateChange.emit(BackendState.Error)
|
||||
self.setState(BackendState.Error)
|
||||
self.backendError.emit(job)
|
||||
return
|
||||
|
||||
|
@ -331,10 +331,10 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._error_message = Message(catalog.i18nc("@info:status",
|
||||
"Unable to slice with the current material as it is incompatible with the selected machine or configuration."), title = catalog.i18nc("@info:title", "Unable to slice"))
|
||||
self._error_message.show()
|
||||
self.backendStateChange.emit(BackendState.Error)
|
||||
self.setState(BackendState.Error)
|
||||
self.backendError.emit(job)
|
||||
else:
|
||||
self.backendStateChange.emit(BackendState.NotStarted)
|
||||
self.setState(BackendState.NotStarted)
|
||||
return
|
||||
|
||||
if job.getResult() == StartJobResult.SettingError:
|
||||
|
@ -362,10 +362,10 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current settings. The following settings have errors: {0}").format(", ".join(error_labels)),
|
||||
title = catalog.i18nc("@info:title", "Unable to slice"))
|
||||
self._error_message.show()
|
||||
self.backendStateChange.emit(BackendState.Error)
|
||||
self.setState(BackendState.Error)
|
||||
self.backendError.emit(job)
|
||||
else:
|
||||
self.backendStateChange.emit(BackendState.NotStarted)
|
||||
self.setState(BackendState.NotStarted)
|
||||
return
|
||||
|
||||
elif job.getResult() == StartJobResult.ObjectSettingError:
|
||||
|
@ -386,7 +386,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice due to some per-model settings. The following settings have errors on one or more models: {error_labels}").format(error_labels = ", ".join(errors.values())),
|
||||
title = catalog.i18nc("@info:title", "Unable to slice"))
|
||||
self._error_message.show()
|
||||
self.backendStateChange.emit(BackendState.Error)
|
||||
self.setState(BackendState.Error)
|
||||
self.backendError.emit(job)
|
||||
return
|
||||
|
||||
|
@ -395,16 +395,16 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice because the prime tower or prime position(s) are invalid."),
|
||||
title = catalog.i18nc("@info:title", "Unable to slice"))
|
||||
self._error_message.show()
|
||||
self.backendStateChange.emit(BackendState.Error)
|
||||
self.setState(BackendState.Error)
|
||||
self.backendError.emit(job)
|
||||
else:
|
||||
self.backendStateChange.emit(BackendState.NotStarted)
|
||||
self.setState(BackendState.NotStarted)
|
||||
|
||||
if job.getResult() == StartJobResult.ObjectsWithDisabledExtruder:
|
||||
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice because there are objects associated with disabled Extruder %s." % job.getMessage()),
|
||||
title = catalog.i18nc("@info:title", "Unable to slice"))
|
||||
self._error_message.show()
|
||||
self.backendStateChange.emit(BackendState.Error)
|
||||
self.setState(BackendState.Error)
|
||||
self.backendError.emit(job)
|
||||
return
|
||||
|
||||
|
@ -413,10 +413,10 @@ class CuraEngineBackend(QObject, Backend):
|
|||
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."),
|
||||
title = catalog.i18nc("@info:title", "Unable to slice"))
|
||||
self._error_message.show()
|
||||
self.backendStateChange.emit(BackendState.Error)
|
||||
self.setState(BackendState.Error)
|
||||
self.backendError.emit(job)
|
||||
else:
|
||||
self.backendStateChange.emit(BackendState.NotStarted)
|
||||
self.setState(BackendState.NotStarted)
|
||||
self._invokeSlice()
|
||||
return
|
||||
|
||||
|
@ -424,7 +424,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._socket.sendMessage(job.getSliceMessage())
|
||||
|
||||
# Notify the user that it's now up to the backend to do it's job
|
||||
self.backendStateChange.emit(BackendState.Processing)
|
||||
self.setState(BackendState.Processing)
|
||||
|
||||
if self._slice_start_time:
|
||||
Logger.log("d", "Sending slice message took %s seconds", time() - self._slice_start_time )
|
||||
|
@ -442,7 +442,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||
for node in DepthFirstIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
|
||||
if node.callDecoration("isBlockSlicing"):
|
||||
enable_timer = False
|
||||
self.backendStateChange.emit(BackendState.Disabled)
|
||||
self.setState(BackendState.Disabled)
|
||||
self._is_disabled = True
|
||||
gcode_list = node.callDecoration("getGCodeList")
|
||||
if gcode_list is not None:
|
||||
|
@ -451,7 +451,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||
if self._use_timer == enable_timer:
|
||||
return self._use_timer
|
||||
if enable_timer:
|
||||
self.backendStateChange.emit(BackendState.NotStarted)
|
||||
self.setState(BackendState.NotStarted)
|
||||
self.enableTimer()
|
||||
return True
|
||||
else:
|
||||
|
@ -518,7 +518,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._build_plates_to_be_sliced.append(build_plate_number)
|
||||
self.printDurationMessage.emit(source_build_plate_number, {}, [])
|
||||
self.processingProgress.emit(0.0)
|
||||
self.backendStateChange.emit(BackendState.NotStarted)
|
||||
self.setState(BackendState.NotStarted)
|
||||
# if not self._use_timer:
|
||||
# With manually having to slice, we want to clear the old invalid layer data.
|
||||
self._clearLayerData(build_plate_changed)
|
||||
|
@ -567,7 +567,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self.stopSlicing()
|
||||
self.markSliceAll()
|
||||
self.processingProgress.emit(0.0)
|
||||
self.backendStateChange.emit(BackendState.NotStarted)
|
||||
self.setState(BackendState.NotStarted)
|
||||
if not self._use_timer:
|
||||
# With manually having to slice, we want to clear the old invalid layer data.
|
||||
self._clearLayerData()
|
||||
|
@ -613,7 +613,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||
# \param message The protobuf message containing the slicing progress.
|
||||
def _onProgressMessage(self, message: Arcus.PythonMessage) -> None:
|
||||
self.processingProgress.emit(message.amount)
|
||||
self.backendStateChange.emit(BackendState.Processing)
|
||||
self.setState(BackendState.Processing)
|
||||
|
||||
def _invokeSlice(self) -> None:
|
||||
if self._use_timer:
|
||||
|
@ -632,7 +632,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||
#
|
||||
# \param message The protobuf message signalling that slicing is finished.
|
||||
def _onSlicingFinishedMessage(self, message: Arcus.PythonMessage) -> None:
|
||||
self.backendStateChange.emit(BackendState.Done)
|
||||
self.setState(BackendState.Done)
|
||||
self.processingProgress.emit(1.0)
|
||||
|
||||
gcode_list = self._scene.gcode_dict[self._start_slice_job_build_plate] #type: ignore #Because we generate this attribute dynamically.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "CuraEngine Backend",
|
||||
"author": "Ultimaker B.V.",
|
||||
"description": "Provides the link to the CuraEngine slicing backend.",
|
||||
"api": 5,
|
||||
"version": "1.0.0",
|
||||
"api": "6.0",
|
||||
"version": "1.0.1",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Cura Profile Reader",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides support for importing Cura profiles.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Cura Profile Writer",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides support for exporting Cura profiles.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog":"cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Firmware Update Checker",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Checks for firmware updates.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Firmware Updater",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides a machine actions for updating firmware.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Compressed G-code Reader",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Reads g-code from a compressed archive.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Compressed G-code Writer",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Writes g-code to a compressed archive.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "G-code Profile Reader",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides support for importing profiles from g-code files.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -364,6 +364,8 @@ class FlavorParser:
|
|||
self._layer_type = LayerPolygon.SupportType
|
||||
elif type == "FILL":
|
||||
self._layer_type = LayerPolygon.InfillType
|
||||
elif type == "SUPPORT-INTERFACE":
|
||||
self._layer_type = LayerPolygon.SupportInterfaceType
|
||||
else:
|
||||
Logger.log("w", "Encountered a unknown type (%s) while parsing g-code.", type)
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "G-code Reader",
|
||||
"author": "Victor Larchenko",
|
||||
"version": "1.0.0",
|
||||
"author": "Victor Larchenko, Ultimaker",
|
||||
"version": "1.0.1",
|
||||
"description": "Allows loading and displaying G-code files.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "G-code Writer",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Writes g-code to a file.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Image Reader",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Enables ability to generate printable geometry from 2D image files.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Legacy Cura Profile Reader",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides support for importing profiles from legacy Cura versions.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import Cura 1.0 as Cura
|
|||
Cura.MachineAction
|
||||
{
|
||||
id: base
|
||||
property var extrudersModel: Cura.ExtrudersModel{}
|
||||
property var extrudersModel: CuraApplication.getExtrudersModel()
|
||||
property int extruderTabsCount: 0
|
||||
|
||||
property var activeMachineId: Cura.MachineManager.activeMachine != null ? Cura.MachineManager.activeMachine.id : ""
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Machine Settings action",
|
||||
"author": "fieldOfView",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides a way to change machine settings (such as build volume, nozzle size, etc.).",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Model Checker",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "0.1",
|
||||
"api": 5,
|
||||
"version": "1.0.1",
|
||||
"api": "6.0",
|
||||
"description": "Checks models and print configuration for possible printing issues and give suggestions.",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Monitor Stage",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides a monitor stage in Cura.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Per Model Settings Tool",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides the Per Model Settings.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Post Processing",
|
||||
"author": "Ultimaker",
|
||||
"version": "2.2",
|
||||
"api": 5,
|
||||
"version": "2.2.1",
|
||||
"api": "6.0",
|
||||
"description": "Extension that allows for user created scripts for post processing",
|
||||
"catalog": "cura"
|
||||
}
|
|
@ -100,7 +100,7 @@ Item
|
|||
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")
|
||||
color: UM.Theme.getColor("icon")
|
||||
|
||||
sourceSize.height: height
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
import os.path
|
||||
from UM.Application import Application
|
||||
|
@ -15,9 +15,5 @@ class PrepareStage(CuraStage):
|
|||
Application.getInstance().engineCreatedSignal.connect(self._engineCreated)
|
||||
|
||||
def _engineCreated(self):
|
||||
sidebar_component_path = os.path.join(Resources.getPath(Application.getInstance().ResourceTypes.QmlFiles),
|
||||
"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)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Prepare Stage",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides a prepare stage in Cura.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
// 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
|
||||
|
@ -19,12 +20,15 @@ Item
|
|||
name: "cura"
|
||||
}
|
||||
|
||||
|
||||
Row
|
||||
{
|
||||
id: stageMenuRow
|
||||
anchors.centerIn: parent
|
||||
height: parent.height
|
||||
width: childrenRect.width
|
||||
|
||||
// We want this row to have a preferred with equals to the 85% of the parent
|
||||
property int preferredWidth: Math.round(0.85 * previewMenu.width)
|
||||
|
||||
Cura.ViewsSelector
|
||||
{
|
||||
|
@ -45,11 +49,12 @@ Item
|
|||
color: UM.Theme.getColor("lining")
|
||||
}
|
||||
|
||||
// This component will grow freely up to complete the preferredWidth of the row.
|
||||
Loader
|
||||
{
|
||||
id: viewPanel
|
||||
height: parent.height
|
||||
width: childrenRect.width
|
||||
width: source != "" ? (stageMenuRow.preferredWidth - viewsSelector.width - printSetupSelectorItem.width - 2 * UM.Theme.getSize("default_lining").width) : 0
|
||||
source: UM.Controller.activeView != null && UM.Controller.activeView.stageMenuComponent != null ? UM.Controller.activeView.stageMenuComponent : ""
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Preview Stage",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides a preview stage in Cura.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
"name": "Removable Drive Output Device Plugin",
|
||||
"author": "Ultimaker B.V.",
|
||||
"description": "Provides removable drive hotplugging and writing support.",
|
||||
"version": "1.0.0",
|
||||
"api": 5,
|
||||
"version": "1.0.1",
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ Cura.ExpandableComponent
|
|||
{
|
||||
id: base
|
||||
|
||||
width: UM.Theme.getSize("layerview_menu_size").width
|
||||
contentHeaderTitle: catalog.i18nc("@label", "Color scheme")
|
||||
|
||||
Connections
|
||||
{
|
||||
|
@ -34,14 +34,36 @@ Cura.ExpandableComponent
|
|||
}
|
||||
}
|
||||
|
||||
headerItem: Label
|
||||
headerItem: Item
|
||||
{
|
||||
id: layerViewTypesLabel
|
||||
Label
|
||||
{
|
||||
id: colorSchemeLabel
|
||||
text: catalog.i18nc("@label", "Color scheme")
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("setting_control_text")
|
||||
height: base.height
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
height: parent.height
|
||||
elide: Text.ElideRight
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
text: layerTypeCombobox.currentText
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
anchors
|
||||
{
|
||||
left: colorSchemeLabel.right
|
||||
leftMargin: UM.Theme.getSize("default_margin").width
|
||||
right: parent.right
|
||||
}
|
||||
height: parent.height
|
||||
elide: Text.ElideRight
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Column
|
||||
|
@ -135,13 +157,13 @@ Cura.ExpandableComponent
|
|||
|
||||
Item // Spacer
|
||||
{
|
||||
height: Math.round(UM.Theme.getSize("default_margin").width / 2)
|
||||
height: UM.Theme.getSize("narrow_margin").width
|
||||
width: width
|
||||
}
|
||||
|
||||
Repeater
|
||||
{
|
||||
model: Cura.ExtrudersModel{}
|
||||
model: CuraApplication.getExtrudersModel()
|
||||
|
||||
CheckBox
|
||||
{
|
||||
|
@ -160,17 +182,16 @@ Cura.ExpandableComponent
|
|||
|
||||
style: UM.Theme.styles.checkbox
|
||||
|
||||
Rectangle
|
||||
|
||||
UM.RecolorImage
|
||||
{
|
||||
id: swatch
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: extrudersModelCheckBox.right
|
||||
width: UM.Theme.getSize("layerview_legend_size").width
|
||||
height: UM.Theme.getSize("layerview_legend_size").height
|
||||
source: UM.Theme.getIcon("extruder_button")
|
||||
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
|
||||
|
@ -200,25 +221,25 @@ Cura.ExpandableComponent
|
|||
Component.onCompleted:
|
||||
{
|
||||
typesLegendModel.append({
|
||||
label: catalog.i18nc("@label", "Show Travels"),
|
||||
label: catalog.i18nc("@label", "Travels"),
|
||||
initialValue: viewSettings.show_travel_moves,
|
||||
preference: "layerview/show_travel_moves",
|
||||
colorId: "layerview_move_combing"
|
||||
});
|
||||
typesLegendModel.append({
|
||||
label: catalog.i18nc("@label", "Show Helpers"),
|
||||
label: catalog.i18nc("@label", "Helpers"),
|
||||
initialValue: viewSettings.show_helpers,
|
||||
preference: "layerview/show_helpers",
|
||||
colorId: "layerview_support"
|
||||
});
|
||||
typesLegendModel.append({
|
||||
label: catalog.i18nc("@label", "Show Shell"),
|
||||
label: catalog.i18nc("@label", "Shell"),
|
||||
initialValue: viewSettings.show_skin,
|
||||
preference: "layerview/show_skin",
|
||||
colorId: "layerview_inset_0"
|
||||
});
|
||||
typesLegendModel.append({
|
||||
label: catalog.i18nc("@label", "Show Infill"),
|
||||
label: catalog.i18nc("@label", "Infill"),
|
||||
initialValue: viewSettings.show_infill,
|
||||
preference: "layerview/show_infill",
|
||||
colorId: "layerview_infill"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Simulation View",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides the Simulation view.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Slice info",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Submits anonymous slice info. Can be disabled through preferences.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ from UM.Math.Color import Color
|
|||
from UM.View.GL.OpenGL import OpenGL
|
||||
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
from cura.Settings.ExtrudersModel import ExtrudersModel
|
||||
|
||||
import math
|
||||
|
||||
|
@ -29,13 +28,16 @@ class SolidView(View):
|
|||
self._non_printing_shader = None
|
||||
self._support_mesh_shader = None
|
||||
|
||||
self._extruders_model = ExtrudersModel()
|
||||
self._extruders_model = None
|
||||
self._theme = None
|
||||
|
||||
def beginRendering(self):
|
||||
scene = self.getController().getScene()
|
||||
renderer = self.getRenderer()
|
||||
|
||||
if not self._extruders_model:
|
||||
self._extruders_model = Application.getInstance().getExtrudersModel()
|
||||
|
||||
if not self._theme:
|
||||
self._theme = Application.getInstance().getTheme()
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Solid View",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides a normal solid mesh view.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Support Eraser",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Creates an eraser mesh to block the printing of support in certain places",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "Toolbox",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"api": 5,
|
||||
"version": "1.0.1",
|
||||
"api": "6.0",
|
||||
"description": "Find, manage and install new Cura packages."
|
||||
}
|
||||
|
|
106
plugins/Toolbox/resources/qml/RatingWidget.qml
Normal file
106
plugins/Toolbox/resources/qml/RatingWidget.qml
Normal file
|
@ -0,0 +1,106 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.1
|
||||
import UM 1.0 as UM
|
||||
import Cura 1.1 as Cura
|
||||
Item
|
||||
{
|
||||
id: ratingWidget
|
||||
|
||||
property real rating: 0
|
||||
property int indexHovered: -1
|
||||
property string packageId: ""
|
||||
|
||||
property int userRating: 0
|
||||
property bool canRate: false
|
||||
|
||||
signal rated(int rating)
|
||||
|
||||
width: contentRow.width
|
||||
height: contentRow.height
|
||||
MouseArea
|
||||
{
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: ratingWidget.canRate
|
||||
acceptedButtons: Qt.NoButton
|
||||
onExited:
|
||||
{
|
||||
if(ratingWidget.canRate)
|
||||
{
|
||||
ratingWidget.indexHovered = -1
|
||||
}
|
||||
}
|
||||
|
||||
Row
|
||||
{
|
||||
id: contentRow
|
||||
height: childrenRect.height
|
||||
Repeater
|
||||
{
|
||||
model: 5 // We need to get 5 stars
|
||||
Button
|
||||
{
|
||||
id: control
|
||||
hoverEnabled: true
|
||||
onHoveredChanged:
|
||||
{
|
||||
if(hovered && ratingWidget.canRate)
|
||||
{
|
||||
indexHovered = index
|
||||
}
|
||||
}
|
||||
|
||||
ToolTip.visible: control.hovered && !ratingWidget.canRate
|
||||
ToolTip.text: !Cura.API.account.isLoggedIn ? catalog.i18nc("@label", "You need to login first before you can rate"): catalog.i18nc("@label", "You need to install the package before you can rate")
|
||||
|
||||
property bool isStarFilled:
|
||||
{
|
||||
// If the entire widget is hovered, override the actual rating.
|
||||
if(ratingWidget.indexHovered >= 0)
|
||||
{
|
||||
return indexHovered >= index
|
||||
}
|
||||
|
||||
if(ratingWidget.userRating > 0)
|
||||
{
|
||||
return userRating >= index +1
|
||||
}
|
||||
|
||||
return rating >= index + 1
|
||||
}
|
||||
|
||||
contentItem: Item {}
|
||||
height: UM.Theme.getSize("rating_star").height
|
||||
width: UM.Theme.getSize("rating_star").width
|
||||
background: UM.RecolorImage
|
||||
{
|
||||
source: UM.Theme.getIcon(control.isStarFilled ? "star_filled" : "star_empty")
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
|
||||
// Unfilled stars should always have the default color. Only filled stars should change on hover
|
||||
color:
|
||||
{
|
||||
if(!ratingWidget.canRate)
|
||||
{
|
||||
return UM.Theme.getColor("rating_star")
|
||||
}
|
||||
if((ratingWidget.indexHovered >= 0 || ratingWidget.userRating > 0) && isStarFilled)
|
||||
{
|
||||
return UM.Theme.getColor("primary")
|
||||
}
|
||||
return UM.Theme.getColor("rating_star")
|
||||
}
|
||||
}
|
||||
onClicked:
|
||||
{
|
||||
if(ratingWidget.canRate)
|
||||
{
|
||||
rated(index + 1) // Notify anyone who cares about this.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
plugins/Toolbox/resources/qml/SmallRatingWidget.qml
Normal file
36
plugins/Toolbox/resources/qml/SmallRatingWidget.qml
Normal file
|
@ -0,0 +1,36 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.4
|
||||
import UM 1.1 as UM
|
||||
import Cura 1.1 as Cura
|
||||
|
||||
Row
|
||||
{
|
||||
id: rating
|
||||
height: UM.Theme.getSize("rating_star").height
|
||||
visible: model.average_rating > 0 //Has a rating at all.
|
||||
spacing: UM.Theme.getSize("thick_lining").width
|
||||
width: starIcon.width + spacing + numRatingsLabel.width
|
||||
UM.RecolorImage
|
||||
{
|
||||
id: starIcon
|
||||
source: UM.Theme.getIcon("star_filled")
|
||||
color: model.user_rating == 0 ? UM.Theme.getColor("rating_star") : UM.Theme.getColor("primary")
|
||||
height: UM.Theme.getSize("rating_star").height
|
||||
width: UM.Theme.getSize("rating_star").width
|
||||
sourceSize.height: height
|
||||
sourceSize.width: width
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
id: numRatingsLabel
|
||||
text: model.average_rating != undefined ? model.average_rating.toFixed(1) + " (" + model.num_ratings + " " + catalog.i18nc("@label", "ratings") + ")": ""
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
height: starIcon.height
|
||||
width: contentWidth
|
||||
anchors.verticalCenter: starIcon.verticalCenter
|
||||
color: starIcon.color
|
||||
font: UM.Theme.getFont("small")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
|
@ -14,8 +14,8 @@ Window
|
|||
modality: Qt.ApplicationModal
|
||||
flags: Qt.Dialog | Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowCloseButtonHint
|
||||
|
||||
width: 720 * screenScaleFactor
|
||||
height: 640 * screenScaleFactor
|
||||
width: Math.floor(720 * screenScaleFactor)
|
||||
height: Math.floor(640 * screenScaleFactor)
|
||||
minimumWidth: width
|
||||
maximumWidth: minimumWidth
|
||||
minimumHeight: height
|
||||
|
@ -95,6 +95,7 @@ Window
|
|||
licenseDialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
ToolboxLicenseDialog
|
||||
{
|
||||
id: licenseDialog
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.3
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.1 as UM
|
||||
|
@ -59,6 +59,7 @@ Item
|
|||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
height: UM.Theme.getSize("toolbox_property_label").height
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Label
|
||||
{
|
||||
|
@ -70,6 +71,7 @@ Item
|
|||
left: title.left
|
||||
topMargin: UM.Theme.getSize("default_margin").height
|
||||
}
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Column
|
||||
{
|
||||
|
@ -88,12 +90,14 @@ Item
|
|||
text: catalog.i18nc("@label", "Website") + ":"
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@label", "Email") + ":"
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
Column
|
||||
|
@ -122,6 +126,7 @@ Item
|
|||
color: UM.Theme.getColor("text")
|
||||
linkColor: UM.Theme.getColor("text_link")
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
Label
|
||||
|
@ -138,6 +143,7 @@ Item
|
|||
color: UM.Theme.getColor("text")
|
||||
linkColor: UM.Theme.getColor("text_link")
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
Rectangle
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.1 as UM
|
||||
|
@ -64,6 +64,7 @@ Item
|
|||
font: UM.Theme.getFont("default_bold")
|
||||
horizontalAlignment: Text.AlignRight
|
||||
width: control.width
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.1 as UM
|
||||
|
@ -67,6 +67,7 @@ Item
|
|||
wrapMode: Text.WordWrap
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
font: UM.Theme.getFont("medium")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
TableView
|
||||
|
@ -99,6 +100,7 @@ Item
|
|||
text: styleData.value || ""
|
||||
color: UM.Theme.getColor("text")
|
||||
font: UM.Theme.getFont("default_bold")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Rectangle
|
||||
{
|
||||
|
@ -118,6 +120,7 @@ Item
|
|||
text: styleData.value || ""
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
font: UM.Theme.getFont("default")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
itemDelegate: Item
|
||||
|
@ -130,6 +133,7 @@ Item
|
|||
text: styleData.value || ""
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
font: UM.Theme.getFont("default")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,6 +148,7 @@ Item
|
|||
elide: Text.ElideRight
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
font: UM.Theme.getFont("default")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,5 +237,6 @@ Item
|
|||
color: UM.Theme.getColor("text")
|
||||
linkColor: UM.Theme.getColor("text_link")
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls.Styles 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
|
@ -66,6 +66,7 @@ UM.Dialog
|
|||
anchors.right: parent.right
|
||||
font: UM.Theme.getFont("default")
|
||||
wrapMode: Text.WordWrap
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
// Buttons
|
||||
|
|
|
@ -26,10 +26,19 @@ Item
|
|||
}
|
||||
height: childrenRect.height + 2 * UM.Theme.getSize("wide_margin").height
|
||||
spacing: UM.Theme.getSize("default_margin").height
|
||||
|
||||
Repeater
|
||||
{
|
||||
model: toolbox.packagesModel
|
||||
delegate: ToolboxDetailTile {}
|
||||
delegate: Loader
|
||||
{
|
||||
// FIXME: When using asynchronous loading, on Mac and Windows, the tile may fail to load complete,
|
||||
// leaving an empty space below the title part. We turn it off for now to make it work on Mac and
|
||||
// Windows.
|
||||
// Can be related to this QT bug: https://bugreports.qt.io/browse/QTBUG-50992
|
||||
asynchronous: false
|
||||
source: "ToolboxDetailTile.qml"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.3
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.1 as UM
|
||||
|
||||
import Cura 1.1 as Cura
|
||||
|
||||
Item
|
||||
{
|
||||
id: page
|
||||
|
@ -24,7 +26,7 @@ Item
|
|||
right: parent.right
|
||||
rightMargin: UM.Theme.getSize("wide_margin").width
|
||||
}
|
||||
height: UM.Theme.getSize("toolbox_detail_header").height
|
||||
height: childrenRect.height + 3 * UM.Theme.getSize("default_margin").width
|
||||
Rectangle
|
||||
{
|
||||
id: thumbnail
|
||||
|
@ -37,7 +39,7 @@ Item
|
|||
leftMargin: UM.Theme.getSize("wide_margin").width
|
||||
topMargin: UM.Theme.getSize("wide_margin").height
|
||||
}
|
||||
color: "white" //Always a white background for image (regardless of theme).
|
||||
color: UM.Theme.getColor("main_background")
|
||||
Image
|
||||
{
|
||||
anchors.fill: parent
|
||||
|
@ -55,16 +57,21 @@ Item
|
|||
top: thumbnail.top
|
||||
left: thumbnail.right
|
||||
leftMargin: UM.Theme.getSize("default_margin").width
|
||||
right: parent.right
|
||||
rightMargin: UM.Theme.getSize("wide_margin").width
|
||||
bottomMargin: UM.Theme.getSize("default_margin").height
|
||||
}
|
||||
text: details === null ? "" : (details.name || "")
|
||||
font: UM.Theme.getFont("large")
|
||||
color: UM.Theme.getColor("text")
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
height: UM.Theme.getSize("toolbox_property_label").height
|
||||
width: contentWidth
|
||||
height: contentHeight
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
SmallRatingWidget
|
||||
{
|
||||
anchors.left: title.right
|
||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
||||
anchors.verticalCenter: title.verticalCenter
|
||||
property var model: details
|
||||
}
|
||||
|
||||
Column
|
||||
|
@ -80,28 +87,39 @@ Item
|
|||
width: childrenRect.width
|
||||
height: childrenRect.height
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@label", "Your rating") + ":"
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@label", "Version") + ":"
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@label", "Last updated") + ":"
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@label", "Author") + ":"
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@label", "Downloads") + ":"
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
Column
|
||||
|
@ -116,11 +134,54 @@ Item
|
|||
}
|
||||
spacing: Math.floor(UM.Theme.getSize("narrow_margin").height)
|
||||
height: childrenRect.height
|
||||
RatingWidget
|
||||
{
|
||||
id: rating
|
||||
visible: details.type == "plugin"
|
||||
packageId: details.id != undefined ? details.id: ""
|
||||
userRating: details.user_rating != undefined ? details.user_rating: 0
|
||||
canRate: toolbox.isInstalled(details.id) && Cura.API.account.isLoggedIn
|
||||
|
||||
onRated:
|
||||
{
|
||||
toolbox.ratePackage(details.id, rating)
|
||||
// HACK: This is a far from optimal solution, but without major refactoring, this is the best we can
|
||||
// do. Since a rework of this is scheduled, it shouldn't live that long...
|
||||
var index = toolbox.pluginsAvailableModel.find("id", details.id)
|
||||
if(index != -1)
|
||||
{
|
||||
if(details.user_rating == 0) // User never rated before.
|
||||
{
|
||||
toolbox.pluginsAvailableModel.setProperty(index, "num_ratings", details.num_ratings + 1)
|
||||
}
|
||||
|
||||
toolbox.pluginsAvailableModel.setProperty(index, "user_rating", rating)
|
||||
|
||||
|
||||
// Hack; This is because the current selection is an outdated copy, so we need to re-copy it.
|
||||
base.selection = toolbox.pluginsAvailableModel.getItem(index)
|
||||
return
|
||||
}
|
||||
index = toolbox.pluginsShowcaseModel.find("id", details.id)
|
||||
if(index != -1)
|
||||
{
|
||||
if(details.user_rating == 0) // User never rated before.
|
||||
{
|
||||
toolbox.pluginsShowcaseModel.setProperty(index, "user_rating", rating)
|
||||
}
|
||||
toolbox.pluginsShowcaseModel.setProperty(index, "num_ratings", details.num_ratings + 1)
|
||||
|
||||
// Hack; This is because the current selection is an outdated copy, so we need to re-copy it.
|
||||
base.selection = toolbox.pluginsShowcaseModel.getItem(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
Label
|
||||
{
|
||||
text: details === null ? "" : (details.version || catalog.i18nc("@label", "Unknown"))
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Label
|
||||
{
|
||||
|
@ -135,6 +196,7 @@ Item
|
|||
}
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Label
|
||||
{
|
||||
|
@ -153,21 +215,16 @@ Item
|
|||
color: UM.Theme.getColor("text")
|
||||
linkColor: UM.Theme.getColor("text_link")
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Label
|
||||
{
|
||||
text: details === null ? "" : (details.download_count || catalog.i18nc("@label", "Unknown"))
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
Rectangle
|
||||
{
|
||||
color: UM.Theme.getColor("lining")
|
||||
width: parent.width
|
||||
height: UM.Theme.getSize("default_lining").height
|
||||
anchors.bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
ToolboxDetailList
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.1 as UM
|
||||
|
@ -31,6 +31,7 @@ Item
|
|||
wrapMode: Text.WordWrap
|
||||
color: UM.Theme.getColor("text")
|
||||
font: UM.Theme.getFont("medium_bold")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Label
|
||||
{
|
||||
|
@ -42,6 +43,7 @@ Item
|
|||
wrapMode: Text.WordWrap
|
||||
color: UM.Theme.getColor("text")
|
||||
font: UM.Theme.getFont("default")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +1,69 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.1 as UM
|
||||
import Cura 1.1 as Cura
|
||||
|
||||
Column
|
||||
{
|
||||
property bool installed: toolbox.isInstalled(model.id)
|
||||
property bool canUpdate: toolbox.canUpdate(model.id)
|
||||
property bool loginRequired: model.login_required && !Cura.API.account.isLoggedIn
|
||||
|
||||
width: UM.Theme.getSize("toolbox_action_button").width
|
||||
spacing: UM.Theme.getSize("narrow_margin").height
|
||||
|
||||
Item
|
||||
{
|
||||
width: installButton.width
|
||||
height: installButton.height
|
||||
ToolboxProgressButton
|
||||
{
|
||||
id: installButton
|
||||
active: toolbox.isDownloading && toolbox.activePackage == model
|
||||
complete: installed
|
||||
readyAction: function()
|
||||
onReadyAction:
|
||||
{
|
||||
toolbox.activePackage = model
|
||||
toolbox.startDownload(model.download_url)
|
||||
}
|
||||
activeAction: function()
|
||||
{
|
||||
toolbox.cancelDownload()
|
||||
}
|
||||
completeAction: function()
|
||||
{
|
||||
toolbox.viewCategory = "installed"
|
||||
}
|
||||
onActiveAction: toolbox.cancelDownload()
|
||||
|
||||
// Don't allow installing while another download is running
|
||||
enabled: installed || !(toolbox.isDownloading && toolbox.activePackage != model)
|
||||
enabled: installed || (!(toolbox.isDownloading && toolbox.activePackage != model) && !loginRequired)
|
||||
opacity: enabled ? 1.0 : 0.5
|
||||
visible: !updateButton.visible // Don't show when the update button is visible
|
||||
visible: !updateButton.visible && !installed// Don't show when the update button is visible
|
||||
}
|
||||
|
||||
Cura.SecondaryButton
|
||||
{
|
||||
visible: installed
|
||||
onClicked: toolbox.viewCategory = "installed"
|
||||
text: catalog.i18nc("@action:button", "Installed")
|
||||
fixedWidthMode: true
|
||||
width: installButton.width
|
||||
height: installButton.height
|
||||
}
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label:The string between <a href=> and </a> is the highlighted link", "<a href='%1'>Log in</a> is required to install or update")
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text")
|
||||
linkColor: UM.Theme.getColor("text_link")
|
||||
visible: loginRequired
|
||||
width: installButton.width
|
||||
renderType: Text.NativeRendering
|
||||
|
||||
MouseArea
|
||||
{
|
||||
anchors.fill: parent
|
||||
onClicked: Cura.API.account.login()
|
||||
}
|
||||
}
|
||||
|
||||
ToolboxProgressButton
|
||||
|
@ -44,20 +73,19 @@ Column
|
|||
readyLabel: catalog.i18nc("@action:button", "Update")
|
||||
activeLabel: catalog.i18nc("@action:button", "Updating")
|
||||
completeLabel: catalog.i18nc("@action:button", "Updated")
|
||||
readyAction: function()
|
||||
|
||||
onReadyAction:
|
||||
{
|
||||
toolbox.activePackage = model
|
||||
toolbox.update(model.id)
|
||||
}
|
||||
activeAction: function()
|
||||
{
|
||||
toolbox.cancelDownload()
|
||||
}
|
||||
onActiveAction: toolbox.cancelDownload()
|
||||
// Don't allow installing while another download is running
|
||||
enabled: !(toolbox.isDownloading && toolbox.activePackage != model)
|
||||
enabled: !(toolbox.isDownloading && toolbox.activePackage != model) && !loginRequired
|
||||
opacity: enabled ? 1.0 : 0.5
|
||||
visible: canUpdate
|
||||
}
|
||||
|
||||
Connections
|
||||
{
|
||||
target: toolbox
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.3
|
||||
|
@ -23,8 +23,9 @@ Column
|
|||
width: parent.width
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
font: UM.Theme.getFont("medium")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
GridLayout
|
||||
Grid
|
||||
{
|
||||
id: grid
|
||||
width: parent.width - 2 * parent.padding
|
||||
|
@ -34,10 +35,12 @@ Column
|
|||
Repeater
|
||||
{
|
||||
model: gridArea.model
|
||||
delegate: ToolboxDownloadsGridTile
|
||||
delegate: Loader
|
||||
{
|
||||
Layout.preferredWidth: (grid.width - (grid.columns - 1) * grid.columnSpacing) / grid.columns
|
||||
Layout.preferredHeight: UM.Theme.getSize("toolbox_thumbnail_small").height
|
||||
asynchronous: true
|
||||
width: Math.round((grid.width - (grid.columns - 1) * grid.columnSpacing) / grid.columns)
|
||||
height: UM.Theme.getSize("toolbox_thumbnail_small").height
|
||||
source: "ToolboxDownloadsGridTile.qml"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.3
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.3
|
||||
import UM 1.1 as UM
|
||||
import Cura 1.1 as Cura
|
||||
|
||||
Item
|
||||
{
|
||||
|
@ -14,90 +15,13 @@ Item
|
|||
property int installedPackages: (toolbox.viewCategory == "material" && model.type === undefined) ? toolbox.getNumberOfInstalledPackagesByAuthor(model.id) : (toolbox.isInstalled(model.id) ? 1 : 0)
|
||||
height: childrenRect.height
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||
Rectangle
|
||||
{
|
||||
id: highlight
|
||||
anchors.fill: parent
|
||||
opacity: 0.0
|
||||
color: UM.Theme.getColor("primary")
|
||||
}
|
||||
Row
|
||||
{
|
||||
width: parent.width
|
||||
height: childrenRect.height
|
||||
spacing: Math.floor(UM.Theme.getSize("narrow_margin").width)
|
||||
Rectangle
|
||||
{
|
||||
id: thumbnail
|
||||
width: UM.Theme.getSize("toolbox_thumbnail_small").width
|
||||
height: UM.Theme.getSize("toolbox_thumbnail_small").height
|
||||
color: "white"
|
||||
border.width: UM.Theme.getSize("default_lining").width
|
||||
border.color: UM.Theme.getColor("lining")
|
||||
Image
|
||||
{
|
||||
anchors.centerIn: parent
|
||||
width: UM.Theme.getSize("toolbox_thumbnail_small").width - UM.Theme.getSize("wide_margin").width
|
||||
height: UM.Theme.getSize("toolbox_thumbnail_small").height - UM.Theme.getSize("wide_margin").width
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: model.icon_url || "../images/logobot.svg"
|
||||
mipmap: true
|
||||
}
|
||||
UM.RecolorImage
|
||||
{
|
||||
width: (parent.width * 0.4) | 0
|
||||
height: (parent.height * 0.4) | 0
|
||||
anchors
|
||||
{
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
}
|
||||
sourceSize.height: height
|
||||
visible: installedPackages != 0
|
||||
color: (installedPackages == packageCount) ? UM.Theme.getColor("primary") : UM.Theme.getColor("border")
|
||||
source: "../images/installed_check.svg"
|
||||
}
|
||||
}
|
||||
Column
|
||||
{
|
||||
width: parent.width - thumbnail.width - parent.spacing
|
||||
spacing: Math.floor(UM.Theme.getSize("narrow_margin").width)
|
||||
Label
|
||||
{
|
||||
id: name
|
||||
text: model.name
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
color: UM.Theme.getColor("text")
|
||||
font: UM.Theme.getFont("default_bold")
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: info
|
||||
text: model.description
|
||||
maximumLineCount: 2
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
font: UM.Theme.getFont("default")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea
|
||||
{
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered:
|
||||
{
|
||||
thumbnail.border.color = UM.Theme.getColor("primary")
|
||||
highlight.opacity = 0.1
|
||||
}
|
||||
onExited:
|
||||
{
|
||||
thumbnail.border.color = UM.Theme.getColor("lining")
|
||||
highlight.opacity = 0.0
|
||||
}
|
||||
onEntered: thumbnail.border.color = UM.Theme.getColor("primary")
|
||||
onExited: thumbnail.border.color = UM.Theme.getColor("lining")
|
||||
onClicked:
|
||||
{
|
||||
base.selection = model
|
||||
|
@ -127,4 +51,83 @@ Item
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle
|
||||
{
|
||||
id: thumbnail
|
||||
width: UM.Theme.getSize("toolbox_thumbnail_small").width
|
||||
height: UM.Theme.getSize("toolbox_thumbnail_small").height
|
||||
color: UM.Theme.getColor("main_background")
|
||||
border.width: UM.Theme.getSize("default_lining").width
|
||||
border.color: UM.Theme.getColor("lining")
|
||||
|
||||
Image
|
||||
{
|
||||
anchors.centerIn: parent
|
||||
width: UM.Theme.getSize("toolbox_thumbnail_small").width - UM.Theme.getSize("wide_margin").width
|
||||
height: UM.Theme.getSize("toolbox_thumbnail_small").height - UM.Theme.getSize("wide_margin").width
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: model.icon_url || "../images/logobot.svg"
|
||||
mipmap: true
|
||||
}
|
||||
UM.RecolorImage
|
||||
{
|
||||
width: (parent.width * 0.4) | 0
|
||||
height: (parent.height * 0.4) | 0
|
||||
anchors
|
||||
{
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
}
|
||||
sourceSize.height: height
|
||||
visible: installedPackages != 0
|
||||
color: (installedPackages == packageCount) ? UM.Theme.getColor("primary") : UM.Theme.getColor("border")
|
||||
source: "../images/installed_check.svg"
|
||||
}
|
||||
}
|
||||
Item
|
||||
{
|
||||
anchors
|
||||
{
|
||||
left: thumbnail.right
|
||||
leftMargin: Math.floor(UM.Theme.getSize("narrow_margin").width)
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
id: name
|
||||
text: model.name
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
color: UM.Theme.getColor("text")
|
||||
font: UM.Theme.getFont("default_bold")
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: info
|
||||
text: model.description
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
font: UM.Theme.getFont("default")
|
||||
anchors.top: name.bottom
|
||||
anchors.bottom: rating.top
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
maximumLineCount: 2
|
||||
}
|
||||
SmallRatingWidget
|
||||
{
|
||||
id: rating
|
||||
anchors
|
||||
{
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.1 as UM
|
||||
|
@ -24,19 +24,19 @@ Rectangle
|
|||
width: parent.width
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
font: UM.Theme.getFont("medium")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Grid
|
||||
{
|
||||
height: childrenRect.height
|
||||
spacing: UM.Theme.getSize("wide_margin").width
|
||||
columns: 3
|
||||
anchors
|
||||
{
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Repeater
|
||||
{
|
||||
model: {
|
||||
model:
|
||||
{
|
||||
if (toolbox.viewCategory == "plugin")
|
||||
{
|
||||
return toolbox.pluginsShowcaseModel
|
||||
|
@ -46,7 +46,11 @@ Rectangle
|
|||
return toolbox.materialsShowcaseModel
|
||||
}
|
||||
}
|
||||
delegate: ToolboxDownloadsShowcaseTile {}
|
||||
delegate: Loader
|
||||
{
|
||||
asynchronous: true
|
||||
source: "ToolboxDownloadsShowcaseTile.qml"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
|
@ -13,57 +13,25 @@ Rectangle
|
|||
property int installedPackages: toolbox.viewCategory == "material" ? toolbox.getNumberOfInstalledPackagesByAuthor(model.id) : (toolbox.isInstalled(model.id) ? 1 : 0)
|
||||
id: tileBase
|
||||
width: UM.Theme.getSize("toolbox_thumbnail_large").width + (2 * UM.Theme.getSize("default_lining").width)
|
||||
height: thumbnail.height + packageNameBackground.height + (2 * UM.Theme.getSize("default_lining").width)
|
||||
height: thumbnail.height + packageName.height + rating.height + UM.Theme.getSize("default_margin").width
|
||||
border.width: UM.Theme.getSize("default_lining").width
|
||||
border.color: UM.Theme.getColor("lining")
|
||||
color: "transparent"
|
||||
Rectangle
|
||||
{
|
||||
id: thumbnail
|
||||
color: "white"
|
||||
width: UM.Theme.getSize("toolbox_thumbnail_large").width
|
||||
height: UM.Theme.getSize("toolbox_thumbnail_large").height
|
||||
anchors
|
||||
{
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
topMargin: UM.Theme.getSize("default_lining").width
|
||||
}
|
||||
color: UM.Theme.getColor("main_background")
|
||||
Image
|
||||
{
|
||||
anchors.centerIn: parent
|
||||
width: UM.Theme.getSize("toolbox_thumbnail_large").width - 2 * UM.Theme.getSize("default_margin").width
|
||||
height: UM.Theme.getSize("toolbox_thumbnail_large").height - 2 * UM.Theme.getSize("default_margin").height
|
||||
id: thumbnail
|
||||
height: UM.Theme.getSize("toolbox_thumbnail_large").height - 4 * UM.Theme.getSize("default_margin").height
|
||||
width: UM.Theme.getSize("toolbox_thumbnail_large").height - 4 * UM.Theme.getSize("default_margin").height
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: model.icon_url || "../images/logobot.svg"
|
||||
mipmap: true
|
||||
}
|
||||
UM.RecolorImage
|
||||
{
|
||||
width: (parent.width * 0.3) | 0
|
||||
height: (parent.height * 0.3) | 0
|
||||
anchors
|
||||
{
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
bottomMargin: UM.Theme.getSize("default_lining").width
|
||||
}
|
||||
visible: installedPackages != 0
|
||||
color: (installedPackages == packageCount) ? UM.Theme.getColor("primary") : UM.Theme.getColor("border")
|
||||
source: "../images/installed_check.svg"
|
||||
}
|
||||
}
|
||||
Rectangle
|
||||
{
|
||||
id: packageNameBackground
|
||||
color: UM.Theme.getColor("primary")
|
||||
anchors
|
||||
{
|
||||
top: thumbnail.bottom
|
||||
top: parent.top
|
||||
topMargin: UM.Theme.getSize("default_margin").height
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
height: UM.Theme.getSize("toolbox_heading_label").height
|
||||
width: parent.width
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: packageName
|
||||
|
@ -71,32 +39,53 @@ Rectangle
|
|||
anchors
|
||||
{
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: thumbnail.bottom
|
||||
}
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
renderType: Text.NativeRendering
|
||||
height: UM.Theme.getSize("toolbox_heading_label").height
|
||||
width: parent.width
|
||||
width: parent.width - UM.Theme.getSize("default_margin").width
|
||||
wrapMode: Text.WordWrap
|
||||
color: UM.Theme.getColor("button_text")
|
||||
elide: Text.ElideRight
|
||||
font: UM.Theme.getFont("medium_bold")
|
||||
}
|
||||
UM.RecolorImage
|
||||
{
|
||||
width: (parent.width * 0.20) | 0
|
||||
height: width
|
||||
anchors
|
||||
{
|
||||
bottom: bottomBorder.top
|
||||
right: parent.right
|
||||
}
|
||||
visible: installedPackages != 0
|
||||
color: (installedPackages == packageCount) ? UM.Theme.getColor("primary") : UM.Theme.getColor("border")
|
||||
source: "../images/installed_check.svg"
|
||||
}
|
||||
|
||||
SmallRatingWidget
|
||||
{
|
||||
id: rating
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: UM.Theme.getSize("narrow_margin").height
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
Rectangle
|
||||
{
|
||||
id: bottomBorder
|
||||
color: UM.Theme.getColor("primary")
|
||||
anchors.bottom: parent.bottom
|
||||
width: parent.width
|
||||
height: UM.Theme.getSize("toolbox_header_highlight").height
|
||||
}
|
||||
|
||||
MouseArea
|
||||
{
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered:
|
||||
{
|
||||
packageName.color = UM.Theme.getColor("button_text_hover")
|
||||
packageNameBackground.color = UM.Theme.getColor("primary_hover")
|
||||
tileBase.border.color = UM.Theme.getColor("primary_hover")
|
||||
}
|
||||
onExited:
|
||||
{
|
||||
packageName.color = UM.Theme.getColor("button_text")
|
||||
packageNameBackground.color = UM.Theme.getColor("primary")
|
||||
tileBase.border.color = UM.Theme.getColor("lining")
|
||||
}
|
||||
onEntered: tileBase.border.color = UM.Theme.getColor("primary")
|
||||
onExited: tileBase.border.color = UM.Theme.getColor("lining")
|
||||
onClicked:
|
||||
{
|
||||
base.selection = model
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
|
@ -18,5 +18,6 @@ Rectangle
|
|||
{
|
||||
centerIn: parent
|
||||
}
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.3
|
||||
|
||||
import UM 1.1 as UM
|
||||
import Cura 1.0 as Cura
|
||||
|
||||
Item
|
||||
{
|
||||
id: footer
|
||||
width: parent.width
|
||||
anchors.bottom: parent.bottom
|
||||
height: visible ? Math.floor(UM.Theme.getSize("toolbox_footer").height) : 0
|
||||
height: visible ? UM.Theme.getSize("toolbox_footer").height : 0
|
||||
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@info", "You will need to restart Cura before changes in packages have effect.")
|
||||
color: UM.Theme.getColor("text")
|
||||
height: Math.floor(UM.Theme.getSize("toolbox_footer_button").height)
|
||||
height: UM.Theme.getSize("toolbox_footer_button").height
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
anchors
|
||||
{
|
||||
|
@ -26,12 +28,12 @@ Item
|
|||
right: restartButton.right
|
||||
rightMargin: UM.Theme.getSize("default_margin").width
|
||||
}
|
||||
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Button
|
||||
|
||||
Cura.PrimaryButton
|
||||
{
|
||||
id: restartButton
|
||||
text: catalog.i18nc("@info:button", "Quit Cura")
|
||||
anchors
|
||||
{
|
||||
top: parent.top
|
||||
|
@ -39,26 +41,11 @@ Item
|
|||
right: parent.right
|
||||
rightMargin: UM.Theme.getSize("wide_margin").width
|
||||
}
|
||||
iconName: "dialog-restart"
|
||||
height: UM.Theme.getSize("toolbox_footer_button").height
|
||||
text: catalog.i18nc("@info:button", "Quit Cura")
|
||||
onClicked: toolbox.restart()
|
||||
style: ButtonStyle
|
||||
{
|
||||
background: Rectangle
|
||||
{
|
||||
implicitWidth: UM.Theme.getSize("toolbox_footer_button").width
|
||||
implicitHeight: Math.floor(UM.Theme.getSize("toolbox_footer_button").height)
|
||||
color: control.hovered ? UM.Theme.getColor("primary_hover") : UM.Theme.getColor("primary")
|
||||
}
|
||||
label: Label
|
||||
{
|
||||
color: UM.Theme.getColor("button_text")
|
||||
font: UM.Theme.getFont("default_bold")
|
||||
text: control.text
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ToolboxShadow
|
||||
{
|
||||
visible: footer.visible
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Dialogs 1.1
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls 1.4
|
||||
|
@ -21,44 +21,40 @@ ScrollView
|
|||
Column
|
||||
{
|
||||
spacing: UM.Theme.getSize("default_margin").height
|
||||
visible: toolbox.pluginsInstalledModel.items.length > 0
|
||||
height: childrenRect.height + 4 * UM.Theme.getSize("default_margin").height
|
||||
|
||||
anchors
|
||||
{
|
||||
right: parent.right
|
||||
left: parent.left
|
||||
leftMargin: UM.Theme.getSize("wide_margin").width
|
||||
topMargin: UM.Theme.getSize("wide_margin").height
|
||||
bottomMargin: UM.Theme.getSize("wide_margin").height
|
||||
margins: UM.Theme.getSize("default_margin").width
|
||||
top: parent.top
|
||||
}
|
||||
height: childrenRect.height + 4 * UM.Theme.getSize("default_margin").height
|
||||
|
||||
Label
|
||||
{
|
||||
visible: toolbox.pluginsInstalledModel.items.length > 0
|
||||
width: parent.width
|
||||
width: page.width
|
||||
text: catalog.i18nc("@title:tab", "Plugins")
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
font: UM.Theme.getFont("medium")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Rectangle
|
||||
{
|
||||
visible: toolbox.pluginsInstalledModel.items.length > 0
|
||||
color: "transparent"
|
||||
width: parent.width
|
||||
height: childrenRect.height + 1 * UM.Theme.getSize("default_lining").width
|
||||
height: childrenRect.height + UM.Theme.getSize("default_margin").width
|
||||
border.color: UM.Theme.getColor("lining")
|
||||
border.width: UM.Theme.getSize("default_lining").width
|
||||
Column
|
||||
{
|
||||
height: childrenRect.height
|
||||
anchors
|
||||
{
|
||||
top: parent.top
|
||||
right: parent.right
|
||||
left: parent.left
|
||||
leftMargin: UM.Theme.getSize("default_margin").width
|
||||
rightMargin: UM.Theme.getSize("default_margin").width
|
||||
topMargin: UM.Theme.getSize("default_lining").width
|
||||
bottomMargin: UM.Theme.getSize("default_lining").width
|
||||
margins: UM.Theme.getSize("default_margin").width
|
||||
}
|
||||
Repeater
|
||||
{
|
||||
|
@ -70,32 +66,27 @@ ScrollView
|
|||
}
|
||||
Label
|
||||
{
|
||||
visible: toolbox.materialsInstalledModel.items.length > 0
|
||||
width: page.width
|
||||
text: catalog.i18nc("@title:tab", "Materials")
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
font: UM.Theme.getFont("medium")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
Rectangle
|
||||
{
|
||||
visible: toolbox.materialsInstalledModel.items.length > 0
|
||||
color: "transparent"
|
||||
width: parent.width
|
||||
height: childrenRect.height + 1 * UM.Theme.getSize("default_lining").width
|
||||
height: childrenRect.height + UM.Theme.getSize("default_margin").width
|
||||
border.color: UM.Theme.getColor("lining")
|
||||
border.width: UM.Theme.getSize("default_lining").width
|
||||
Column
|
||||
{
|
||||
height: Math.max( UM.Theme.getSize("wide_margin").height, childrenRect.height)
|
||||
anchors
|
||||
{
|
||||
top: parent.top
|
||||
right: parent.right
|
||||
left: parent.left
|
||||
leftMargin: UM.Theme.getSize("default_margin").width
|
||||
rightMargin: UM.Theme.getSize("default_margin").width
|
||||
topMargin: UM.Theme.getSize("default_lining").width
|
||||
bottomMargin: UM.Theme.getSize("default_lining").width
|
||||
margins: UM.Theme.getSize("default_margin").width
|
||||
}
|
||||
Repeater
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.1 as UM
|
||||
|
@ -51,6 +51,7 @@ Item
|
|||
wrapMode: Text.WordWrap
|
||||
font: UM.Theme.getFont("default_bold")
|
||||
color: pluginInfo.color
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
Label
|
||||
{
|
||||
|
@ -60,6 +61,7 @@ Item
|
|||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
color: pluginInfo.color
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
Column
|
||||
|
@ -88,6 +90,7 @@ Item
|
|||
onLinkActivated: Qt.openUrlExternally("mailto:" + model.author_email + "?Subject=Cura: " + model.name + " Plugin")
|
||||
color: model.enabled ? UM.Theme.getColor("text") : UM.Theme.getColor("lining")
|
||||
linkColor: UM.Theme.getColor("text_link")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
Label
|
||||
|
@ -98,6 +101,7 @@ Item
|
|||
color: UM.Theme.getColor("text")
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
ToolboxInstalledTileActions
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.1 as UM
|
||||
|
||||
import Cura 1.1 as Cura
|
||||
|
||||
Column
|
||||
{
|
||||
property bool canUpdate: false
|
||||
property bool canDowngrade: false
|
||||
property bool loginRequired: model.login_required && !Cura.API.account.isLoggedIn
|
||||
width: UM.Theme.getSize("toolbox_action_button").width
|
||||
spacing: UM.Theme.getSize("narrow_margin").height
|
||||
|
||||
|
@ -21,6 +24,7 @@ Column
|
|||
font: UM.Theme.getFont("default")
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
ToolboxProgressButton
|
||||
|
@ -30,59 +34,49 @@ Column
|
|||
readyLabel: catalog.i18nc("@action:button", "Update")
|
||||
activeLabel: catalog.i18nc("@action:button", "Updating")
|
||||
completeLabel: catalog.i18nc("@action:button", "Updated")
|
||||
readyAction: function()
|
||||
onReadyAction:
|
||||
{
|
||||
toolbox.activePackage = model
|
||||
toolbox.update(model.id)
|
||||
}
|
||||
activeAction: function()
|
||||
{
|
||||
toolbox.cancelDownload()
|
||||
}
|
||||
onActiveAction: toolbox.cancelDownload()
|
||||
|
||||
// Don't allow installing while another download is running
|
||||
enabled: !(toolbox.isDownloading && toolbox.activePackage != model)
|
||||
enabled: !(toolbox.isDownloading && toolbox.activePackage != model) && !loginRequired
|
||||
opacity: enabled ? 1.0 : 0.5
|
||||
visible: canUpdate
|
||||
}
|
||||
|
||||
Button
|
||||
Label
|
||||
{
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label:The string between <a href=> and </a> is the highlighted link", "<a href='%1'>Log in</a> is required to update")
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text")
|
||||
linkColor: UM.Theme.getColor("text_link")
|
||||
visible: loginRequired
|
||||
width: updateButton.width
|
||||
renderType: Text.NativeRendering
|
||||
|
||||
MouseArea
|
||||
{
|
||||
anchors.fill: parent
|
||||
onClicked: Cura.API.account.login()
|
||||
}
|
||||
}
|
||||
|
||||
Cura.SecondaryButton
|
||||
{
|
||||
id: removeButton
|
||||
text: canDowngrade ? catalog.i18nc("@action:button", "Downgrade") : catalog.i18nc("@action:button", "Uninstall")
|
||||
visible: !model.is_bundled && model.is_installed
|
||||
enabled: !toolbox.isDownloading
|
||||
style: ButtonStyle
|
||||
{
|
||||
background: Rectangle
|
||||
{
|
||||
implicitWidth: UM.Theme.getSize("toolbox_action_button").width
|
||||
implicitHeight: UM.Theme.getSize("toolbox_action_button").height
|
||||
color: "transparent"
|
||||
border
|
||||
{
|
||||
width: UM.Theme.getSize("default_lining").width
|
||||
color:
|
||||
{
|
||||
if (control.hovered)
|
||||
{
|
||||
return UM.Theme.getColor("primary_hover")
|
||||
}
|
||||
else
|
||||
{
|
||||
return UM.Theme.getColor("lining")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
label: Label
|
||||
{
|
||||
text: control.text
|
||||
color: UM.Theme.getColor("text")
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font: UM.Theme.getFont("default")
|
||||
}
|
||||
}
|
||||
|
||||
width: UM.Theme.getSize("toolbox_action_button").width
|
||||
height: UM.Theme.getSize("toolbox_action_button").height
|
||||
|
||||
fixedWidthMode: true
|
||||
|
||||
onClicked: toolbox.checkPackageUsageAndUninstall(model.id)
|
||||
Connections
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Dialogs 1.1
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls 1.4
|
||||
|
@ -32,6 +32,7 @@ UM.Dialog
|
|||
anchors.right: parent.right
|
||||
text: licenseDialog.pluginName + catalog.i18nc("@label", "This plugin contains a license.\nYou need to accept this license to install this plugin.\nDo you agree with the terms below?")
|
||||
wrapMode: Text.Wrap
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
TextArea
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
|
@ -18,5 +18,6 @@ Rectangle
|
|||
{
|
||||
centerIn: parent
|
||||
}
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import QtQuick 2.2
|
|||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.1 as UM
|
||||
import Cura 1.0 as Cura
|
||||
|
||||
|
||||
Item
|
||||
|
@ -18,16 +19,19 @@ Item
|
|||
property var activeLabel: catalog.i18nc("@action:button", "Cancel")
|
||||
property var completeLabel: catalog.i18nc("@action:button", "Installed")
|
||||
|
||||
property var readyAction: null // Action when button is ready and clicked (likely install)
|
||||
property var activeAction: null // Action when button is active and clicked (likely cancel)
|
||||
property var completeAction: null // Action when button is complete and clicked (likely go to installed)
|
||||
signal readyAction() // Action when button is ready and clicked (likely install)
|
||||
signal activeAction() // Action when button is active and clicked (likely cancel)
|
||||
signal completeAction() // Action when button is complete and clicked (likely go to installed)
|
||||
|
||||
width: UM.Theme.getSize("toolbox_action_button").width
|
||||
height: UM.Theme.getSize("toolbox_action_button").height
|
||||
|
||||
Button
|
||||
Cura.PrimaryButton
|
||||
{
|
||||
id: button
|
||||
width: UM.Theme.getSize("toolbox_action_button").width
|
||||
height: UM.Theme.getSize("toolbox_action_button").height
|
||||
fixedWidthMode: true
|
||||
text:
|
||||
{
|
||||
if (complete)
|
||||
|
@ -47,101 +51,15 @@ Item
|
|||
{
|
||||
if (complete)
|
||||
{
|
||||
return completeAction()
|
||||
completeAction()
|
||||
}
|
||||
else if (active)
|
||||
{
|
||||
return activeAction()
|
||||
activeAction()
|
||||
}
|
||||
else
|
||||
{
|
||||
return readyAction()
|
||||
}
|
||||
}
|
||||
style: ButtonStyle
|
||||
{
|
||||
background: Rectangle
|
||||
{
|
||||
implicitWidth: UM.Theme.getSize("toolbox_action_button").width
|
||||
implicitHeight: UM.Theme.getSize("toolbox_action_button").height
|
||||
color:
|
||||
{
|
||||
if (base.complete)
|
||||
{
|
||||
return "transparent"
|
||||
}
|
||||
else
|
||||
{
|
||||
if (control.hovered)
|
||||
{
|
||||
return UM.Theme.getColor("primary_hover")
|
||||
}
|
||||
else
|
||||
{
|
||||
return UM.Theme.getColor("primary")
|
||||
}
|
||||
}
|
||||
}
|
||||
border
|
||||
{
|
||||
width:
|
||||
{
|
||||
if (base.complete)
|
||||
{
|
||||
UM.Theme.getSize("default_lining").width
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0
|
||||
}
|
||||
}
|
||||
color:
|
||||
{
|
||||
if (control.hovered)
|
||||
{
|
||||
return UM.Theme.getColor("primary_hover")
|
||||
}
|
||||
else
|
||||
{
|
||||
return UM.Theme.getColor("lining")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
label: Label
|
||||
{
|
||||
text: control.text
|
||||
color:
|
||||
{
|
||||
if (base.complete)
|
||||
{
|
||||
return UM.Theme.getColor("text")
|
||||
}
|
||||
else
|
||||
{
|
||||
if (control.hovered)
|
||||
{
|
||||
return UM.Theme.getColor("button_text_hover")
|
||||
}
|
||||
else
|
||||
{
|
||||
return UM.Theme.getColor("button_text")
|
||||
}
|
||||
}
|
||||
}
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font:
|
||||
{
|
||||
if (base.complete)
|
||||
{
|
||||
return UM.Theme.getFont("default")
|
||||
}
|
||||
else
|
||||
{
|
||||
return UM.Theme.getFont("default_bold")
|
||||
}
|
||||
}
|
||||
readyAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.3
|
||||
import UM 1.1 as UM
|
||||
|
||||
Button
|
||||
{
|
||||
id: control
|
||||
property bool active: false
|
||||
style: ButtonStyle
|
||||
hoverEnabled: true
|
||||
|
||||
background: Item
|
||||
{
|
||||
background: Rectangle
|
||||
{
|
||||
color: "transparent"
|
||||
implicitWidth: UM.Theme.getSize("toolbox_header_tab").width
|
||||
implicitHeight: UM.Theme.getSize("toolbox_header_tab").height
|
||||
Rectangle
|
||||
{
|
||||
visible: control.active
|
||||
color: UM.Theme.getColor("toolbox_header_highlight_hover")
|
||||
color: UM.Theme.getColor("primary")
|
||||
anchors.bottom: parent.bottom
|
||||
width: parent.width
|
||||
height: UM.Theme.getSize("toolbox_header_highlight").height
|
||||
}
|
||||
}
|
||||
label: Label
|
||||
contentItem: Label
|
||||
{
|
||||
id: label
|
||||
text: control.text
|
||||
color:
|
||||
{
|
||||
|
@ -46,6 +46,6 @@ Button
|
|||
font: control.enabled ? (control.active ? UM.Theme.getFont("medium_bold") : UM.Theme.getFont("medium")) : UM.Theme.getFont("default_italic")
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
}
|
|
@ -2,18 +2,19 @@
|
|||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import re
|
||||
from typing import Dict
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtProperty, pyqtSignal
|
||||
|
||||
from UM.Qt.ListModel import ListModel
|
||||
|
||||
|
||||
## Model that holds cura packages. By setting the filter property the instances held by this model can be changed.
|
||||
class AuthorsModel(ListModel):
|
||||
def __init__(self, parent = None):
|
||||
def __init__(self, parent = None) -> None:
|
||||
super().__init__(parent)
|
||||
|
||||
self._metadata = None
|
||||
self._metadata = None # type: Optional[List[Dict[str, Union[str, List[str], int]]]]
|
||||
|
||||
self.addRoleName(Qt.UserRole + 1, "id")
|
||||
self.addRoleName(Qt.UserRole + 2, "name")
|
||||
|
@ -27,37 +28,38 @@ class AuthorsModel(ListModel):
|
|||
# List of filters for queries. The result is the union of the each list of results.
|
||||
self._filter = {} # type: Dict[str, str]
|
||||
|
||||
def setMetadata(self, data):
|
||||
def setMetadata(self, data: List[Dict[str, Union[str, List[str], int]]]):
|
||||
if self._metadata != data:
|
||||
self._metadata = data
|
||||
self._update()
|
||||
|
||||
def _update(self):
|
||||
items = []
|
||||
def _update(self) -> None:
|
||||
items = [] # type: List[Dict[str, Union[str, List[str], int, None]]]
|
||||
if not self._metadata:
|
||||
self.setItems([])
|
||||
self.setItems(items)
|
||||
return
|
||||
|
||||
for author in self._metadata:
|
||||
items.append({
|
||||
"id": author["author_id"],
|
||||
"name": author["display_name"],
|
||||
"email": author["email"] if "email" in author else None,
|
||||
"website": author["website"],
|
||||
"package_count": author["package_count"] if "package_count" in author else 0,
|
||||
"package_types": author["package_types"] if "package_types" in author else [],
|
||||
"icon_url": author["icon_url"] if "icon_url" in author else None,
|
||||
"description": "Material and quality profiles from {author_name}".format(author_name = author["display_name"])
|
||||
"id": author.get("author_id"),
|
||||
"name": author.get("display_name"),
|
||||
"email": author.get("email"),
|
||||
"website": author.get("website"),
|
||||
"package_count": author.get("package_count", 0),
|
||||
"package_types": author.get("package_types", []),
|
||||
"icon_url": author.get("icon_url"),
|
||||
"description": "Material and quality profiles from {author_name}".format(author_name = author.get("display_name", ""))
|
||||
})
|
||||
|
||||
# Filter on all the key-word arguments.
|
||||
for key, value in self._filter.items():
|
||||
if key is "package_types":
|
||||
key_filter = lambda item, value = value: value in item["package_types"]
|
||||
key_filter = lambda item, value = value: value in item["package_types"] # type: ignore
|
||||
elif "*" in value:
|
||||
key_filter = lambda item, key = key, value = value: self._matchRegExp(item, key, value)
|
||||
key_filter = lambda item, key = key, value = value: self._matchRegExp(item, key, value) # type: ignore
|
||||
else:
|
||||
key_filter = lambda item, key = key, value = value: self._matchString(item, key, value)
|
||||
items = filter(key_filter, items)
|
||||
key_filter = lambda item, key = key, value = value: self._matchString(item, key, value) # type: ignore
|
||||
items = filter(key_filter, items) # type: ignore
|
||||
|
||||
# Execute all filters.
|
||||
filtered_items = list(items)
|
||||
|
|
|
@ -40,11 +40,16 @@ class PackagesModel(ListModel):
|
|||
self.addRoleName(Qt.UserRole + 19, "tags")
|
||||
self.addRoleName(Qt.UserRole + 20, "links")
|
||||
self.addRoleName(Qt.UserRole + 21, "website")
|
||||
self.addRoleName(Qt.UserRole + 22, "login_required")
|
||||
self.addRoleName(Qt.UserRole + 23, "average_rating")
|
||||
self.addRoleName(Qt.UserRole + 24, "num_ratings")
|
||||
self.addRoleName(Qt.UserRole + 25, "user_rating")
|
||||
|
||||
# List of filters for queries. The result is the union of the each list of results.
|
||||
self._filter = {} # type: Dict[str, str]
|
||||
|
||||
def setMetadata(self, data):
|
||||
if self._metadata != data:
|
||||
self._metadata = data
|
||||
self._update()
|
||||
|
||||
|
@ -99,6 +104,10 @@ class PackagesModel(ListModel):
|
|||
"tags": package["tags"] if "tags" in package else [],
|
||||
"links": links_dict,
|
||||
"website": package["website"] if "website" in package else None,
|
||||
"login_required": "login-required" in package.get("tags", []),
|
||||
"average_rating": float(package.get("rating", {}).get("average", 0)),
|
||||
"num_ratings": package.get("rating", {}).get("count", 0),
|
||||
"user_rating": package.get("rating", {}).get("user_rating", 0)
|
||||
})
|
||||
|
||||
# Filter on all the key-word arguments.
|
||||
|
|
|
@ -13,7 +13,6 @@ from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkRepl
|
|||
from UM.Logger import Logger
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
from UM.Extension import Extension
|
||||
from UM.Qt.ListModel import ListModel
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Version import Version
|
||||
|
||||
|
@ -50,47 +49,35 @@ class Toolbox(QObject, Extension):
|
|||
self._download_progress = 0 # type: float
|
||||
self._is_downloading = False # type: bool
|
||||
self._network_manager = None # type: Optional[QNetworkAccessManager]
|
||||
self._request_header = [
|
||||
b"User-Agent",
|
||||
str.encode(
|
||||
"%s/%s (%s %s)" % (
|
||||
self._application.getApplicationName(),
|
||||
self._application.getVersion(),
|
||||
platform.system(),
|
||||
platform.machine(),
|
||||
)
|
||||
)
|
||||
]
|
||||
self._request_headers = [] # type: List[Tuple[bytes, bytes]]
|
||||
self._updateRequestHeader()
|
||||
|
||||
|
||||
self._request_urls = {} # type: Dict[str, QUrl]
|
||||
self._to_update = [] # type: List[str] # Package_ids that are waiting to be updated
|
||||
self._old_plugin_ids = set() # type: Set[str]
|
||||
self._old_plugin_metadata = dict() # type: Dict[str, Dict[str, Any]]
|
||||
|
||||
# Data:
|
||||
self._metadata = {
|
||||
# The responses as given by the server parsed to a list.
|
||||
self._server_response_data = {
|
||||
"authors": [],
|
||||
"packages": [],
|
||||
"plugins_showcase": [],
|
||||
"plugins_available": [],
|
||||
"plugins_installed": [],
|
||||
"materials_showcase": [],
|
||||
"materials_available": [],
|
||||
"materials_installed": [],
|
||||
"materials_generic": []
|
||||
"packages": []
|
||||
} # type: Dict[str, List[Any]]
|
||||
|
||||
# Models:
|
||||
self._models = {
|
||||
"authors": AuthorsModel(self),
|
||||
"packages": PackagesModel(self),
|
||||
"plugins_showcase": PackagesModel(self),
|
||||
"plugins_available": PackagesModel(self),
|
||||
"plugins_installed": PackagesModel(self),
|
||||
"materials_showcase": AuthorsModel(self),
|
||||
"materials_available": AuthorsModel(self),
|
||||
"materials_installed": PackagesModel(self),
|
||||
"materials_generic": PackagesModel(self)
|
||||
} # type: Dict[str, ListModel]
|
||||
} # type: Dict[str, Union[AuthorsModel, PackagesModel]]
|
||||
|
||||
self._plugins_showcase_model = PackagesModel(self)
|
||||
self._plugins_available_model = PackagesModel(self)
|
||||
self._plugins_installed_model = PackagesModel(self)
|
||||
|
||||
self._materials_showcase_model = AuthorsModel(self)
|
||||
self._materials_available_model = AuthorsModel(self)
|
||||
self._materials_installed_model = PackagesModel(self)
|
||||
self._materials_generic_model = PackagesModel(self)
|
||||
|
||||
# These properties are for keeping track of the UI state:
|
||||
# ----------------------------------------------------------------------
|
||||
|
@ -120,6 +107,7 @@ class Toolbox(QObject, Extension):
|
|||
self._restart_dialog_message = "" # type: str
|
||||
|
||||
self._application.initializationFinished.connect(self._onAppInitialized)
|
||||
self._application.getCuraAPI().account.loginStateChanged.connect(self._updateRequestHeader)
|
||||
|
||||
# Signals:
|
||||
# --------------------------------------------------------------------------
|
||||
|
@ -139,12 +127,38 @@ class Toolbox(QObject, Extension):
|
|||
showLicenseDialog = pyqtSignal()
|
||||
uninstallVariablesChanged = pyqtSignal()
|
||||
|
||||
def _updateRequestHeader(self):
|
||||
self._request_headers = [
|
||||
(b"User-Agent",
|
||||
str.encode(
|
||||
"%s/%s (%s %s)" % (
|
||||
self._application.getApplicationName(),
|
||||
self._application.getVersion(),
|
||||
platform.system(),
|
||||
platform.machine(),
|
||||
)
|
||||
))
|
||||
]
|
||||
access_token = self._application.getCuraAPI().account.accessToken
|
||||
if access_token:
|
||||
self._request_headers.append((b"Authorization", "Bearer {}".format(access_token).encode()))
|
||||
|
||||
def _resetUninstallVariables(self) -> None:
|
||||
self._package_id_to_uninstall = None # type: Optional[str]
|
||||
self._package_name_to_uninstall = ""
|
||||
self._package_used_materials = [] # type: List[Tuple[GlobalStack, str, str]]
|
||||
self._package_used_qualities = [] # type: List[Tuple[GlobalStack, str, str]]
|
||||
|
||||
@pyqtSlot(str, int)
|
||||
def ratePackage(self, package_id: str, rating: int) -> None:
|
||||
url = QUrl("{base_url}/packages/{package_id}/ratings".format(base_url=self._api_url, package_id = package_id))
|
||||
|
||||
self._rate_request = QNetworkRequest(url)
|
||||
for header_name, header_value in self._request_headers:
|
||||
cast(QNetworkRequest, self._rate_request).setRawHeader(header_name, header_value)
|
||||
data = "{\"data\": {\"cura_version\": \"%s\", \"rating\": %i}}" % (Version(self._application.getVersion()), rating)
|
||||
self._rate_reply = cast(QNetworkAccessManager, self._network_manager).put(self._rate_request, data.encode())
|
||||
|
||||
@pyqtSlot(result = str)
|
||||
def getLicenseDialogPluginName(self) -> str:
|
||||
return self._license_dialog_plugin_name
|
||||
|
@ -178,12 +192,7 @@ class Toolbox(QObject, Extension):
|
|||
)
|
||||
self._request_urls = {
|
||||
"authors": QUrl("{base_url}/authors".format(base_url = self._api_url)),
|
||||
"packages": QUrl("{base_url}/packages".format(base_url = self._api_url)),
|
||||
"plugins_showcase": QUrl("{base_url}/showcase".format(base_url = self._api_url)),
|
||||
"plugins_available": QUrl("{base_url}/packages?package_type=plugin".format(base_url = self._api_url)),
|
||||
"materials_showcase": QUrl("{base_url}/showcase".format(base_url = self._api_url)),
|
||||
"materials_available": QUrl("{base_url}/packages?package_type=material".format(base_url = self._api_url)),
|
||||
"materials_generic": QUrl("{base_url}/packages?package_type=material&tags=generic".format(base_url = self._api_url))
|
||||
"packages": QUrl("{base_url}/packages".format(base_url = self._api_url))
|
||||
}
|
||||
|
||||
# Get the API root for the packages API depending on Cura version settings.
|
||||
|
@ -231,12 +240,6 @@ class Toolbox(QObject, Extension):
|
|||
# Make remote requests:
|
||||
self._makeRequestByType("packages")
|
||||
self._makeRequestByType("authors")
|
||||
# TODO: Uncomment in the future when the tag-filtered api calls work in the cloud server
|
||||
# self._makeRequestByType("plugins_showcase")
|
||||
# self._makeRequestByType("plugins_available")
|
||||
# self._makeRequestByType("materials_showcase")
|
||||
# self._makeRequestByType("materials_available")
|
||||
# self._makeRequestByType("materials_generic")
|
||||
|
||||
# Gather installed packages:
|
||||
self._updateInstalledModels()
|
||||
|
@ -281,7 +284,7 @@ class Toolbox(QObject, Extension):
|
|||
"description": plugin_data["plugin"]["description"]
|
||||
}
|
||||
return formatted
|
||||
except:
|
||||
except KeyError:
|
||||
Logger.log("w", "Unable to convert plugin meta data %s", str(plugin_data))
|
||||
return None
|
||||
|
||||
|
@ -319,13 +322,10 @@ class Toolbox(QObject, Extension):
|
|||
if plugin_id not in all_plugin_package_ids)
|
||||
self._old_plugin_metadata = {k: v for k, v in self._old_plugin_metadata.items() if k in self._old_plugin_ids}
|
||||
|
||||
self._metadata["plugins_installed"] = all_packages["plugin"] + list(self._old_plugin_metadata.values())
|
||||
self._models["plugins_installed"].setMetadata(self._metadata["plugins_installed"])
|
||||
self._plugins_installed_model.setMetadata(all_packages["plugin"] + list(self._old_plugin_metadata.values()))
|
||||
self.metadataChanged.emit()
|
||||
if "material" in all_packages:
|
||||
self._metadata["materials_installed"] = all_packages["material"]
|
||||
# TODO: ADD MATERIALS HERE ONCE MATERIALS PORTION OF TOOLBOX IS LIVE
|
||||
self._models["materials_installed"].setMetadata(self._metadata["materials_installed"])
|
||||
self._materials_installed_model.setMetadata(all_packages["material"])
|
||||
self.metadataChanged.emit()
|
||||
|
||||
@pyqtSlot(str)
|
||||
|
@ -479,7 +479,7 @@ class Toolbox(QObject, Extension):
|
|||
def getRemotePackage(self, package_id: str) -> Optional[Dict]:
|
||||
# TODO: make the lookup in a dict, not a loop. canUpdate is called for every item.
|
||||
remote_package = None
|
||||
for package in self._metadata["packages"]:
|
||||
for package in self._server_response_data["packages"]:
|
||||
if package["package_id"] == package_id:
|
||||
remote_package = package
|
||||
break
|
||||
|
@ -491,11 +491,8 @@ class Toolbox(QObject, Extension):
|
|||
def canUpdate(self, package_id: str) -> bool:
|
||||
local_package = self._package_manager.getInstalledPackageInfo(package_id)
|
||||
if local_package is None:
|
||||
Logger.log("i", "Could not find package [%s] as installed in the package manager, fall back to check the old plugins",
|
||||
package_id)
|
||||
local_package = self.getOldPluginPackageMetadata(package_id)
|
||||
if local_package is None:
|
||||
Logger.log("i", "Could not find package [%s] in the old plugins", package_id)
|
||||
return False
|
||||
|
||||
remote_package = self.getRemotePackage(package_id)
|
||||
|
@ -545,8 +542,8 @@ class Toolbox(QObject, Extension):
|
|||
@pyqtSlot(str, result = int)
|
||||
def getNumberOfInstalledPackagesByAuthor(self, author_id: str) -> int:
|
||||
count = 0
|
||||
for package in self._metadata["materials_installed"]:
|
||||
if package["author"]["author_id"] == author_id:
|
||||
for package in self._materials_installed_model.items:
|
||||
if package["author_id"] == author_id:
|
||||
count += 1
|
||||
return count
|
||||
|
||||
|
@ -554,7 +551,7 @@ class Toolbox(QObject, Extension):
|
|||
@pyqtSlot(str, result = int)
|
||||
def getTotalNumberOfMaterialPackagesByAuthor(self, author_id: str) -> int:
|
||||
count = 0
|
||||
for package in self._metadata["packages"]:
|
||||
for package in self._server_response_data["packages"]:
|
||||
if package["package_type"] == "material":
|
||||
if package["author"]["author_id"] == author_id:
|
||||
count += 1
|
||||
|
@ -568,34 +565,31 @@ class Toolbox(QObject, Extension):
|
|||
|
||||
# Check for plugins that were installed with the old plugin browser
|
||||
def isOldPlugin(self, plugin_id: str) -> bool:
|
||||
if plugin_id in self._old_plugin_ids:
|
||||
return True
|
||||
return False
|
||||
return plugin_id in self._old_plugin_ids
|
||||
|
||||
def getOldPluginPackageMetadata(self, plugin_id: str) -> Optional[Dict[str, Any]]:
|
||||
return self._old_plugin_metadata.get(plugin_id)
|
||||
|
||||
def loadingComplete(self) -> bool:
|
||||
def isLoadingComplete(self) -> bool:
|
||||
populated = 0
|
||||
for list in self._metadata.items():
|
||||
if len(list) > 0:
|
||||
for metadata_list in self._server_response_data.items():
|
||||
if metadata_list:
|
||||
populated += 1
|
||||
if populated == len(self._metadata.items()):
|
||||
return True
|
||||
return False
|
||||
return populated == len(self._server_response_data.items())
|
||||
|
||||
# Make API Calls
|
||||
# --------------------------------------------------------------------------
|
||||
def _makeRequestByType(self, type: str) -> None:
|
||||
Logger.log("i", "Marketplace: Requesting %s metadata from server.", type)
|
||||
request = QNetworkRequest(self._request_urls[type])
|
||||
request.setRawHeader(*self._request_header)
|
||||
def _makeRequestByType(self, request_type: str) -> None:
|
||||
Logger.log("i", "Requesting %s metadata from server.", request_type)
|
||||
request = QNetworkRequest(self._request_urls[request_type])
|
||||
for header_name, header_value in self._request_headers:
|
||||
request.setRawHeader(header_name, header_value)
|
||||
if self._network_manager:
|
||||
self._network_manager.get(request)
|
||||
|
||||
@pyqtSlot(str)
|
||||
def startDownload(self, url: str) -> None:
|
||||
Logger.log("i", "Marketplace: Attempting to download & install package from %s.", url)
|
||||
Logger.log("i", "Attempting to download & install package from %s.", url)
|
||||
url = QUrl(url)
|
||||
self._download_request = QNetworkRequest(url)
|
||||
if hasattr(QNetworkRequest, "FollowRedirectsAttribute"):
|
||||
|
@ -604,7 +598,8 @@ class Toolbox(QObject, Extension):
|
|||
if hasattr(QNetworkRequest, "RedirectPolicyAttribute"):
|
||||
# Patch for Qt 5.9+
|
||||
cast(QNetworkRequest, self._download_request).setAttribute(QNetworkRequest.RedirectPolicyAttribute, True)
|
||||
cast(QNetworkRequest, self._download_request).setRawHeader(*self._request_header)
|
||||
for header_name, header_value in self._request_headers:
|
||||
cast(QNetworkRequest, self._download_request).setRawHeader(header_name, header_value)
|
||||
self._download_reply = cast(QNetworkAccessManager, self._network_manager).get(self._download_request)
|
||||
self.setDownloadProgress(0)
|
||||
self.setIsDownloading(True)
|
||||
|
@ -612,7 +607,7 @@ class Toolbox(QObject, Extension):
|
|||
|
||||
@pyqtSlot()
|
||||
def cancelDownload(self) -> None:
|
||||
Logger.log("i", "Marketplace: User cancelled the download of a package.")
|
||||
Logger.log("i", "User cancelled the download of a package.")
|
||||
self.resetDownload()
|
||||
|
||||
def resetDownload(self) -> None:
|
||||
|
@ -646,22 +641,8 @@ class Toolbox(QObject, Extension):
|
|||
self.resetDownload()
|
||||
return
|
||||
|
||||
# HACK: These request are not handled independently at this moment, but together from the "packages" call
|
||||
do_not_handle = [
|
||||
"materials_available",
|
||||
"materials_showcase",
|
||||
"materials_generic",
|
||||
"plugins_available",
|
||||
"plugins_showcase",
|
||||
]
|
||||
|
||||
if reply.operation() == QNetworkAccessManager.GetOperation:
|
||||
for type, url in self._request_urls.items():
|
||||
|
||||
# HACK: Do nothing because we'll handle these from the "packages" call
|
||||
if type in do_not_handle:
|
||||
continue
|
||||
|
||||
for response_type, url in self._request_urls.items():
|
||||
if reply.url() == url:
|
||||
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 200:
|
||||
try:
|
||||
|
@ -674,39 +655,33 @@ class Toolbox(QObject, Extension):
|
|||
return
|
||||
|
||||
# Create model and apply metadata:
|
||||
if not self._models[type]:
|
||||
Logger.log("e", "Could not find the %s model.", type)
|
||||
if not self._models[response_type]:
|
||||
Logger.log("e", "Could not find the %s model.", response_type)
|
||||
break
|
||||
|
||||
self._metadata[type] = json_data["data"]
|
||||
self._models[type].setMetadata(self._metadata[type])
|
||||
self._server_response_data[response_type] = json_data["data"]
|
||||
self._models[response_type].setMetadata(self._server_response_data[response_type])
|
||||
|
||||
# Do some auto filtering
|
||||
# TODO: Make multiple API calls in the future to handle this
|
||||
if type is "packages":
|
||||
self._models[type].setFilter({"type": "plugin"})
|
||||
self.buildMaterialsModels()
|
||||
self.buildPluginsModels()
|
||||
if type is "authors":
|
||||
self._models[type].setFilter({"package_types": "material"})
|
||||
if type is "materials_generic":
|
||||
self._models[type].setFilter({"tags": "generic"})
|
||||
if response_type is "packages":
|
||||
self._models[response_type].setFilter({"type": "plugin"})
|
||||
self.reBuildMaterialsModels()
|
||||
self.reBuildPluginsModels()
|
||||
elif response_type is "authors":
|
||||
self._models[response_type].setFilter({"package_types": "material"})
|
||||
self._models[response_type].setFilter({"tags": "generic"})
|
||||
|
||||
self.metadataChanged.emit()
|
||||
|
||||
if self.loadingComplete() is True:
|
||||
if self.isLoadingComplete():
|
||||
self.setViewPage("overview")
|
||||
|
||||
return
|
||||
except json.decoder.JSONDecodeError:
|
||||
Logger.log("w", "Marketplace: Received invalid JSON for %s.", type)
|
||||
Logger.log("w", "Received invalid JSON for %s.", response_type)
|
||||
break
|
||||
else:
|
||||
self.setViewPage("errored")
|
||||
self.resetDownload()
|
||||
return
|
||||
|
||||
else:
|
||||
elif reply.operation() == QNetworkAccessManager.PutOperation:
|
||||
# Ignore any operation that is not a get operation
|
||||
pass
|
||||
|
||||
|
@ -716,7 +691,13 @@ class Toolbox(QObject, Extension):
|
|||
self.setDownloadProgress(new_progress)
|
||||
if bytes_sent == bytes_total:
|
||||
self.setIsDownloading(False)
|
||||
cast(QNetworkReply, self._download_reply).downloadProgress.disconnect(self._onDownloadProgress)
|
||||
self._download_reply = cast(QNetworkReply, self._download_reply)
|
||||
self._download_reply.downloadProgress.disconnect(self._onDownloadProgress)
|
||||
|
||||
# Check if the download was sucessfull
|
||||
if self._download_reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200:
|
||||
Logger.log("w", "Failed to download package. The following error was returned: %s", json.loads(bytes(self._download_reply.readAll()).decode("utf-8")))
|
||||
return
|
||||
# Must not delete the temporary file on Windows
|
||||
self._temp_plugin_file = tempfile.NamedTemporaryFile(mode = "w+b", suffix = ".curapackage", delete = False)
|
||||
file_path = self._temp_plugin_file.name
|
||||
|
@ -726,10 +707,10 @@ class Toolbox(QObject, Extension):
|
|||
self._onDownloadComplete(file_path)
|
||||
|
||||
def _onDownloadComplete(self, file_path: str) -> None:
|
||||
Logger.log("i", "Marketplace: Download complete.")
|
||||
Logger.log("i", "Download complete.")
|
||||
package_info = self._package_manager.getPackageInfo(file_path)
|
||||
if not package_info:
|
||||
Logger.log("w", "Marketplace: Package file [%s] was not a valid CuraPackage.", file_path)
|
||||
Logger.log("w", "Package file [%s] was not a valid CuraPackage.", file_path)
|
||||
return
|
||||
|
||||
license_content = self._package_manager.getPackageLicense(file_path)
|
||||
|
@ -738,7 +719,6 @@ class Toolbox(QObject, Extension):
|
|||
return
|
||||
|
||||
self.install(file_path)
|
||||
return
|
||||
|
||||
# Getter & Setters for Properties:
|
||||
# --------------------------------------------------------------------------
|
||||
|
@ -761,6 +741,7 @@ class Toolbox(QObject, Extension):
|
|||
return self._is_downloading
|
||||
|
||||
def setActivePackage(self, package: Dict[str, Any]) -> None:
|
||||
if self._active_package != package:
|
||||
self._active_package = package
|
||||
self.activePackageChanged.emit()
|
||||
|
||||
|
@ -770,6 +751,7 @@ class Toolbox(QObject, Extension):
|
|||
return self._active_package
|
||||
|
||||
def setViewCategory(self, category: str = "plugin") -> None:
|
||||
if self._view_category != category:
|
||||
self._view_category = category
|
||||
self.viewChanged.emit()
|
||||
|
||||
|
@ -778,6 +760,7 @@ class Toolbox(QObject, Extension):
|
|||
return self._view_category
|
||||
|
||||
def setViewPage(self, page: str = "overview") -> None:
|
||||
if self._view_page != page:
|
||||
self._view_page = page
|
||||
self.viewChanged.emit()
|
||||
|
||||
|
@ -787,48 +770,48 @@ class Toolbox(QObject, Extension):
|
|||
|
||||
# Exposed Models:
|
||||
# --------------------------------------------------------------------------
|
||||
@pyqtProperty(QObject, notify = metadataChanged)
|
||||
@pyqtProperty(QObject, constant=True)
|
||||
def authorsModel(self) -> AuthorsModel:
|
||||
return cast(AuthorsModel, self._models["authors"])
|
||||
|
||||
@pyqtProperty(QObject, notify = metadataChanged)
|
||||
@pyqtProperty(QObject, constant=True)
|
||||
def packagesModel(self) -> PackagesModel:
|
||||
return cast(PackagesModel, self._models["packages"])
|
||||
|
||||
@pyqtProperty(QObject, notify = metadataChanged)
|
||||
@pyqtProperty(QObject, constant=True)
|
||||
def pluginsShowcaseModel(self) -> PackagesModel:
|
||||
return cast(PackagesModel, self._models["plugins_showcase"])
|
||||
return self._plugins_showcase_model
|
||||
|
||||
@pyqtProperty(QObject, notify = metadataChanged)
|
||||
@pyqtProperty(QObject, constant=True)
|
||||
def pluginsAvailableModel(self) -> PackagesModel:
|
||||
return cast(PackagesModel, self._models["plugins_available"])
|
||||
return self._plugins_available_model
|
||||
|
||||
@pyqtProperty(QObject, notify = metadataChanged)
|
||||
@pyqtProperty(QObject, constant=True)
|
||||
def pluginsInstalledModel(self) -> PackagesModel:
|
||||
return cast(PackagesModel, self._models["plugins_installed"])
|
||||
return self._plugins_installed_model
|
||||
|
||||
@pyqtProperty(QObject, notify = metadataChanged)
|
||||
@pyqtProperty(QObject, constant=True)
|
||||
def materialsShowcaseModel(self) -> AuthorsModel:
|
||||
return cast(AuthorsModel, self._models["materials_showcase"])
|
||||
return self._materials_showcase_model
|
||||
|
||||
@pyqtProperty(QObject, notify = metadataChanged)
|
||||
@pyqtProperty(QObject, constant=True)
|
||||
def materialsAvailableModel(self) -> AuthorsModel:
|
||||
return cast(AuthorsModel, self._models["materials_available"])
|
||||
return self._materials_available_model
|
||||
|
||||
@pyqtProperty(QObject, notify = metadataChanged)
|
||||
@pyqtProperty(QObject, constant=True)
|
||||
def materialsInstalledModel(self) -> PackagesModel:
|
||||
return cast(PackagesModel, self._models["materials_installed"])
|
||||
return self._materials_installed_model
|
||||
|
||||
@pyqtProperty(QObject, notify=metadataChanged)
|
||||
@pyqtProperty(QObject, constant=True)
|
||||
def materialsGenericModel(self) -> PackagesModel:
|
||||
return cast(PackagesModel, self._models["materials_generic"])
|
||||
return self._materials_generic_model
|
||||
|
||||
# Filter Models:
|
||||
# --------------------------------------------------------------------------
|
||||
@pyqtSlot(str, str, str)
|
||||
def filterModelByProp(self, model_type: str, filter_type: str, parameter: str) -> None:
|
||||
if not self._models[model_type]:
|
||||
Logger.log("w", "Marketplace: Couldn't filter %s model because it doesn't exist.", model_type)
|
||||
Logger.log("w", "Couldn't filter %s model because it doesn't exist.", model_type)
|
||||
return
|
||||
self._models[model_type].setFilter({filter_type: parameter})
|
||||
self.filterChanged.emit()
|
||||
|
@ -836,7 +819,7 @@ class Toolbox(QObject, Extension):
|
|||
@pyqtSlot(str, "QVariantMap")
|
||||
def setFilters(self, model_type: str, filter_dict: dict) -> None:
|
||||
if not self._models[model_type]:
|
||||
Logger.log("w", "Marketplace: Couldn't filter %s model because it doesn't exist.", model_type)
|
||||
Logger.log("w", "Couldn't filter %s model because it doesn't exist.", model_type)
|
||||
return
|
||||
self._models[model_type].setFilter(filter_dict)
|
||||
self.filterChanged.emit()
|
||||
|
@ -844,21 +827,21 @@ class Toolbox(QObject, Extension):
|
|||
@pyqtSlot(str)
|
||||
def removeFilters(self, model_type: str) -> None:
|
||||
if not self._models[model_type]:
|
||||
Logger.log("w", "Marketplace: Couldn't remove filters on %s model because it doesn't exist.", model_type)
|
||||
Logger.log("w", "Couldn't remove filters on %s model because it doesn't exist.", model_type)
|
||||
return
|
||||
self._models[model_type].setFilter({})
|
||||
self.filterChanged.emit()
|
||||
|
||||
# HACK(S):
|
||||
# --------------------------------------------------------------------------
|
||||
def buildMaterialsModels(self) -> None:
|
||||
self._metadata["materials_showcase"] = []
|
||||
self._metadata["materials_available"] = []
|
||||
self._metadata["materials_generic"] = []
|
||||
def reBuildMaterialsModels(self) -> None:
|
||||
materials_showcase_metadata = []
|
||||
materials_available_metadata = []
|
||||
materials_generic_metadata = []
|
||||
|
||||
processed_authors = [] # type: List[str]
|
||||
|
||||
for item in self._metadata["packages"]:
|
||||
for item in self._server_response_data["packages"]:
|
||||
if item["package_type"] == "material":
|
||||
|
||||
author = item["author"]
|
||||
|
@ -867,30 +850,29 @@ class Toolbox(QObject, Extension):
|
|||
|
||||
# Generic materials to be in the same section
|
||||
if "generic" in item["tags"]:
|
||||
self._metadata["materials_generic"].append(item)
|
||||
materials_generic_metadata.append(item)
|
||||
else:
|
||||
if "showcase" in item["tags"]:
|
||||
self._metadata["materials_showcase"].append(author)
|
||||
materials_showcase_metadata.append(author)
|
||||
else:
|
||||
self._metadata["materials_available"].append(author)
|
||||
materials_available_metadata.append(author)
|
||||
|
||||
processed_authors.append(author["author_id"])
|
||||
|
||||
self._models["materials_showcase"].setMetadata(self._metadata["materials_showcase"])
|
||||
self._models["materials_available"].setMetadata(self._metadata["materials_available"])
|
||||
self._models["materials_generic"].setMetadata(self._metadata["materials_generic"])
|
||||
self._materials_showcase_model.setMetadata(materials_showcase_metadata)
|
||||
self._materials_available_model.setMetadata(materials_available_metadata)
|
||||
self._materials_generic_model.setMetadata(materials_generic_metadata)
|
||||
|
||||
def buildPluginsModels(self) -> None:
|
||||
self._metadata["plugins_showcase"] = []
|
||||
self._metadata["plugins_available"] = []
|
||||
def reBuildPluginsModels(self) -> None:
|
||||
plugins_showcase_metadata = []
|
||||
plugins_available_metadata = []
|
||||
|
||||
for item in self._metadata["packages"]:
|
||||
for item in self._server_response_data["packages"]:
|
||||
if item["package_type"] == "plugin":
|
||||
|
||||
if "showcase" in item["tags"]:
|
||||
self._metadata["plugins_showcase"].append(item)
|
||||
plugins_showcase_metadata.append(item)
|
||||
else:
|
||||
self._metadata["plugins_available"].append(item)
|
||||
plugins_available_metadata.append(item)
|
||||
|
||||
self._models["plugins_showcase"].setMetadata(self._metadata["plugins_showcase"])
|
||||
self._models["plugins_available"].setMetadata(self._metadata["plugins_available"])
|
||||
self._plugins_showcase_model.setMetadata(plugins_showcase_metadata)
|
||||
self._plugins_available_model.setMetadata(plugins_available_metadata)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "UFP Writer",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Provides support for writing Ultimaker Format Packages.",
|
||||
"api": 5,
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
"name": "UM3 Network Connection",
|
||||
"author": "Ultimaker B.V.",
|
||||
"description": "Manages network connections to Ultimaker 3 printers.",
|
||||
"version": "1.0.0",
|
||||
"api": 5,
|
||||
"version": "1.0.1",
|
||||
"api": "6.0",
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
|
|
|
@ -8,11 +8,13 @@ import UM 1.3 as UM
|
|||
import Cura 1.0 as Cura
|
||||
|
||||
Rectangle {
|
||||
id: base
|
||||
property var iconSource: null;
|
||||
color: "#0a0850" // TODO: Theme!
|
||||
height: width;
|
||||
radius: Math.round(0.5 * width);
|
||||
width: 24 * screenScaleFactor;
|
||||
property var enabled: true
|
||||
|
||||
UM.RecolorImage {
|
||||
id: icon;
|
||||
|
@ -29,12 +31,18 @@ Rectangle {
|
|||
MouseArea {
|
||||
id: clickArea;
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
hoverEnabled: base.enabled
|
||||
onClicked: {
|
||||
if (OutputDevice.activeCameraUrl != "") {
|
||||
OutputDevice.setActiveCameraUrl("");
|
||||
} else {
|
||||
OutputDevice.setActiveCameraUrl(modelData.cameraUrl);
|
||||
if (base.enabled)
|
||||
{
|
||||
if (OutputDevice.activeCameraUrl != "")
|
||||
{
|
||||
OutputDevice.setActiveCameraUrl("")
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputDevice.setActiveCameraUrl(modelData.cameraUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
import UM 1.3 as UM
|
||||
import Cura 1.0 as Cura
|
||||
|
||||
Component {
|
||||
Rectangle {
|
||||
id: base;
|
||||
property var shadowRadius: UM.Theme.getSize("monitor_shadow_radius").width;
|
||||
property var cornerRadius: UM.Theme.getSize("monitor_corner_radius").width;
|
||||
anchors.fill: parent;
|
||||
color: UM.Theme.getColor("main_background");
|
||||
visible: OutputDevice != null;
|
||||
|
||||
UM.I18nCatalog {
|
||||
id: catalog;
|
||||
name: "cura";
|
||||
}
|
||||
|
||||
Label {
|
||||
id: printingLabel;
|
||||
anchors {
|
||||
left: parent.left;
|
||||
leftMargin: 4 * UM.Theme.getSize("default_margin").width;
|
||||
margins: 2 * UM.Theme.getSize("default_margin").width;
|
||||
right: parent.right;
|
||||
top: parent.top;
|
||||
}
|
||||
color: UM.Theme.getColor("text");
|
||||
elide: Text.ElideRight;
|
||||
font: UM.Theme.getFont("large");
|
||||
text: catalog.i18nc("@label", "Printing");
|
||||
}
|
||||
|
||||
Label {
|
||||
id: managePrintersLabel;
|
||||
anchors {
|
||||
bottom: printingLabel.bottom;
|
||||
right: printerScrollView.right;
|
||||
rightMargin: 4 * UM.Theme.getSize("default_margin").width;
|
||||
}
|
||||
color: UM.Theme.getColor("primary"); // "Cura Blue"
|
||||
font: UM.Theme.getFont("default");
|
||||
linkColor: UM.Theme.getColor("primary"); // "Cura Blue"
|
||||
text: catalog.i18nc("@label link to connect manager", "Manage printers");
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: managePrintersLabel;
|
||||
hoverEnabled: true;
|
||||
onClicked: Cura.MachineManager.printerOutputDevices[0].openPrinterControlPanel();
|
||||
onEntered: managePrintersLabel.font.underline = true;
|
||||
onExited: managePrintersLabel.font.underline = false;
|
||||
}
|
||||
|
||||
// Skeleton loading
|
||||
Column {
|
||||
id: skeletonLoader;
|
||||
anchors {
|
||||
left: parent.left;
|
||||
leftMargin: UM.Theme.getSize("wide_margin").width;
|
||||
right: parent.right;
|
||||
rightMargin: UM.Theme.getSize("wide_margin").width;
|
||||
top: printingLabel.bottom;
|
||||
topMargin: UM.Theme.getSize("default_margin").height;
|
||||
}
|
||||
spacing: UM.Theme.getSize("default_margin").height - 10;
|
||||
visible: printerList.count === 0;
|
||||
|
||||
PrinterCard {
|
||||
printer: null;
|
||||
}
|
||||
PrinterCard {
|
||||
printer: null;
|
||||
}
|
||||
}
|
||||
|
||||
// Actual content
|
||||
ScrollView {
|
||||
id: printerScrollView;
|
||||
anchors {
|
||||
bottom: parent.bottom;
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
top: printingLabel.bottom;
|
||||
topMargin: UM.Theme.getSize("default_margin").height;
|
||||
}
|
||||
style: UM.Theme.styles.scrollview;
|
||||
|
||||
ListView {
|
||||
id: printerList;
|
||||
property var currentIndex: -1;
|
||||
anchors {
|
||||
fill: parent;
|
||||
leftMargin: UM.Theme.getSize("wide_margin").width;
|
||||
rightMargin: UM.Theme.getSize("wide_margin").width;
|
||||
}
|
||||
delegate: PrinterCard {
|
||||
printer: modelData;
|
||||
}
|
||||
model: OutputDevice.printers;
|
||||
spacing: UM.Theme.getSize("default_margin").height - 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,247 +0,0 @@
|
|||
// 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.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.3 as UM
|
||||
import Cura 1.0 as Cura
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
Component
|
||||
{
|
||||
Item
|
||||
{
|
||||
id: monitorFrame
|
||||
|
||||
property var emphasisColor: UM.Theme.getColor("setting_control_border_highlight")
|
||||
property var cornerRadius: UM.Theme.getSize("monitor_corner_radius").width
|
||||
|
||||
height: maximumHeight
|
||||
onVisibleChanged:
|
||||
{
|
||||
if (monitorFrame != null && !monitorFrame.visible)
|
||||
{
|
||||
OutputDevice.setActiveCameraUrl("")
|
||||
}
|
||||
}
|
||||
width: maximumWidth
|
||||
|
||||
UM.I18nCatalog
|
||||
{
|
||||
id: catalog
|
||||
name: "cura"
|
||||
}
|
||||
|
||||
LinearGradient {
|
||||
anchors.fill: parent
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.0
|
||||
color: "#f6f6f6"
|
||||
}
|
||||
GradientStop {
|
||||
position: 1.0
|
||||
color: "#ffffff"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
id: queue
|
||||
width: Math.min(834 * screenScaleFactor, maximumWidth)
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: printers.bottom
|
||||
topMargin: 48 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
id: queuedLabel
|
||||
anchors
|
||||
{
|
||||
left: queuedPrintJobs.left
|
||||
top: parent.top
|
||||
}
|
||||
color: UM.Theme.getColor("text")
|
||||
font: UM.Theme.getFont("large_nonbold")
|
||||
text: catalog.i18nc("@label", "Queued")
|
||||
}
|
||||
|
||||
Item
|
||||
{
|
||||
id: manageQueueLabel
|
||||
anchors
|
||||
{
|
||||
right: queuedPrintJobs.right
|
||||
verticalCenter: queuedLabel.verticalCenter
|
||||
}
|
||||
height: 18 * screenScaleFactor // TODO: Theme!
|
||||
width: childrenRect.width
|
||||
|
||||
UM.RecolorImage
|
||||
{
|
||||
id: externalLinkIcon
|
||||
anchors.verticalCenter: manageQueueLabel.verticalCenter
|
||||
color: UM.Theme.getColor("primary")
|
||||
source: "../svg/icons/external_link.svg"
|
||||
width: 16 * screenScaleFactor // TODO: Theme! (Y U NO USE 18 LIKE ALL OTHER ICONS?!)
|
||||
height: 16 * screenScaleFactor // TODO: Theme! (Y U NO USE 18 LIKE ALL OTHER ICONS?!)
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: manageQueueText
|
||||
anchors
|
||||
{
|
||||
left: externalLinkIcon.right
|
||||
leftMargin: 6 * screenScaleFactor // TODO: Theme!
|
||||
verticalCenter: externalLinkIcon.verticalCenter
|
||||
}
|
||||
color: UM.Theme.getColor("primary")
|
||||
font: UM.Theme.getFont("default")
|
||||
linkColor: UM.Theme.getColor("primary")
|
||||
text: catalog.i18nc("@label link to connect manager", "Manage queue in Cura Connect")
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea
|
||||
{
|
||||
anchors.fill: manageQueueLabel
|
||||
hoverEnabled: true
|
||||
onClicked: Cura.MachineManager.printerOutputDevices[0].openPrintJobControlPanel()
|
||||
onEntered:
|
||||
{
|
||||
manageQueueText.font.underline = true
|
||||
}
|
||||
onExited:
|
||||
{
|
||||
manageQueueText.font.underline = false
|
||||
}
|
||||
}
|
||||
|
||||
Row
|
||||
{
|
||||
id: printJobQueueHeadings
|
||||
anchors
|
||||
{
|
||||
left: queuedPrintJobs.left
|
||||
leftMargin: 6 * screenScaleFactor // TODO: Theme!
|
||||
top: queuedLabel.bottom
|
||||
topMargin: 24 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
spacing: 18 * screenScaleFactor // TODO: Theme!
|
||||
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@label", "Print jobs")
|
||||
color: "#666666"
|
||||
elide: Text.ElideRight
|
||||
font: UM.Theme.getFont("medium") // 14pt, regular
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 284 * screenScaleFactor // TODO: Theme! (Should match column size)
|
||||
|
||||
// FIXED-LINE-HEIGHT:
|
||||
height: 18 * screenScaleFactor // TODO: Theme!
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@label", "Total print time")
|
||||
color: "#666666"
|
||||
elide: Text.ElideRight
|
||||
font: UM.Theme.getFont("medium") // 14pt, regular
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 216 * screenScaleFactor // TODO: Theme! (Should match column size)
|
||||
|
||||
// FIXED-LINE-HEIGHT:
|
||||
height: 18 * screenScaleFactor // TODO: Theme!
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@label", "Waiting for")
|
||||
color: "#666666"
|
||||
elide: Text.ElideRight
|
||||
font: UM.Theme.getFont("medium") // 14pt, regular
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 216 * screenScaleFactor // TODO: Theme! (Should match column size)
|
||||
|
||||
// FIXED-LINE-HEIGHT:
|
||||
height: 18 * screenScaleFactor // TODO: Theme!
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView
|
||||
{
|
||||
id: queuedPrintJobs
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: printJobQueueHeadings.bottom
|
||||
topMargin: 12 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
style: UM.Theme.styles.scrollview
|
||||
visible: OutputDevice.receivedPrintJobs
|
||||
width: parent.width
|
||||
|
||||
ListView
|
||||
{
|
||||
id: printJobList
|
||||
anchors.fill: parent
|
||||
delegate: MonitorPrintJobCard
|
||||
{
|
||||
anchors
|
||||
{
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
printJob: modelData
|
||||
}
|
||||
model: OutputDevice.queuedPrintJobs
|
||||
spacing: 6
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PrinterVideoStream {
|
||||
anchors.fill: parent
|
||||
cameraUrl: OutputDevice.activeCameraUrl
|
||||
visible: OutputDevice.activeCameraUrl != ""
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,9 +16,9 @@ Item
|
|||
|
||||
property bool expanded: false
|
||||
property var borderWidth: 1
|
||||
property color borderColor: "#EAEAEC"
|
||||
property color borderColor: "#CCCCCC"
|
||||
property color headerBackgroundColor: "white"
|
||||
property color headerHoverColor: "#f5f5f5"
|
||||
property color headerHoverColor: "#e8f2fc"
|
||||
property color drawerBackgroundColor: "white"
|
||||
property alias headerItem: header.children
|
||||
property alias drawerItem: drawer.children
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
// 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
|
||||
|
||||
Rectangle {
|
||||
color: UM.Theme.getColor("monitor_lining_light"); // TODO: Maybe theme separately? Maybe not.
|
||||
height: UM.Theme.getSize("default_lining").height;
|
||||
width: parent.width;
|
||||
}
|
251
plugins/UM3NetworkPrinting/resources/qml/MonitorCarousel.qml
Normal file
251
plugins/UM3NetworkPrinting/resources/qml/MonitorCarousel.qml
Normal file
|
@ -0,0 +1,251 @@
|
|||
// 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 QtGraphicalEffects 1.0
|
||||
import UM 1.3 as UM
|
||||
|
||||
Item
|
||||
{
|
||||
id: base
|
||||
|
||||
property var currentIndex: 0
|
||||
property var tileWidth: 834 * screenScaleFactor // TODO: Theme!
|
||||
property var tileHeight: 216 * screenScaleFactor // TODO: Theme!
|
||||
property var tileSpacing: 60 * screenScaleFactor // TODO: Theme!
|
||||
property var maxOffset: (OutputDevice.printers.length - 1) * (tileWidth + tileSpacing)
|
||||
|
||||
height: centerSection.height
|
||||
width: maximumWidth
|
||||
|
||||
Item
|
||||
{
|
||||
id: leftHint
|
||||
anchors
|
||||
{
|
||||
right: leftButton.left
|
||||
rightMargin: 12 * screenScaleFactor // TODO: Theme!
|
||||
left: parent.left
|
||||
}
|
||||
height: parent.height
|
||||
z: 10
|
||||
LinearGradient
|
||||
{
|
||||
anchors.fill: parent
|
||||
start: Qt.point(0, 0)
|
||||
end: Qt.point(leftHint.width, 0)
|
||||
gradient: Gradient
|
||||
{
|
||||
GradientStop
|
||||
{
|
||||
position: 0.0
|
||||
color: "#fff6f6f6" // TODO: Theme!
|
||||
}
|
||||
GradientStop
|
||||
{
|
||||
position: 1.0
|
||||
color: "#66f6f6f6" // TODO: Theme!
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseArea
|
||||
{
|
||||
anchors.fill: parent
|
||||
onClicked: navigateTo(currentIndex - 1)
|
||||
}
|
||||
}
|
||||
|
||||
Button
|
||||
{
|
||||
id: leftButton
|
||||
anchors
|
||||
{
|
||||
verticalCenter: parent.verticalCenter
|
||||
right: centerSection.left
|
||||
rightMargin: 12 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
width: 36 * screenScaleFactor // TODO: Theme!
|
||||
height: 72 * screenScaleFactor // TODO: Theme!
|
||||
visible: currentIndex > 0
|
||||
hoverEnabled: true
|
||||
z: 10
|
||||
onClicked: navigateTo(currentIndex - 1)
|
||||
background: Rectangle
|
||||
{
|
||||
color: leftButton.hovered ? "#e8f2fc" : "#ffffff" // TODO: Theme!
|
||||
border.width: 1 * screenScaleFactor // TODO: Theme!
|
||||
border.color: "#cccccc" // TODO: Theme!
|
||||
radius: 2 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
contentItem: Item
|
||||
{
|
||||
anchors.fill: parent
|
||||
UM.RecolorImage
|
||||
{
|
||||
anchors.centerIn: parent
|
||||
width: 18 // TODO: Theme!
|
||||
height: width // TODO: Theme!
|
||||
sourceSize.width: width // TODO: Theme!
|
||||
sourceSize.height: width // TODO: Theme!
|
||||
color: "#152950" // TODO: Theme!
|
||||
source: UM.Theme.getIcon("arrow_left")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item
|
||||
{
|
||||
id: centerSection
|
||||
anchors
|
||||
{
|
||||
verticalCenter: parent.verticalCenter
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
width: tileWidth
|
||||
height: tiles.height
|
||||
z: 1
|
||||
|
||||
Row
|
||||
{
|
||||
id: tiles
|
||||
height: childrenRect.height
|
||||
width: 5 * tileWidth + 4 * tileSpacing // TODO: Theme!
|
||||
x: 0
|
||||
z: 0
|
||||
Behavior on x
|
||||
{
|
||||
NumberAnimation
|
||||
{
|
||||
duration: 200
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
spacing: 60 * screenScaleFactor // TODO: Theme!
|
||||
|
||||
Repeater
|
||||
{
|
||||
model: OutputDevice.printers
|
||||
MonitorPrinterCard
|
||||
{
|
||||
printer: modelData
|
||||
enabled: model.index == currentIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button
|
||||
{
|
||||
id: rightButton
|
||||
anchors
|
||||
{
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: centerSection.right
|
||||
leftMargin: 12 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
width: 36 * screenScaleFactor // TODO: Theme!
|
||||
height: 72 * screenScaleFactor // TODO: Theme!
|
||||
z: 10
|
||||
visible: currentIndex < OutputDevice.printers.length - 1
|
||||
onClicked: navigateTo(currentIndex + 1)
|
||||
hoverEnabled: true
|
||||
background: Rectangle
|
||||
{
|
||||
color: rightButton.hovered ? "#e8f2fc" : "#ffffff" // TODO: Theme!
|
||||
border.width: 1 * screenScaleFactor // TODO: Theme!
|
||||
border.color: "#cccccc" // TODO: Theme!
|
||||
radius: 2 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
contentItem: Item
|
||||
{
|
||||
anchors.fill: parent
|
||||
UM.RecolorImage
|
||||
{
|
||||
anchors.centerIn: parent
|
||||
width: 18 // TODO: Theme!
|
||||
height: width // TODO: Theme!
|
||||
sourceSize.width: width // TODO: Theme!
|
||||
sourceSize.height: width // TODO: Theme!
|
||||
color: "#152950" // TODO: Theme!
|
||||
source: UM.Theme.getIcon("arrow_right")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item
|
||||
{
|
||||
id: rightHint
|
||||
anchors
|
||||
{
|
||||
left: rightButton.right
|
||||
leftMargin: 12 * screenScaleFactor // TODO: Theme!
|
||||
right: parent.right
|
||||
}
|
||||
height: centerSection.height
|
||||
z: 10
|
||||
|
||||
LinearGradient
|
||||
{
|
||||
anchors.fill: parent
|
||||
start: Qt.point(0, 0)
|
||||
end: Qt.point(rightHint.width, 0)
|
||||
gradient: Gradient
|
||||
{
|
||||
GradientStop
|
||||
{
|
||||
position: 0.0
|
||||
color: "#66f6f6f6" // TODO: Theme!
|
||||
}
|
||||
GradientStop
|
||||
{
|
||||
position: 1.0
|
||||
color: "#fff6f6f6" // TODO: Theme!
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseArea
|
||||
{
|
||||
anchors.fill: parent
|
||||
onClicked: navigateTo(currentIndex + 1)
|
||||
}
|
||||
}
|
||||
|
||||
Item
|
||||
{
|
||||
id: navigationDots
|
||||
anchors
|
||||
{
|
||||
horizontalCenter: centerSection.horizontalCenter
|
||||
top: centerSection.bottom
|
||||
topMargin: 36 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
Row
|
||||
{
|
||||
spacing: 8 * screenScaleFactor // TODO: Theme!
|
||||
Repeater
|
||||
{
|
||||
model: OutputDevice.printers
|
||||
Button
|
||||
{
|
||||
background: Rectangle
|
||||
{
|
||||
color: model.index == currentIndex ? "#777777" : "#d8d8d8" // TODO: Theme!
|
||||
radius: Math.floor(width / 2)
|
||||
width: 12 * screenScaleFactor // TODO: Theme!
|
||||
height: width // TODO: Theme!
|
||||
}
|
||||
onClicked: navigateTo(model.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function navigateTo( i ) {
|
||||
if (i >= 0 && i < OutputDevice.printers.length)
|
||||
{
|
||||
tiles.x = -1 * i * (tileWidth + tileSpacing)
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
// Copyright (c) 2018 Ultimaker B.V.
|
||||
// Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Dialogs 1.2
|
||||
import UM 1.3 as UM
|
||||
|
||||
UM.Dialog
|
||||
{
|
||||
id: overrideConfirmationDialog
|
||||
|
||||
property var printer: null
|
||||
|
||||
minimumWidth: screenScaleFactor * 640;
|
||||
minimumHeight: screenScaleFactor * 320;
|
||||
width: minimumWidth
|
||||
height: minimumHeight
|
||||
title: catalog.i18nc("@title:window", "Configuration Changes")
|
||||
rightButtons:
|
||||
[
|
||||
Button
|
||||
{
|
||||
id: overrideButton
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
text: catalog.i18nc("@action:button", "Override")
|
||||
onClicked:
|
||||
{
|
||||
OutputDevice.forceSendJob(printer.activePrintJob.key)
|
||||
overrideConfirmationDialog.close()
|
||||
}
|
||||
},
|
||||
Button
|
||||
{
|
||||
id: cancelButton
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
text: catalog.i18nc("@action:button", "Cancel")
|
||||
onClicked:
|
||||
{
|
||||
overrideConfirmationDialog.reject()
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Label
|
||||
{
|
||||
anchors
|
||||
{
|
||||
fill: parent
|
||||
margins: 36 * screenScaleFactor // TODO: Theme!
|
||||
bottomMargin: 56 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
wrapMode: Text.WordWrap
|
||||
text:
|
||||
{
|
||||
if (!printer.activePrintJob)
|
||||
{
|
||||
return ""
|
||||
}
|
||||
var topLine
|
||||
if (materialsAreKnown(printer.activePrintJob))
|
||||
{
|
||||
topLine = catalog.i18ncp("@label", "The assigned printer, %1, requires the following configuration change:", "The assigned printer, %1, requires the following configuration changes:", printer.activePrintJob.configurationChanges.length).arg(printer.name)
|
||||
}
|
||||
else
|
||||
{
|
||||
topLine = catalog.i18nc("@label", "The printer %1 is assigned, but the job contains an unknown material configuration.").arg(printer.name)
|
||||
}
|
||||
var result = "<p>" + topLine +"</p>\n\n"
|
||||
for (var i = 0; i < printer.activePrintJob.configurationChanges.length; i++)
|
||||
{
|
||||
var change = printer.activePrintJob.configurationChanges[i]
|
||||
var text
|
||||
switch (change.typeOfChange)
|
||||
{
|
||||
case "material_change":
|
||||
text = catalog.i18nc("@label", "Change material %1 from %2 to %3.").arg(change.index + 1).arg(change.originName).arg(change.targetName)
|
||||
break
|
||||
case "material_insert":
|
||||
text = catalog.i18nc("@label", "Load %3 as material %1 (This cannot be overridden).").arg(change.index + 1).arg(change.targetName)
|
||||
break
|
||||
case "print_core_change":
|
||||
text = catalog.i18nc("@label", "Change print core %1 from %2 to %3.").arg(change.index + 1).arg(change.originName).arg(change.targetName)
|
||||
break
|
||||
case "buildplate_change":
|
||||
text = catalog.i18nc("@label", "Change build plate to %1 (This cannot be overridden).").arg(formatBuildPlateType(change.target_name))
|
||||
break
|
||||
default:
|
||||
text = "unknown"
|
||||
}
|
||||
result += "<p><b>" + text + "</b></p>\n\n"
|
||||
}
|
||||
var bottomLine = catalog.i18nc("@label", "Override will use the specified settings with the existing printer configuration. This may result in a failed print.")
|
||||
result += "<p>" + bottomLine + "</p>\n\n"
|
||||
return result
|
||||
}
|
||||
}
|
||||
// Utils
|
||||
function formatPrintJobName(name)
|
||||
{
|
||||
var extensions = [ ".gcode.gz", ".gz", ".gcode", ".ufp" ]
|
||||
for (var i = 0; i < extensions.length; i++)
|
||||
{
|
||||
var extension = extensions[i]
|
||||
if (name.slice(-extension.length) === extension)
|
||||
{
|
||||
name = name.substring(0, name.length - extension.length)
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
function materialsAreKnown(job)
|
||||
{
|
||||
var conf0 = job.configuration[0]
|
||||
if (conf0 && !conf0.material.material)
|
||||
{
|
||||
return false
|
||||
}
|
||||
var conf1 = job.configuration[1]
|
||||
if (conf1 && !conf1.material.material)
|
||||
{
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
function formatBuildPlateType(buildPlateType)
|
||||
{
|
||||
var translationText = ""
|
||||
switch (buildPlateType) {
|
||||
case "glass":
|
||||
translationText = catalog.i18nc("@label", "Glass")
|
||||
break
|
||||
case "aluminum":
|
||||
translationText = catalog.i18nc("@label", "Aluminum")
|
||||
break
|
||||
default:
|
||||
translationText = null
|
||||
}
|
||||
return translationText
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ Item
|
|||
|
||||
ExpandableCard
|
||||
{
|
||||
borderColor: printJob.configurationChanges.length !== 0 ? "#f5a623" : "#CCCCCC" // TODO: Theme!
|
||||
headerItem: Row
|
||||
{
|
||||
height: 48 * screenScaleFactor // TODO: Theme!
|
||||
|
@ -96,6 +97,7 @@ Item
|
|||
return ""
|
||||
}
|
||||
visible: printJob
|
||||
width: 120 * screenScaleFactor // TODO: Theme!
|
||||
|
||||
// FIXED-LINE-HEIGHT:
|
||||
height: 18 * screenScaleFactor // TODO: Theme!
|
||||
|
|
|
@ -23,7 +23,7 @@ Item
|
|||
anchors.fill: parent
|
||||
opacity:
|
||||
{
|
||||
if (printJob && (printJob.state == "error" || !printJob.isActive))
|
||||
if (printJob && (printJob.state == "error" || printJob.configurationChanges.length > 0 || !printJob.isActive))
|
||||
{
|
||||
return 0.5
|
||||
}
|
||||
|
@ -60,6 +60,14 @@ Item
|
|||
height: 0.5 * printJobPreview.height
|
||||
source:
|
||||
{
|
||||
if (!printJob)
|
||||
{
|
||||
return ""
|
||||
}
|
||||
if (printJob.configurationChanges.length > 0)
|
||||
{
|
||||
return "../svg/warning-icon.svg"
|
||||
}
|
||||
switch(printJob.state)
|
||||
{
|
||||
case "error":
|
||||
|
@ -75,6 +83,7 @@ Item
|
|||
default:
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
sourceSize
|
||||
{
|
||||
|
|
|
@ -55,7 +55,7 @@ Item
|
|||
left: progressBar.right
|
||||
leftMargin: 18 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
text: Math.round(printJob.progress * 100) + "%"
|
||||
text: printJob ? Math.round(printJob.progress * 100) + "%" : "0%"
|
||||
color: printJob && printJob.isActive ? "#374355" : "#babac1" // TODO: Theme!
|
||||
width: contentWidth
|
||||
font: UM.Theme.getFont("medium") // 14pt, regular
|
||||
|
@ -88,6 +88,8 @@ Item
|
|||
return catalog.i18nc("@label:status", "Aborted")
|
||||
}
|
||||
return catalog.i18nc("@label:status", "Finished")
|
||||
case "finished":
|
||||
return catalog.i18nc("@label:status", "Finished")
|
||||
case "sent_to_printer":
|
||||
return catalog.i18nc("@label:status", "Preparing...")
|
||||
case "pre_print":
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Dialogs 1.1
|
||||
import UM 1.3 as UM
|
||||
|
||||
/**
|
||||
|
@ -24,8 +25,13 @@ Item
|
|||
|
||||
property var borderSize: 1 * screenScaleFactor // TODO: Theme, and remove from here
|
||||
|
||||
// If the printer card's controls are enabled. This is used by the carousel
|
||||
// to prevent opening the context menu or camera while the printer card is not
|
||||
// "in focus"
|
||||
property var enabled: true
|
||||
|
||||
width: 834 * screenScaleFactor // TODO: Theme!
|
||||
height: 216 * screenScaleFactor // TODO: Theme!
|
||||
height: childrenRect.height
|
||||
|
||||
// Printer portion
|
||||
Rectangle
|
||||
|
@ -33,7 +39,7 @@ Item
|
|||
id: printerInfo
|
||||
border
|
||||
{
|
||||
color: "#EAEAEC" // TODO: Theme!
|
||||
color: "#CCCCCC" // TODO: Theme!
|
||||
width: borderSize // TODO: Remove once themed
|
||||
}
|
||||
color: "white" // TODO: Theme!
|
||||
|
@ -66,7 +72,7 @@ Item
|
|||
{
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
width: 216 * screenScaleFactor // TODO: Theme!
|
||||
width: 180 * screenScaleFactor // TODO: Theme!
|
||||
height: printerNameLabel.height + printerFamilyPill.height + 6 * screenScaleFactor // TODO: Theme!
|
||||
|
||||
Label
|
||||
|
@ -123,6 +129,7 @@ Item
|
|||
printJob: printer.activePrintJob
|
||||
width: 36 * screenScaleFactor // TODO: Theme!
|
||||
height: 36 * screenScaleFactor // TODO: Theme!
|
||||
enabled: base.enabled
|
||||
}
|
||||
CameraButton
|
||||
{
|
||||
|
@ -135,6 +142,7 @@ Item
|
|||
bottomMargin: 20 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
iconSource: "../svg/icons/camera.svg"
|
||||
enabled: base.enabled
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,7 +158,7 @@ Item
|
|||
}
|
||||
border
|
||||
{
|
||||
color: "#EAEAEC" // TODO: Theme!
|
||||
color: printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 ? "#f5a623" : "#CCCCCC" // TODO: Theme!
|
||||
width: borderSize // TODO: Remove once themed
|
||||
}
|
||||
color: "white" // TODO: Theme!
|
||||
|
@ -185,14 +193,15 @@ Item
|
|||
}
|
||||
if (printer && printer.state == "unreachable")
|
||||
{
|
||||
return catalog.i18nc("@label:status", "Unreachable")
|
||||
return catalog.i18nc("@label:status", "Unavailable")
|
||||
}
|
||||
if (printer && printer.state == "idle")
|
||||
if (printer && !printer.activePrintJob && printer.state == "idle")
|
||||
{
|
||||
return catalog.i18nc("@label:status", "Idle")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
visible: text !== ""
|
||||
}
|
||||
|
||||
Item
|
||||
|
@ -218,7 +227,7 @@ Item
|
|||
{
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
width: 216 * screenScaleFactor // TODO: Theme!
|
||||
width: 180 * screenScaleFactor // TODO: Theme!
|
||||
height: printerNameLabel.height + printerFamilyPill.height + 6 * screenScaleFactor // TODO: Theme!
|
||||
visible: printer.activePrintJob
|
||||
|
||||
|
@ -247,7 +256,7 @@ Item
|
|||
}
|
||||
color: printer.activePrintJob && printer.activePrintJob.isActive ? "#53657d" : "#babac1" // TODO: Theme!
|
||||
elide: Text.ElideRight
|
||||
font: UM.Theme.getFont("very_small") // 12pt, regular
|
||||
font: UM.Theme.getFont("default") // 12pt, regular
|
||||
text: printer.activePrintJob ? printer.activePrintJob.owner : "Anonymous" // TODO: I18N
|
||||
width: parent.width
|
||||
|
||||
|
@ -264,8 +273,67 @@ Item
|
|||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
printJob: printer.activePrintJob
|
||||
visible: printer.activePrintJob
|
||||
visible: printer.activePrintJob && printer.activePrintJob.configurationChanges.length === 0
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
anchors
|
||||
{
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
font: UM.Theme.getFont("default")
|
||||
text: "Requires configuration changes"
|
||||
visible: printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0
|
||||
|
||||
// FIXED-LINE-HEIGHT:
|
||||
height: 18 * screenScaleFactor // TODO: Theme!
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
Button
|
||||
{
|
||||
id: detailsButton
|
||||
anchors
|
||||
{
|
||||
verticalCenter: parent.verticalCenter
|
||||
right: parent.right
|
||||
rightMargin: 18 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
background: Rectangle
|
||||
{
|
||||
color: "#d8d8d8" // TODO: Theme!
|
||||
radius: 2 * screenScaleFactor // Todo: Theme!
|
||||
Rectangle
|
||||
{
|
||||
anchors.fill: parent
|
||||
anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme!
|
||||
color: detailsButton.hovered ? "#e4e4e4" : "#f0f0f0" // TODO: Theme!
|
||||
radius: 2 * screenScaleFactor // Todo: Theme!
|
||||
}
|
||||
}
|
||||
contentItem: Label
|
||||
{
|
||||
anchors.fill: parent
|
||||
anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme!
|
||||
color: "#1e66d7" // TODO: Theme!
|
||||
font: UM.Theme.getFont("medium") // 14pt, regular
|
||||
text: "Details" // TODO: I18NC!
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
height: 18 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
implicitHeight: 32 * screenScaleFactor // TODO: Theme!
|
||||
implicitWidth: 96 * screenScaleFactor // TODO: Theme!
|
||||
visible: printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0
|
||||
onClicked: base.enabled ? overrideConfirmationDialog.open() : {}
|
||||
}
|
||||
}
|
||||
|
||||
MonitorConfigOverrideDialog
|
||||
{
|
||||
id: overrideConfirmationDialog
|
||||
printer: base.printer
|
||||
}
|
||||
}
|
|
@ -12,7 +12,19 @@ import UM 1.2 as UM
|
|||
Item
|
||||
{
|
||||
// The printer name
|
||||
property alias text: printerNameLabel.text;
|
||||
property var text: ""
|
||||
property var tagText: {
|
||||
switch(text) {
|
||||
case "Ultimaker 3":
|
||||
return "UM 3"
|
||||
case "Ultimaker 3 Extended":
|
||||
return "UM 3 EXT"
|
||||
case "Ultimaker S5":
|
||||
return "UM S5"
|
||||
default:
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
||||
implicitHeight: 18 * screenScaleFactor // TODO: Theme!
|
||||
implicitWidth: printerNameLabel.contentWidth + 12 // TODO: Theme!
|
||||
|
@ -28,7 +40,7 @@ Item
|
|||
id: printerNameLabel
|
||||
anchors.centerIn: parent
|
||||
color: "#535369" // TODO: Theme!
|
||||
text: ""
|
||||
text: tagText
|
||||
font.pointSize: 10
|
||||
}
|
||||
}
|
167
plugins/UM3NetworkPrinting/resources/qml/MonitorQueue.qml
Normal file
167
plugins/UM3NetworkPrinting/resources/qml/MonitorQueue.qml
Normal file
|
@ -0,0 +1,167 @@
|
|||
// 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.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.3 as UM
|
||||
import Cura 1.0 as Cura
|
||||
|
||||
/**
|
||||
* This component contains the print job queue, extracted from the primary
|
||||
* MonitorStage.qml file not for reusability but simply to keep it lean and more
|
||||
* readable.
|
||||
*/
|
||||
Item
|
||||
{
|
||||
Label
|
||||
{
|
||||
id: queuedLabel
|
||||
anchors
|
||||
{
|
||||
left: queuedPrintJobs.left
|
||||
top: parent.top
|
||||
}
|
||||
color: UM.Theme.getColor("text")
|
||||
font: UM.Theme.getFont("large_nonbold")
|
||||
text: catalog.i18nc("@label", "Queued")
|
||||
}
|
||||
|
||||
Item
|
||||
{
|
||||
id: manageQueueLabel
|
||||
anchors
|
||||
{
|
||||
right: queuedPrintJobs.right
|
||||
verticalCenter: queuedLabel.verticalCenter
|
||||
}
|
||||
height: 18 * screenScaleFactor // TODO: Theme!
|
||||
width: childrenRect.width
|
||||
|
||||
UM.RecolorImage
|
||||
{
|
||||
id: externalLinkIcon
|
||||
anchors.verticalCenter: manageQueueLabel.verticalCenter
|
||||
color: UM.Theme.getColor("primary")
|
||||
source: "../svg/icons/external_link.svg"
|
||||
width: 16 * screenScaleFactor // TODO: Theme! (Y U NO USE 18 LIKE ALL OTHER ICONS?!)
|
||||
height: 16 * screenScaleFactor // TODO: Theme! (Y U NO USE 18 LIKE ALL OTHER ICONS?!)
|
||||
}
|
||||
Label
|
||||
{
|
||||
id: manageQueueText
|
||||
anchors
|
||||
{
|
||||
left: externalLinkIcon.right
|
||||
leftMargin: 6 * screenScaleFactor // TODO: Theme!
|
||||
verticalCenter: externalLinkIcon.verticalCenter
|
||||
}
|
||||
color: UM.Theme.getColor("primary")
|
||||
font: UM.Theme.getFont("default") // 12pt, regular
|
||||
linkColor: UM.Theme.getColor("primary")
|
||||
text: catalog.i18nc("@label link to connect manager", "Manage queue in Cura Connect")
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea
|
||||
{
|
||||
anchors.fill: manageQueueLabel
|
||||
hoverEnabled: true
|
||||
onClicked: Cura.MachineManager.printerOutputDevices[0].openPrintJobControlPanel()
|
||||
onEntered:
|
||||
{
|
||||
manageQueueText.font.underline = true
|
||||
}
|
||||
onExited:
|
||||
{
|
||||
manageQueueText.font.underline = false
|
||||
}
|
||||
}
|
||||
|
||||
Row
|
||||
{
|
||||
id: printJobQueueHeadings
|
||||
anchors
|
||||
{
|
||||
left: queuedPrintJobs.left
|
||||
leftMargin: 6 * screenScaleFactor // TODO: Theme!
|
||||
top: queuedLabel.bottom
|
||||
topMargin: 24 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
spacing: 18 * screenScaleFactor // TODO: Theme!
|
||||
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@label", "Print jobs")
|
||||
color: "#666666"
|
||||
elide: Text.ElideRight
|
||||
font: UM.Theme.getFont("medium") // 14pt, regular
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 284 * screenScaleFactor // TODO: Theme! (Should match column size)
|
||||
|
||||
// FIXED-LINE-HEIGHT:
|
||||
height: 18 * screenScaleFactor // TODO: Theme!
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@label", "Total print time")
|
||||
color: "#666666"
|
||||
elide: Text.ElideRight
|
||||
font: UM.Theme.getFont("medium") // 14pt, regular
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 216 * screenScaleFactor // TODO: Theme! (Should match column size)
|
||||
|
||||
// FIXED-LINE-HEIGHT:
|
||||
height: 18 * screenScaleFactor // TODO: Theme!
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@label", "Waiting for")
|
||||
color: "#666666"
|
||||
elide: Text.ElideRight
|
||||
font: UM.Theme.getFont("medium") // 14pt, regular
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 216 * screenScaleFactor // TODO: Theme! (Should match column size)
|
||||
|
||||
// FIXED-LINE-HEIGHT:
|
||||
height: 18 * screenScaleFactor // TODO: Theme!
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView
|
||||
{
|
||||
id: queuedPrintJobs
|
||||
anchors
|
||||
{
|
||||
bottom: parent.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: printJobQueueHeadings.bottom
|
||||
topMargin: 12 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
style: UM.Theme.styles.scrollview
|
||||
visible: OutputDevice.receivedPrintJobs
|
||||
width: parent.width
|
||||
|
||||
ListView
|
||||
{
|
||||
id: printJobList
|
||||
anchors.fill: parent
|
||||
delegate: MonitorPrintJobCard
|
||||
{
|
||||
anchors
|
||||
{
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
printJob: modelData
|
||||
}
|
||||
model: OutputDevice.queuedPrintJobs
|
||||
spacing: 6 // TODO: Theme!
|
||||
}
|
||||
}
|
||||
}
|
85
plugins/UM3NetworkPrinting/resources/qml/MonitorStage.qml
Normal file
85
plugins/UM3NetworkPrinting/resources/qml/MonitorStage.qml
Normal file
|
@ -0,0 +1,85 @@
|
|||
// 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.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.3 as UM
|
||||
import Cura 1.0 as Cura
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
// This is the root component for the monitor stage.
|
||||
Component
|
||||
{
|
||||
Item
|
||||
{
|
||||
id: monitorFrame
|
||||
|
||||
height: maximumHeight
|
||||
onVisibleChanged:
|
||||
{
|
||||
if (monitorFrame != null && !monitorFrame.visible)
|
||||
{
|
||||
OutputDevice.setActiveCameraUrl("")
|
||||
}
|
||||
}
|
||||
width: maximumWidth
|
||||
|
||||
UM.I18nCatalog
|
||||
{
|
||||
id: catalog
|
||||
name: "cura"
|
||||
}
|
||||
|
||||
LinearGradient
|
||||
{
|
||||
anchors.fill: parent
|
||||
gradient: Gradient
|
||||
{
|
||||
GradientStop
|
||||
{
|
||||
position: 0.0
|
||||
color: "#f6f6f6" // TODO: Theme!
|
||||
}
|
||||
GradientStop
|
||||
{
|
||||
position: 1.0
|
||||
color: "#ffffff" // TODO: Theme!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item
|
||||
{
|
||||
id: printers
|
||||
anchors
|
||||
{
|
||||
top: parent.top
|
||||
topMargin: 48 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
width: parent.width
|
||||
height: 264 * screenScaleFactor // TODO: Theme!
|
||||
MonitorCarousel {}
|
||||
}
|
||||
|
||||
MonitorQueue
|
||||
{
|
||||
id: queue
|
||||
width: Math.min(834 * screenScaleFactor, maximumWidth)
|
||||
anchors
|
||||
{
|
||||
bottom: parent.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: printers.bottom
|
||||
topMargin: 48 * screenScaleFactor // TODO: Theme!
|
||||
}
|
||||
}
|
||||
|
||||
PrinterVideoStream
|
||||
{
|
||||
anchors.fill: parent
|
||||
cameraUrl: OutputDevice.activeCameraUrl
|
||||
visible: OutputDevice.activeCameraUrl != ""
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
// 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.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import UM 1.2 as UM
|
||||
|
||||
Item {
|
||||
id: extruderInfo;
|
||||
property var printCoreConfiguration: null;
|
||||
height: childrenRect.height;
|
||||
width: Math.round(parent.width / 2);
|
||||
|
||||
// Extruder circle
|
||||
Item {
|
||||
id: extruderCircle;
|
||||
height: UM.Theme.getSize("monitor_extruder_circle").height;
|
||||
width: UM.Theme.getSize("monitor_extruder_circle").width;
|
||||
|
||||
// Loading skeleton
|
||||
Rectangle {
|
||||
anchors.fill: parent;
|
||||
color: UM.Theme.getColor("monitor_skeleton_fill");
|
||||
radius: Math.round(width / 2);
|
||||
visible: !printCoreConfiguration;
|
||||
}
|
||||
|
||||
// Actual content
|
||||
Rectangle {
|
||||
anchors.fill: parent;
|
||||
border.width: UM.Theme.getSize("monitor_thick_lining").width;
|
||||
border.color: UM.Theme.getColor("monitor_lining_heavy");
|
||||
color: "transparent";
|
||||
opacity: {
|
||||
if (printCoreConfiguration == null || printCoreConfiguration.activeMaterial == null || printCoreConfiguration.hotendID == null) {
|
||||
return 0.5;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
radius: Math.round(width / 2);
|
||||
visible: printCoreConfiguration;
|
||||
|
||||
Label {
|
||||
anchors.centerIn: parent;
|
||||
color: UM.Theme.getColor("text");
|
||||
font: UM.Theme.getFont("default_bold");
|
||||
text: printCoreConfiguration ? printCoreConfiguration.position + 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print core and material labels
|
||||
Item {
|
||||
id: materialLabel
|
||||
anchors {
|
||||
left: extruderCircle.right;
|
||||
leftMargin: UM.Theme.getSize("default_margin").width;
|
||||
right: parent.right;
|
||||
top: parent.top;
|
||||
}
|
||||
height: UM.Theme.getSize("monitor_text_line").height;
|
||||
|
||||
// Loading skeleton
|
||||
Rectangle {
|
||||
anchors.fill: parent;
|
||||
color: UM.Theme.getColor("monitor_skeleton_fill");
|
||||
visible: !extruderInfo.printCoreConfiguration;
|
||||
}
|
||||
|
||||
// Actual content
|
||||
Label {
|
||||
anchors.fill: parent;
|
||||
elide: Text.ElideRight;
|
||||
color: UM.Theme.getColor("text");
|
||||
font: UM.Theme.getFont("default");
|
||||
text: {
|
||||
if (printCoreConfiguration && printCoreConfiguration.activeMaterial != undefined) {
|
||||
return printCoreConfiguration.activeMaterial.name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
visible: extruderInfo.printCoreConfiguration;
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: printCoreLabel;
|
||||
anchors {
|
||||
left: extruderCircle.right;
|
||||
leftMargin: UM.Theme.getSize("default_margin").width;
|
||||
right: parent.right;
|
||||
top: materialLabel.bottom;
|
||||
topMargin: Math.floor(UM.Theme.getSize("default_margin").height/4);
|
||||
}
|
||||
height: UM.Theme.getSize("monitor_text_line").height;
|
||||
|
||||
// Loading skeleton
|
||||
Rectangle {
|
||||
color: UM.Theme.getColor("monitor_skeleton_fill");
|
||||
height: parent.height;
|
||||
visible: !extruderInfo.printCoreConfiguration;
|
||||
width: Math.round(parent.width / 3);
|
||||
}
|
||||
|
||||
// Actual content
|
||||
Label {
|
||||
color: UM.Theme.getColor("text");
|
||||
elide: Text.ElideRight;
|
||||
font: UM.Theme.getFont("default");
|
||||
opacity: 0.6;
|
||||
text: {
|
||||
if (printCoreConfiguration != undefined && printCoreConfiguration.hotendID != undefined) {
|
||||
return printCoreConfiguration.hotendID;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
visible: extruderInfo.printCoreConfiguration;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ Item {
|
|||
property var printJob: null;
|
||||
property var started: isStarted(printJob);
|
||||
property var assigned: isAssigned(printJob);
|
||||
property var enabled: true
|
||||
|
||||
Button {
|
||||
id: button;
|
||||
|
@ -31,8 +32,8 @@ Item {
|
|||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
height: width;
|
||||
hoverEnabled: true;
|
||||
onClicked: parent.switchPopupState();
|
||||
hoverEnabled: base.enabled
|
||||
onClicked: base.enabled ? parent.switchPopupState() : {}
|
||||
text: "\u22EE"; //Unicode; Three stacked points.
|
||||
visible: {
|
||||
if (!printJob) {
|
||||
|
@ -182,7 +183,7 @@ Item {
|
|||
abortConfirmationDialog.visible = true;
|
||||
popup.close();
|
||||
}
|
||||
text: printJob.state == "aborting" ? catalog.i18nc("@label", "Aborting...") : catalog.i18nc("@label", "Abort");
|
||||
text: printJob && printJob.state == "aborting" ? catalog.i18nc("@label", "Aborting...") : catalog.i18nc("@label", "Abort");
|
||||
visible: {
|
||||
if (!printJob) {
|
||||
return false;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue