Merge pull request #1 from Ultimaker/master

update
This commit is contained in:
quillford 2015-07-03 11:43:10 -07:00
commit d7ef41d774
52 changed files with 11902 additions and 962 deletions

173
CHANGES Normal file
View File

@ -0,0 +1,173 @@
Cura 15.06 Beta
===============
This is the *Beta* version of Cura 15.06.
Cura 15.06 is a new release built from the ground up on a completely new
framework called Uranium. This framework has been designed to make it easier to
extend Cura with additional functionality as well as provide a cleaner UI.
Changes since 15.05.95
----------------------
* Fixed: Selection ghost remains visible after deleting an object
* Fixed: Window does not show up immediately after starting application on OSX
* Fixed: Added display of rotation angle during rotation
* Fixed: Object changes position while rotating/scaling
* Fixed: Loading improvements in the layer view
* Fixed: Added application icons
* Fixed: Improved feedback when loading models
* Fixed: Eject device on MacOSX now provides proper feedback
* Fixed: Make it possible to show retraction settings for UM2
* Fixed: Opening the machine preferences page will switch to the first available machine
* Fixed: Improved tool handle hit area size
* Fixed: Render lines with a thickness based on screen DPI
Changes since 15.05.94
----------------------
* Added Russian translations
* Fixed: Infill not displayed in layer view
* Fixed: Cannot select/scale/rotate when first activating the tool and then trying to select a model.
* Fixed: Improved font rendering on Windows
* Fixed: Help > Show Documentation crashes Cura on Windows
* Fixed: "There is no disk in the drive" repeating messages on Windows
* Fixed: Retraction settings not visible for Ultimaker2
* Fixed: Display rotation angle when rotating an object
* Fixed: Time/Quality slider values are properly rounded
* Fixed: Improved clarity of buttons and text
* Fixed: No indication that anything is happening when loading a model
* Fixed: Eject device now works on Windows
Changes since 15.05.93
----------------------
* Fixed: No shortcuts for moving up/down layers in layer view.
* Fixed: Last view layers could not be scrolled through in layer view.
* Fixed: Files provided on command line would not actually show up on the build
platform.
* Fixed: Render a ghost of the selection in Layer view to make the actual object
position clear.
* Fixed: Showing a menu would clear the selection.
* Fixed: Size and scaling factor display for scale tool.
* Fixed: Missing background for additional tool controls.
* Fixed: Loading message times out when loading large files.
* Fixed: Show recent files in the file menu.
* Fixed: Windows installer will now install MSVC 2010 redistributable, to
prevent issues with missing DLL's.
* Fixed: Collapsed/expanded state of setting categories not stored.
Changes since 15.05.91
----------------------
* There is now a working MacOSX version. Currently it supports OSX 10.7 and
higher.
* Fixed: Need to deselect before selecting a different object.
* Fixed: Object can be moved on Z axis.
* Fixed: Error values should be considered invalid values and will not trigger a
slice.
* Fixed: Text fields used a locale-aware validator while the underlying code did
not.
* Fixed: Text fields will trigger a slice on text change, not only after focus
change/enter press.
* Fixed: Rotate Tool snaps to incorrect value.
* Fixed: Object Collision would only moved objects to the right.
* Fixed: Object Collision would move the selected object when it should not.
* Fixed: Camera panning now works correctly instead of doing nothing.
* Fixed: Camera would flip around center point at maximum rotation.
* Fixed: Build platform grid blocked view from below objects.
* Fixed: Viewport on MacOSX with high-DPI screens was only taking 1/4th of the
window
Changes since 15.05.90
----------------------
* Fixed: Additional UI elements for tools and views not loading.
* Fixed: Double click needed to change setting dialog page.
* Fixed: Context menu entries (reload, center object, etc.) not working.
* Fixed: "Open With" or passing files from command line not working.
* Fixed: "Reload All" would not reload files.
In addition, a lot of work has gone into getting a usable Mac OSX version.
New Features
------------
* Plugin based system
The Uranium framework provides us with a plugin-based system
that provides additional flexibility when extending Cura. Think
of new views, tools, file formats, etc. This is probably the
biggest new feature.
* Improved UI
The UI has received a complete overhaul.
* Time-Quality Slider
The 4 static quick print profiles have been replaced with
a slider that should make it easier to find the right spot
between print time and print quality.
* More Settings
The Advanced mode is now configurable and can show many
additional settings that were previously not available, while at
the same time not overwhelming new users with too many settings.
Custom set of visible settings can be created by the user.
* Support for high-DPI screens
The refreshed UI has been designed with high-DPI screens in
mind which should improve the experience of Cura on such
devices.
* Improved language support
(Not yet available for the Beta release.)
* Improved support structure generation
The new version of the CuraEngine now features improved
support generation algorithms and additional options for support
structure generation.
* Experimental Feature: Wire Printing
Wire Printing has been added as an experimental new feature. It
will print objects as a structure of lines. It can be enabled by
from Advanced Mode -> Fixes -> Wire Printing.
* Undo/Redo
It is now possible to undo and redo most scene operations, like
moving or rotating objects.
Features from earlier versions not (yet) in this release
--------------------------------------------------------
* The All-at-once/One-at-a-time toggle is not available.
We are working on an improved implementation of this mechanism
but it will not be available for this release.
* No dual extrusion features are available yet.
We are working on a completely new workflow for this but this
needs additional time.
* “Lay Flat” has been removed.
The existing implementation was unfortunately not salvageable.
We will be looking into an improved implementation for this
feature.
* "Split Object Into Parts" has been removed.
Due to the same reason as Lay Flat.
* Support for AMF and DAE file formats has been removed.
Both of these will be implemented as plugins in the future.
* Support for directly loading a GCode file is not yet available.
This will be implemented as a plugin in the future.
* Support for PNG, JPG and other image formats has been removed.
These can be supported by a plugin with an improved UI.
* Support for loading Minecraft levels has been removed.
This can be implemented as a plugin.
* Windows XP support has been dropped.
Microsoft is no longer supporting xp, so they no longer back
port certain features that we require.
* X-Ray view is missing.
Will be implemented as a (you might have guessed it) plugin.
* Fixes: Follow Mesh Surface
Has been removed from the engine, the same result can be
achieved using no infill or top/bottom layers.
Known Issues
------------
For an up to date list of all known issues, please see
https://github.com/Ultimaker/Cura/issues and
https://github.com/Ultimaker/Uranium/issues .
* Some OBJ files are rendered as black objects due to missing
normals.
* Disabling plugins does not work correctly yet.
* Unicorn occasionally still requires feeding. Do not feed it
after midnight.

View File

@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 2.8.12)
set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY "The location of the scripts directory of the Uranium repository")
if(${URANIUM_SCRIPTS_DIR})
if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
# Extract Strings
add_custom_target(extract-messages ${URANIUM_SCRIPTS_DIR}/extract-messages ${CMAKE_SOURCE_DIR} cura)
@ -27,6 +27,12 @@ if(${URANIUM_SCRIPTS_DIR})
set(languages
en
x-test
ru
fr
de
it
es
fi
)
foreach(lang ${languages})
file(GLOB po_files resources/i18n/${lang}/*.po)
@ -55,7 +61,6 @@ find_package(PythonInterp 3.4.0 REQUIRED)
set(PYTHON_SITE_PACKAGES_DIR ${CMAKE_INSTALL_LIBDIR}/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages CACHE PATH "Install location of Python package")
install(DIRECTORY resources DESTINATION ${CMAKE_INSTALL_DATADIR}/cura)
install(DIRECTORY plugins DESTINATION ${CMAKE_INSTALL_LIBDIR}/cura)
file(GLOB cura_SRCS cura/*)
install(FILES ${cura_SRCS} DESTINATION ${PYTHON_SITE_PACKAGES_DIR}/cura)
install(DIRECTORY cura DESTINATION ${PYTHON_SITE_PACKAGES_DIR})
install(FILES cura_app.py DESTINATION ${CMAKE_INSTALL_BINDIR})

View File

@ -1,7 +1,9 @@
Cura
====
This is the source code of Cura.
This is the new, shiny, unreleased frontend for Cura. [daid/Cura](https://github.com/daid/Cura.git) is the old legacy Cura that everyone knows and loves/hates.
We re-worked the whole GUI code at Ultimaker, because my old code started to become an unmaintainable ball of poo.
Dependencies
------------
@ -12,3 +14,15 @@ Dependencies
This will be needed at runtime to perform the actual slicing.
* PySerial
Only required for USB printing support.
Configuring Cura
----------------
* link your CuraEngine backend by inserting the following line in home/.config/cura/config.cfg :
[backend]
location = /[path_to_the..]/CuraEngine/build/CuraEngine
Build scripts
-------------
Please checkout [cura-build](https://github.com/Ultimaker/cura-build)

View File

@ -42,6 +42,9 @@ class BuildVolume(SceneNode):
def setDepth(self, depth):
self._depth = depth
def getDisallowedAreas(self):
return self._disallowed_areas
def setDisallowedAreas(self, areas):
self._disallowed_areas = areas
@ -62,7 +65,7 @@ class BuildVolume(SceneNode):
self._grid_material.setUniformValue("u_gridColor1", Color(205, 202, 201, 255))
renderer.queueNode(self, material = self._material, mode = Renderer.RenderLines)
renderer.queueNode(self, mesh = self._grid_mesh, material = self._grid_material)
renderer.queueNode(self, mesh = self._grid_mesh, material = self._grid_material, force_single_sided = True)
if self._disallowed_area_mesh:
renderer.queueNode(self, mesh = self._disallowed_area_mesh, material = self._material)
return True
@ -99,29 +102,53 @@ class BuildVolume(SceneNode):
mb = MeshBuilder()
mb.addQuad(
Vector(minW, minH, maxD),
Vector(maxW, minH, maxD),
Vector(minW, minH, minD),
Vector(maxW, minH, minD),
Vector(minW, minH, minD)
Vector(maxW, minH, maxD),
Vector(minW, minH, maxD)
)
self._grid_mesh = mb.getData()
for n in range(0, 6):
v = self._grid_mesh.getVertex(n)
self._grid_mesh.setVertexUVCoordinates(n, v[0], v[2])
disallowed_area_size = 0
if self._disallowed_areas:
mb = MeshBuilder()
for area in self._disallowed_areas:
for polygon in self._disallowed_areas:
points = polygon.getPoints()
mb.addQuad(
area[0],
area[1],
area[2],
area[3],
Vector(points[0, 0], 0.1, points[0, 1]),
Vector(points[1, 0], 0.1, points[1, 1]),
Vector(points[2, 0], 0.1, points[2, 1]),
Vector(points[3, 0], 0.1, points[3, 1]),
color = Color(174, 174, 174, 255)
)
# Find the largest disallowed area to exclude it from the maximum scale bounds
size = abs(numpy.max(points[:, 1]) - numpy.min(points[:, 1]))
disallowed_area_size = max(size, disallowed_area_size)
self._disallowed_area_mesh = mb.getData()
else:
self._disallowed_area_mesh = None
self._aabb = AxisAlignedBox(minimum = Vector(minW, minH - 1.0, minD), maximum = Vector(maxW, maxH, maxD))
settings = Application.getInstance().getActiveMachine()
skirt_size = 0.0
if settings.getSettingValueByKey("adhesion_type") == "None":
skirt_size = settings.getSettingValueByKey("skirt_line_count") * settings.getSettingValueByKey("skirt_line_width") + settings.getSettingValueByKey("skirt_gap")
elif settings.getSettingValueByKey("adhesion_type") == "Brim":
skirt_size = settings.getSettingValueByKey("brim_line_count") * settings.getSettingValueByKey("skirt_line_width")
else:
skirt_size = settings.getSettingValueByKey("skirt_line_width")
skirt_size += settings.getSettingValueByKey("skirt_line_width")
scale_to_max_bounds = AxisAlignedBox(
minimum = Vector(minW + skirt_size, minH, minD + skirt_size + disallowed_area_size),
maximum = Vector(maxW - skirt_size, maxH, maxD - skirt_size - disallowed_area_size)
)
Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds

View File

@ -48,6 +48,9 @@ class ConvexHullNode(SceneNode):
self.setMeshData(mesh)
def getWatchedNode(self):
return self._node
def render(self, renderer):
if not self._material:
self._material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "color.frag"))

27
cura/CuraActions.py Normal file
View File

@ -0,0 +1,27 @@
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty, QUrl
from PyQt5.QtGui import QDesktopServices
from UM.Event import CallFunctionEvent
from UM.Application import Application
import webbrowser
class CuraActions(QObject):
def __init__(self, parent = None):
super().__init__(parent)
@pyqtSlot()
def openDocumentation(self):
# Starting a web browser from a signal handler connected to a menu will crash on windows.
# So instead, defer the call to the next run of the event loop, since that does work.
# Note that weirdly enough, only signal handlers that open a web browser fail like that.
event = CallFunctionEvent(self._openUrl, [QUrl("http://ultimaker.com/en/support/software")], {})
Application.getInstance().functionEvent(event)
@pyqtSlot()
def openBugReportPage(self):
event = CallFunctionEvent(self._openUrl, [QUrl("http://github.com/Ultimaker/Cura/issues")], {})
Application.getInstance().functionEvent(event)
def _openUrl(self, url):
QDesktopServices.openUrl(url)

View File

@ -17,6 +17,8 @@ from UM.Logger import Logger
from UM.Preferences import Preferences
from UM.Message import Message
from UM.PluginRegistry import PluginRegistry
from UM.JobQueue import JobQueue
from UM.Math.Polygon import Polygon
from UM.Scene.BoxRenderer import BoxRenderer
from UM.Scene.Selection import Selection
@ -32,9 +34,10 @@ from . import PlatformPhysics
from . import BuildVolume
from . import CameraAnimation
from . import PrintInformation
from . import CuraActions
from PyQt5.QtCore import pyqtSlot, QUrl, Qt, pyqtSignal, pyqtProperty
from PyQt5.QtGui import QColor
from PyQt5.QtGui import QColor, QIcon
import platform
import sys
@ -50,6 +53,8 @@ class CuraApplication(QtApplication):
super().__init__(name = "cura", version = "master")
self.setWindowIcon(QIcon(Resources.getPath(Resources.ImagesLocation, "cura-icon.png")))
self.setRequiredPlugins([
"CuraEngineBackend",
"MeshView",
@ -66,11 +71,24 @@ class CuraApplication(QtApplication):
self._output_devices = {}
self._print_information = None
self._i18n_catalog = None
self._previous_active_tool = None
self.activeMachineChanged.connect(self._onActiveMachineChanged)
Preferences.getInstance().addPreference("cura/active_machine", "")
Preferences.getInstance().addPreference("cura/active_mode", "simple")
Preferences.getInstance().addPreference("cura/recent_files", "")
Preferences.getInstance().addPreference("cura/categories_expanded", "")
JobQueue.getInstance().jobFinished.connect(self._onJobFinished)
self._recent_files = []
files = Preferences.getInstance().getValue("cura/recent_files").split(";")
for f in files:
if not os.path.isfile(f):
continue
self._recent_files.append(QUrl.fromLocalFile(f))
## Handle loading of all plugin types (and the backend explicitly)
# \sa PluginRegistery
@ -162,6 +180,7 @@ class CuraApplication(QtApplication):
for file in self.getCommandLineOption("file", []):
job = ReadMeshJob(os.path.abspath(file))
job.finished.connect(self._onFileLoaded)
job.start()
self.exec_()
@ -170,18 +189,27 @@ class CuraApplication(QtApplication):
engine.rootContext().setContextProperty("Printer", self)
self._print_information = PrintInformation.PrintInformation()
engine.rootContext().setContextProperty("PrintInformation", self._print_information)
self._cura_actions = CuraActions.CuraActions(self)
engine.rootContext().setContextProperty("CuraActions", self._cura_actions)
def onSelectionChanged(self):
if Selection.hasSelection():
if not self.getController().getActiveTool():
self.getController().setActiveTool("TranslateTool")
if self._previous_active_tool:
self.getController().setActiveTool(self._previous_active_tool)
self._previous_active_tool = None
else:
self.getController().setActiveTool("TranslateTool")
self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin())
self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition())
self._camera_animation.start()
else:
if self.getController().getActiveTool():
self._previous_active_tool = self.getController().getActiveTool().getPluginId()
self.getController().setActiveTool(None)
else:
self._previous_active_tool = None
requestAddPrinter = pyqtSignal()
@ -190,6 +218,9 @@ class CuraApplication(QtApplication):
def deleteObject(self, object_id):
object = self.getController().getScene().findObject(object_id)
if not object and object_id != 0: #Workaround for tool handles overlapping the selected object
object = Selection.getSelectedObject(0)
if object:
op = RemoveSceneNodeOperation(object)
op.push()
@ -199,6 +230,9 @@ class CuraApplication(QtApplication):
def multiplyObject(self, object_id, count):
node = self.getController().getScene().findObject(object_id)
if not node and object_id != 0: #Workaround for tool handles overlapping the selected object
node = Selection.getSelectedObject(0)
if node:
op = GroupedOperation()
for i in range(count):
@ -215,6 +249,9 @@ class CuraApplication(QtApplication):
def centerObject(self, object_id):
node = self.getController().getScene().findObject(object_id)
if not node and object_id != 0: #Workaround for tool handles overlapping the selected object
node = Selection.getSelectedObject(0)
if node:
op = SetTransformOperation(node, Vector())
op.push()
@ -304,6 +341,25 @@ class CuraApplication(QtApplication):
return log
recentFilesChanged = pyqtSignal()
@pyqtProperty("QVariantList", notify = recentFilesChanged)
def recentFiles(self):
return self._recent_files
@pyqtSlot("QStringList")
def setExpandedCategories(self, categories):
categories = list(set(categories))
categories.sort()
joined = ";".join(categories)
if joined != Preferences.getInstance().getValue("cura/categories_expanded"):
Preferences.getInstance().setValue("cura/categories_expanded", joined)
self.expandedCategoriesChanged.emit()
expandedCategoriesChanged = pyqtSignal()
@pyqtProperty("QStringList", notify = expandedCategoriesChanged)
def expandedCategories(self):
return Preferences.getInstance().getValue("cura/categories_expanded").split(";")
outputDevicesChanged = pyqtSignal()
@pyqtProperty("QVariantMap", notify = outputDevicesChanged)
@ -385,7 +441,7 @@ class CuraApplication(QtApplication):
self.addOutputDevice(drive, {
"id": drive,
"function": self._writeToSD,
"description": self._i18n_catalog.i18nc("Save button tooltip. {0} is sd card name", "Save to SD Card {0}".format(drive)),
"description": self._i18n_catalog.i18nc("Save button tooltip. {0} is sd card name", "Save to SD Card {0}").format(drive),
"icon": "save_sd",
"priority": 1
})
@ -411,21 +467,13 @@ class CuraApplication(QtApplication):
disallowed_areas = machine.getSettingValueByKey("machine_disallowed_areas")
areas = []
if disallowed_areas:
for area in disallowed_areas:
polygon = []
polygon.append(Vector(area[0][0], 0.2, area[0][1]))
polygon.append(Vector(area[1][0], 0.2, area[1][1]))
polygon.append(Vector(area[2][0], 0.2, area[2][1]))
polygon.append(Vector(area[3][0], 0.2, area[3][1]))
areas.append(polygon)
areas.append(Polygon(numpy.array(area, numpy.float32)))
self._volume.setDisallowedAreas(areas)
self._volume.rebuild()
if self.getController().getTool("ScaleTool"):
self.getController().getTool("ScaleTool").setMaximumBounds(self._volume.getBoundingBox())
offset = machine.getSettingValueByKey("machine_platform_offset")
if offset:
self._platform.setPosition(Vector(offset[0], offset[1], offset[2]))
@ -438,7 +486,7 @@ class CuraApplication(QtApplication):
"eject",
self._i18n_catalog.i18nc("Message action", "Eject"),
"eject",
self._i18n_catalog.i18nc("Message action tooltip, {0} is sdcard", "Eject SD Card {0}".format(job._sdcard))
self._i18n_catalog.i18nc("Message action tooltip, {0} is sdcard", "Eject SD Card {0}").format(job._sdcard)
)
message._sdcard = job._sdcard
message.actionTriggered.connect(self._onMessageActionTriggered)
@ -447,3 +495,34 @@ class CuraApplication(QtApplication):
def _onMessageActionTriggered(self, message, action):
if action == "eject":
self.getStorageDevice("LocalFileStorage").ejectRemovableDrive(message._sdcard)
def _onFileLoaded(self, job):
mesh = job.getResult()
if mesh != None:
node = SceneNode()
node.setSelectable(True)
node.setMeshData(mesh)
node.setName(os.path.basename(job.getFileName()))
op = AddSceneNodeOperation(node, self.getController().getScene().getRoot())
op.push()
def _onJobFinished(self, job):
if type(job) is not ReadMeshJob:
return
f = QUrl.fromLocalFile(job.getFileName())
if f in self._recent_files:
self._recent_files.remove(f)
self._recent_files.insert(0, f)
if len(self._recent_files) > 10:
del self._recent_files[10]
pref = ""
for path in self._recent_files:
pref += path.toLocalFile() + ";"
Preferences.getInstance().setValue("cura/recent_files", pref)
self.recentFilesChanged.emit()

View File

@ -11,6 +11,7 @@ from UM.Math.Float import Float
from UM.Math.Vector import Vector
from UM.Math.AxisAlignedBox import AxisAlignedBox
from UM.Application import Application
from UM.Scene.Selection import Selection
from . import PlatformPhysicsOperation
from . import ConvexHullJob
@ -23,8 +24,12 @@ class PlatformPhysics:
super().__init__()
self._controller = controller
self._controller.getScene().sceneChanged.connect(self._onSceneChanged)
self._controller.toolOperationStarted.connect(self._onToolOperationStarted)
self._controller.toolOperationStopped.connect(self._onToolOperationStopped)
self._build_volume = volume
self._enabled = True
self._change_timer = QTimer()
self._change_timer.setInterval(100)
self._change_timer.setSingleShot(True)
@ -34,6 +39,9 @@ class PlatformPhysics:
self._change_timer.start()
def _onChangeTimerFinished(self):
if not self._enabled:
return
root = self._controller.getScene().getRoot()
for node in BreadthFirstIterator(root):
if node is root or type(node) is not SceneNode:
@ -41,6 +49,7 @@ class PlatformPhysics:
bbox = node.getBoundingBox()
if not bbox or not bbox.isValid():
self._change_timer.start()
continue
# Mark the node as outside the build volume if the bounding box test fails.
@ -60,6 +69,8 @@ class PlatformPhysics:
job = ConvexHullJob.ConvexHullJob(node)
job.start()
node._convex_hull_job = job
elif Selection.isSelected(node):
pass
else:
# Check for collisions between convex hulls
for other_node in BreadthFirstIterator(root):
@ -80,13 +91,25 @@ class PlatformPhysics:
if overlap is None:
continue
move_vector.setX(-overlap[0])
move_vector.setZ(-overlap[1])
move_vector.setX(overlap[0] * 1.1)
move_vector.setZ(overlap[1] * 1.1)
if hasattr(node, "_convex_hull"):
# Check for collisions between disallowed areas and the object
for area in self._build_volume.getDisallowedAreas():
overlap = node._convex_hull.intersectsPolygon(area)
if overlap is None:
continue
node._outside_buildarea = True
if move_vector != Vector():
op = PlatformPhysicsOperation.PlatformPhysicsOperation(node, move_vector)
op.push()
if node.getBoundingBox().intersectsBox(self._build_volume.getBoundingBox()) == AxisAlignedBox.IntersectionResult.FullIntersection:
op = ScaleToBoundsOperation(node, self._build_volume.getBoundingBox())
op.push()
def _onToolOperationStarted(self, tool):
self._enabled = False
def _onToolOperationStopped(self, tool):
self._enabled = True
self._onChangeTimerFinished()

View File

@ -38,6 +38,8 @@ class PrintInformation(QObject):
def __init__(self, parent = None):
super().__init__(parent)
self._enabled = False
self._minimum_print_time = Duration(None, self)
self._current_print_time = Duration(None, self)
self._maximum_print_time = Duration(None, self)
@ -51,8 +53,8 @@ class PrintInformation(QObject):
self._time_quality_changed_timer.timeout.connect(self._updateTimeQualitySettings)
self._interpolation_settings = {
"layer_height": { "minimum": "low", "maximum": "high", "curve": "linear" },
"fill_sparse_density": { "minimum": "low", "maximum": "high", "curve": "linear" }
"layer_height": { "minimum": "low", "maximum": "high", "curve": "linear", "precision": 2 },
"fill_sparse_density": { "minimum": "low", "maximum": "high", "curve": "linear", "precision": 0 }
}
self._low_quality_settings = None
@ -103,6 +105,21 @@ class PrintInformation(QObject):
def timeQualityValue(self):
return self._time_quality_value
def setEnabled(self, enabled):
if enabled != self._enabled:
self._enabled = enabled
if self._enabled:
self._updateTimeQualitySettings()
self._onSlicingStarted()
self.enabledChanged.emit()
enabledChanged = pyqtSignal()
@pyqtProperty(bool, fset = setEnabled, notify = enabledChanged)
def enabled(self):
return self._enabled
@pyqtSlot(int)
def setTimeQualityValue(self, value):
if value != self._time_quality_value:
@ -132,7 +149,10 @@ class PrintInformation(QObject):
self._material_amount = round(amount / 10) / 100
self.materialAmountChanged.emit()
if self._slice_reason != self.SliceReason.SettingChanged:
if not self._enabled:
return
if self._slice_reason != self.SliceReason.SettingChanged or not self._minimum_print_time.valid or not self._maximum_print_time.valid:
self._slice_pass = self.SlicePass.LowQualitySettings
self._backend.slice(settings = self._low_quality_settings, save_gcode = False, save_polygons = False, force_restart = False, report_progress = False)
else:
@ -166,7 +186,7 @@ class PrintInformation(QObject):
self._slice_reason = self.SliceReason.ActiveMachineChanged
def _updateTimeQualitySettings(self):
if not self._current_settings:
if not self._current_settings or not self._enabled:
return
if not self._low_quality_settings:
@ -196,7 +216,7 @@ class PrintInformation(QObject):
else:
continue
setting_value = minimum_value + (maximum_value - minimum_value) * (self._time_quality_value / 100)
setting_value = round(minimum_value + (maximum_value - minimum_value) * (self._time_quality_value / 100), options["precision"])
self._current_settings.setSettingValueByKey(key, setting_value)
def _onSceneChanged(self, source):

0
cura_app.py Normal file → Executable file
View File

BIN
icons/cura-128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
icons/cura-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

BIN
icons/cura-48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
icons/cura-64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/cura.icns Normal file

Binary file not shown.

BIN
icons/cura.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -1,5 +1,5 @@
!ifndef VERSION
!define VERSION 'BETA'
!define VERSION '15.05.96'
!endif
; The name of the installer
@ -44,6 +44,9 @@ SetCompressor /SOLID lzma
!define MUI_FINISHPAGE_RUN_TEXT "Start Cura ${VERSION}"
!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink"
;Add an option to show release notes
!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\release_notes.txt"
; Pages
;!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
@ -89,7 +92,7 @@ Section "Cura ${VERSION}"
CreateDirectory "$SMPROGRAMS\Cura ${VERSION}"
CreateShortCut "$SMPROGRAMS\Cura ${VERSION}\Uninstall Cura ${VERSION}.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0
CreateShortCut "$SMPROGRAMS\Cura ${VERSION}\Cura ${VERSION}.lnk" "$INSTDIR\Cura.exe" '' "$INSTDIR\resources\cura.ico" 0
CreateShortCut "$SMPROGRAMS\Cura ${VERSION}\Cura ${VERSION}.lnk" "$INSTDIR\Cura.exe" '' "$INSTDIR\Cura.exe" 0
SectionEnd
@ -99,6 +102,15 @@ Function LaunchLink
Exec '"$WINDIR\explorer.exe" "$SMPROGRAMS\Cura ${VERSION}\Cura ${VERSION}.lnk"'
FunctionEnd
Section "Install Visual Studio 2010 Redistributable"
SetOutPath "$INSTDIR"
File "vcredist_2010_20110908_x86.exe"
IfSilent +2
ExecWait '"$INSTDIR\vcredist_2010_20110908_x86.exe" /q /norestart'
SectionEnd
;Section "Install Arduino Drivers"
; ; Set output path to the driver directory.
; SetOutPath "$INSTDIR\drivers\"

View File

@ -59,6 +59,8 @@ class CuraEngineBackend(Backend):
self._save_polygons = True
self._report_progress = True
self._enabled = True
self.backendConnected.connect(self._onBackendConnected)
def getEngineCommand(self):
@ -86,6 +88,9 @@ class CuraEngineBackend(Backend):
# If False, this method will do nothing when already slicing. True by default.
# - report_progress: True if the slicing progress should be reported, False if not. Default is True.
def slice(self, **kwargs):
if not self._enabled:
return
if self._slicing:
if not kwargs.get("force_restart", True):
return
@ -110,6 +115,9 @@ class CuraEngineBackend(Backend):
if not objects:
return #No point in slicing an empty build plate
if kwargs.get("settings", self._settings).hasErrorValue():
return #No slicing if we have error values since those are by definition illegal values.
self._slicing = True
self.slicingStarted.emit()
@ -232,3 +240,10 @@ class CuraEngineBackend(Backend):
if self._restart:
self._onChanged()
self._restart = False
def _onToolOperationStarted(self, tool):
self._enabled = False
def _onToolOperationStopped(self, tool):
self._enabled = True
self._onChanged()

View File

@ -1,6 +1,3 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: Cura.proto
@ -21,7 +18,7 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='Cura.proto',
package='Cura',
serialized_pb=_b('\n\nCura.proto\x12\x04\x43ura\"+\n\nObjectList\x12\x1d\n\x07objects\x18\x01 \x03(\x0b\x32\x0c.Cura.Object\"i\n\x06Object\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08vertices\x18\x02 \x01(\x0c\x12\x0f\n\x07normals\x18\x03 \x01(\x0c\x12\x0f\n\x07indices\x18\x04 \x01(\x0c\x12\x1f\n\x08settings\x18\x05 \x03(\x0b\x32\r.Cura.Setting\"\x1a\n\x08Progress\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x02\"7\n\x10SlicedObjectList\x12#\n\x07objects\x18\x01 \x03(\x0b\x32\x12.Cura.SlicedObject\"7\n\x0cSlicedObject\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x1b\n\x06layers\x18\x02 \x03(\x0b\x32\x0b.Cura.Layer\"4\n\x05Layer\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x1f\n\x08polygons\x18\x02 \x03(\x0b\x32\r.Cura.Polygon\"\x9f\x01\n\x07Polygon\x12 \n\x04type\x18\x01 \x01(\x0e\x32\x12.Cura.Polygon.Type\x12\x0e\n\x06points\x18\x02 \x01(\x0c\"b\n\x04Type\x12\x0c\n\x08NoneType\x10\x00\x12\x0e\n\nInset0Type\x10\x01\x12\x0e\n\nInsetXType\x10\x02\x12\x0c\n\x08SkinType\x10\x03\x12\x0f\n\x0bSupportType\x10\x04\x12\r\n\tSkirtType\x10\x05\"&\n\nGCodeLayer\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"D\n\x0fObjectPrintTime\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04time\x18\x02 \x01(\x02\x12\x17\n\x0fmaterial_amount\x18\x03 \x01(\x02\".\n\x0bSettingList\x12\x1f\n\x08settings\x18\x01 \x03(\x0b\x32\r.Cura.Setting\"&\n\x07Setting\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\"\x1b\n\x0bGCodePrefix\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x62\x06proto3')
serialized_pb=_b('\n\nCura.proto\x12\x04\x43ura\"+\n\nObjectList\x12\x1d\n\x07objects\x18\x01 \x03(\x0b\x32\x0c.Cura.Object\"i\n\x06Object\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08vertices\x18\x02 \x01(\x0c\x12\x0f\n\x07normals\x18\x03 \x01(\x0c\x12\x0f\n\x07indices\x18\x04 \x01(\x0c\x12\x1f\n\x08settings\x18\x05 \x03(\x0b\x32\r.Cura.Setting\"\x1a\n\x08Progress\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x02\"7\n\x10SlicedObjectList\x12#\n\x07objects\x18\x01 \x03(\x0b\x32\x12.Cura.SlicedObject\"7\n\x0cSlicedObject\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x1b\n\x06layers\x18\x02 \x03(\x0b\x32\x0b.Cura.Layer\"W\n\x05Layer\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0e\n\x06height\x18\x02 \x01(\x02\x12\x11\n\tthickness\x18\x03 \x01(\x02\x12\x1f\n\x08polygons\x18\x04 \x03(\x0b\x32\r.Cura.Polygon\"\xdb\x01\n\x07Polygon\x12 \n\x04type\x18\x01 \x01(\x0e\x32\x12.Cura.Polygon.Type\x12\x0e\n\x06points\x18\x02 \x01(\x0c\x12\x12\n\nline_width\x18\x03 \x01(\x02\"\x89\x01\n\x04Type\x12\x0c\n\x08NoneType\x10\x00\x12\x0e\n\nInset0Type\x10\x01\x12\x0e\n\nInsetXType\x10\x02\x12\x0c\n\x08SkinType\x10\x03\x12\x0f\n\x0bSupportType\x10\x04\x12\r\n\tSkirtType\x10\x05\x12\x0e\n\nInfillType\x10\x06\x12\x15\n\x11SupportInfillType\x10\x07\"&\n\nGCodeLayer\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"D\n\x0fObjectPrintTime\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04time\x18\x02 \x01(\x02\x12\x17\n\x0fmaterial_amount\x18\x03 \x01(\x02\".\n\x0bSettingList\x12\x1f\n\x08settings\x18\x01 \x03(\x0b\x32\r.Cura.Setting\"&\n\x07Setting\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\"\x1b\n\x0bGCodePrefix\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x62\x06proto3')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
@ -57,11 +54,19 @@ _POLYGON_TYPE = _descriptor.EnumDescriptor(
name='SkirtType', index=5, number=5,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='InfillType', index=6, number=6,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='SupportInfillType', index=7, number=7,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=430,
serialized_end=528,
serialized_start=486,
serialized_end=623,
)
_sym_db.RegisterEnumDescriptor(_POLYGON_TYPE)
@ -266,8 +271,22 @@ _LAYER = _descriptor.Descriptor(
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='polygons', full_name='Cura.Layer.polygons', index=1,
number=2, type=11, cpp_type=10, label=3,
name='height', full_name='Cura.Layer.height', index=1,
number=2, type=2, cpp_type=6, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='thickness', full_name='Cura.Layer.thickness', index=2,
number=3, type=2, cpp_type=6, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='polygons', full_name='Cura.Layer.polygons', index=3,
number=4, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
@ -284,7 +303,7 @@ _LAYER = _descriptor.Descriptor(
oneofs=[
],
serialized_start=314,
serialized_end=366,
serialized_end=401,
)
@ -309,6 +328,13 @@ _POLYGON = _descriptor.Descriptor(
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='line_width', full_name='Cura.Polygon.line_width', index=2,
number=3, type=2, cpp_type=6, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
@ -321,8 +347,8 @@ _POLYGON = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=369,
serialized_end=528,
serialized_start=404,
serialized_end=623,
)
@ -358,8 +384,8 @@ _GCODELAYER = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=530,
serialized_end=568,
serialized_start=625,
serialized_end=663,
)
@ -402,8 +428,8 @@ _OBJECTPRINTTIME = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=570,
serialized_end=638,
serialized_start=665,
serialized_end=733,
)
@ -432,8 +458,8 @@ _SETTINGLIST = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=640,
serialized_end=686,
serialized_start=735,
serialized_end=781,
)
@ -469,8 +495,8 @@ _SETTING = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=688,
serialized_end=726,
serialized_start=783,
serialized_end=821,
)
@ -499,8 +525,8 @@ _GCODEPREFIX = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=728,
serialized_end=755,
serialized_start=823,
serialized_end=850,
)
_OBJECTLIST.fields_by_name['objects'].message_type = _OBJECT

View File

@ -2,10 +2,13 @@
# Cura is released under the terms of the AGPLv3 or higher.
from UM.Mesh.MeshData import MeshData
from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Math.Color import Color
from UM.Math.Vector import Vector
import numpy
import math
import copy
class LayerData(MeshData):
def __init__(self):
@ -13,12 +16,19 @@ class LayerData(MeshData):
self._layers = {}
self._element_counts = {}
def addPolygon(self, layer, type, data):
def addLayer(self, layer):
if layer not in self._layers:
self._layers[layer] = []
self._layers[layer] = Layer(layer)
p = Polygon(self, type, data)
self._layers[layer].append(p)
def addPolygon(self, layer, type, data, line_width):
if layer not in self._layers:
self.addLayer(layer)
p = Polygon(self, type, data, line_width)
self._layers[layer].polygons.append(p)
def getLayer(self, layer):
return self._layers[layer]
def getLayers(self):
return self._layers
@ -26,14 +36,134 @@ class LayerData(MeshData):
def getElementCounts(self):
return self._element_counts
def build(self):
for layer, data in self._layers.items():
if layer not in self._element_counts:
self._element_counts[layer] = []
def setLayerHeight(self, layer, height):
if layer not in self._layers:
self.addLayer(layer)
for polygon in data:
polygon.build()
self._element_counts[layer].append(polygon.elementCount)
self._layers[layer].setHeight(height)
def setLayerThickness(self, layer, thickness):
if layer not in self._layers:
self.addLayer(layer)
self._layers[layer].setThickness(thickness)
def build(self):
vertex_count = 0
for layer, data in self._layers.items():
vertex_count += data.vertexCount()
vertices = numpy.empty((vertex_count, 3), numpy.float32)
colors = numpy.empty((vertex_count, 4), numpy.float32)
indices = numpy.empty((vertex_count, 2), numpy.int32)
offset = 0
for layer, data in self._layers.items():
offset = data.build(offset, vertices, colors, indices)
self._element_counts[layer] = data.elementCount
self.addVertices(vertices)
self.addColors(colors)
self.addIndices(indices.flatten())
class Layer():
def __init__(self, id):
self._id = id
self._height = 0.0
self._thickness = 0.0
self._polygons = []
self._element_count = 0
@property
def height(self):
return self._height
@property
def thickness(self):
return self._thickness
@property
def polygons(self):
return self._polygons
@property
def elementCount(self):
return self._element_count
def setHeight(self, height):
self._height = height
def setThickness(self, thickness):
self._thickness = thickness
def vertexCount(self):
result = 0
for polygon in self._polygons:
result += polygon.vertexCount()
return result
def build(self, offset, vertices, colors, indices):
result = offset
for polygon in self._polygons:
if polygon._type == Polygon.InfillType or polygon._type == Polygon.SupportInfillType:
continue
polygon.build(result, vertices, colors, indices)
result += polygon.vertexCount()
self._element_count += polygon.elementCount
return result
def createMesh(self):
builder = MeshBuilder()
for polygon in self._polygons:
poly_color = polygon.getColor()
points = numpy.copy(polygon.data)
if polygon.type == Polygon.InfillType or polygon.type == Polygon.SkinType or polygon.type == Polygon.SupportInfillType:
points[:,1] -= 0.01
# Calculate normals for the entire polygon using numpy.
normals = numpy.copy(points)
normals[:,1] = 0.0 # We are only interested in 2D normals
# Calculate the edges between points.
# The call to numpy.roll shifts the entire array by one so that
# we end up subtracting each next point from the current, wrapping
# around. This gives us the edges from the next point to the current
# point.
normals[:] = normals[:] - numpy.roll(normals, -1, axis = 0)
# Calculate the length of each edge using standard Pythagoras
lengths = numpy.sqrt(normals[:,0] ** 2 + normals[:,2] ** 2)
# The normal of a 2D vector is equal to its x and y coordinates swapped
# and then x inverted. This code does that.
normals[:,[0, 2]] = normals[:,[2, 0]]
normals[:,0] *= -1
# Normalize the normals.
normals[:,0] /= lengths
normals[:,2] /= lengths
# Scale all by the line width of the polygon so we can easily offset.
normals *= (polygon.lineWidth / 2)
#TODO: Use numpy magic to perform the vertex creation to speed up things.
for i in range(len(points)):
start = points[i - 1]
end = points[i]
normal = normals[i - 1]
point1 = Vector(data = start - normal)
point2 = Vector(data = start + normal)
point3 = Vector(data = end + normal)
point4 = Vector(data = end - normal)
builder.addQuad(point1, point2, point3, point4, color = poly_color)
return builder.getData()
class Polygon():
NoneType = 0
@ -42,43 +172,58 @@ class Polygon():
SkinType = 3
SupportType = 4
SkirtType = 5
InfillType = 6
SupportInfillType = 7
def __init__(self, mesh, type, data):
def __init__(self, mesh, type, data, line_width):
super().__init__()
self._mesh = mesh
self._type = type
self._data = data
self._line_width = line_width / 1000
def build(self, offset, vertices, colors, indices):
self._begin = offset
color = self.getColor()
color.setValues(color.r * 0.5, color.g * 0.5, color.b * 0.5, color.a)
for i in range(len(self._data)):
vertices[offset + i, :] = self._data[i, :]
colors[offset + i, 0] = color.r
colors[offset + i, 1] = color.g
colors[offset + i, 2] = color.b
colors[offset + i, 3] = color.a
def build(self):
self._begin = self._mesh._vertex_count
self._mesh.addVertices(self._data)
self._end = self._begin + len(self._data) - 1
color = None
if self._type == self.Inset0Type:
color = [1, 0, 0, 1]
elif self._type == self.InsetXType:
color = [0, 1, 0, 1]
elif self._type == self.SkinType:
color = [1, 1, 0, 1]
elif self._type == self.SupportType:
color = [0, 1, 1, 1]
elif self._type == self.SkirtType:
color = [0, 1, 1, 1]
else:
color = [1, 1, 1, 1]
colors = [color for i in range(len(self._data))]
self._mesh.addColors(numpy.array(colors, dtype=numpy.float32))
indices = []
for i in range(self._begin, self._end):
indices.append(i)
indices.append(i + 1)
indices[i, 0] = i
indices[i, 1] = i + 1
indices.append(self._end)
indices.append(self._begin)
self._mesh.addIndices(numpy.array(indices, dtype=numpy.int32))
indices[self._end, 0] = self._end
indices[self._end, 1] = self._begin
def getColor(self):
if self._type == self.Inset0Type:
return Color(1.0, 0.0, 0.0, 1.0)
elif self._type == self.InsetXType:
return Color(0.0, 1.0, 0.0, 1.0)
elif self._type == self.SkinType:
return Color(1.0, 1.0, 0.0, 1.0)
elif self._type == self.SupportType:
return Color(0.0, 1.0, 1.0, 1.0)
elif self._type == self.SkirtType:
return Color(0.0, 1.0, 1.0, 1.0)
elif self._type == self.InfillType:
return Color(1.0, 1.0, 0.0, 1.0)
elif self._type == self.SupportInfillType:
return Color(0.0, 1.0, 1.0, 1.0)
else:
return Color(1.0, 1.0, 1.0, 1.0)
def vertexCount(self):
return len(self._data)
@property
def type(self):
@ -90,4 +235,8 @@ class Polygon():
@property
def elementCount(self):
return (self._end - self._begin) * 2 #The range of vertices multiplied by 2 since each vertex is used twice
return ((self._end - self._begin) + 1) * 2 #The range of vertices multiplied by 2 since each vertex is used twice
@property
def lineWidth(self):
return self._line_width

View File

@ -7,18 +7,30 @@ from UM.Scene.SceneNode import SceneNode
from UM.Application import Application
from UM.Mesh.MeshData import MeshData
from UM.Message import Message
from UM.i18n import i18nCatalog
from . import LayerData
import numpy
import struct
catalog = i18nCatalog("cura")
class ProcessSlicedObjectListJob(Job):
def __init__(self, message):
super().__init__()
self._message = message
self._scene = Application.getInstance().getController().getScene()
self._progress = None
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
def run(self):
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
self._progress = Message(catalog.i18nc("Layers View mode", "Layers"), 0, False, 0)
self._progress.show()
objectIdMap = {}
new_node = SceneNode()
## Put all nodes in a dict identified by ID
@ -32,39 +44,67 @@ class ProcessSlicedObjectListJob(Job):
settings = Application.getInstance().getActiveMachine()
layerHeight = settings.getSettingValueByKey("layer_height")
center = None
if not settings.getSettingValueByKey("machine_center_is_zero"):
center = numpy.array([settings.getSettingValueByKey("machine_width") / 2, 0.0, -settings.getSettingValueByKey("machine_depth") / 2])
else:
center = numpy.array([0.0, 0.0, 0.0])
if self._progress:
self._progress.setProgress(2)
mesh = MeshData()
for object in self._message.objects:
try:
try:
node = objectIdMap[object.id]
except KeyError:
continue
mesh = MeshData()
layerData = LayerData.LayerData()
for layer in object.layers:
layerData.addLayer(layer.id)
layerData.setLayerHeight(layer.id, layer.height)
layerData.setLayerThickness(layer.id, layer.thickness)
for polygon in layer.polygons:
points = numpy.fromstring(polygon.points, dtype="i8") # Convert bytearray to numpy array
points = points.reshape((-1,2)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly.
points = numpy.asarray(points, dtype=numpy.float32)
points /= 1000
points = numpy.insert(points, 1, layer.id * layerHeight, axis = 1)
points = numpy.insert(points, 1, (layer.height / 1000), axis = 1)
points[:,2] *= -1
if not settings.getSettingValueByKey("machine_center_is_zero"):
center = [settings.getSettingValueByKey("machine_width") / 2, 0.0, -settings.getSettingValueByKey("machine_depth") / 2]
points -= numpy.array(center)
points -= numpy.array(center)
#points = numpy.pad(points, ((0,0), (0,1)), "constant", constant_values=(0.0, 1.0))
#inverse = node.getWorldTransformation().getInverse().getData()
#points = points.dot(inverse)
#points = points[:,0:3]
layerData.addPolygon(layer.id, polygon.type, points, polygon.line_width)
layerData.addPolygon(layer.id, polygon.type, points)
if self._progress:
self._progress.setProgress(50)
# We are done processing all the layers we got from the engine, now create a mesh out of the data
layerData.build()
mesh.layerData = layerData
if self._progress:
self._progress.setProgress(100)
# We are done processing all the layers we got from the engine, now create a mesh out of the data
layerData.build()
mesh.layerData = layerData
new_node.setMeshData(mesh)
new_node.setParent(self._scene.getRoot())
view = Application.getInstance().getController().getActiveView()
if view.getPluginId() == "LayerView":
view.resetLayerData()
if self._progress:
self._progress.hide()
def _onActiveViewChanged(self):
if self.isRunning():
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
if not self._progress:
self._progress = Message(catalog.i18nc("Layers View mode", "Layers"), 0, False, 0)
self._progress.show()
else:
if self._progress:
self._progress.hide()

View File

@ -5,6 +5,15 @@ from UM.View.View import View
from UM.View.Renderer import Renderer
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Resources import Resources
from UM.Event import Event, KeyEvent
from UM.Signal import Signal
from UM.Scene.Selection import Selection
from UM.Math.Color import Color
from UM.Mesh.MeshData import MeshData
from cura.ConvexHullNode import ConvexHullNode
from . import LayerViewProxy
## View used to display g-code paths.
class LayerView(View):
@ -13,6 +22,25 @@ class LayerView(View):
self._material = None
self._num_layers = 0
self._layer_percentage = 0 # what percentage of layers need to be shown (SLider gives value between 0 - 100)
self._proxy = LayerViewProxy.LayerViewProxy()
self._controller.getScene().sceneChanged.connect(self._onSceneChanged)
self._max_layers = 10
self._current_layer_num = 10
self._current_layer_mesh = None
self._solid_layers = 5
def getCurrentLayer(self):
return self._current_layer_num
def _onSceneChanged(self, node):
self.calculateMaxLayers()
def getMaxLayers(self):
return self._max_layers
def resetLayerData(self):
self._current_layer_mesh = None
def beginRendering(self):
scene = self.getController().getScene()
@ -23,32 +51,110 @@ class LayerView(View):
self._material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "vertexcolor.frag"))
self._material.setUniformValue("u_color", [1.0, 0.0, 0.0, 1.0])
self._selection_material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "color.frag"))
self._selection_material.setUniformValue("u_color", Color(35, 35, 35, 128))
for node in DepthFirstIterator(scene.getRoot()):
# We do not want to render ConvexHullNode as it conflicts with the bottom layers.
# However, it is somewhat relevant when the node is selected, so do render it then.
if type(node) is ConvexHullNode and not Selection.isSelected(node.getWatchedNode()):
continue
if not node.render(renderer):
if node.getMeshData() and node.isVisible():
if Selection.isSelected(node):
renderer.queueNode(node, material = self._selection_material, transparent = True)
try:
layer_data = node.getMeshData().layerData
except AttributeError:
continue
if self._layer_percentage < 100:
# Render all layers below a certain number as line mesh instead of vertices.
if self._current_layer_num - self._solid_layers > -1:
start = 0
end_layer = round(len(layer_data.getLayers()) * (self._layer_percentage / 100))
end = 0
element_counts = layer_data.getElementCounts()
for layer, counts in element_counts.items():
end += sum(counts)
if layer >= end_layer:
if layer + self._solid_layers > self._current_layer_num:
break
end += counts
# This uses glDrawRangeElements internally to only draw a certain range of lines.
renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines, start = start, end = end)
else:
renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines)
# We currently recreate the current "solid" layers every time a
if not self._current_layer_mesh:
self._current_layer_mesh = MeshData()
for i in range(self._solid_layers):
layer = self._current_layer_num - i
if layer < 0:
continue
layer_mesh = layer_data.getLayer(layer).createMesh()
if not layer_mesh or layer_mesh.getVertices() is None:
continue
self._current_layer_mesh.addVertices(layer_mesh.getVertices())
# Scale layer color by a brightness factor based on the current layer number
# This will result in a range of 0.5 - 1.0 to multiply colors by.
brightness = (2.0 - (i / self._solid_layers)) / 2.0
self._current_layer_mesh.addColors(layer_mesh.getColors() * brightness)
renderer.queueNode(node, mesh = self._current_layer_mesh, material = self._material)
def setLayer(self, value):
self._layer_percentage = value
if self._current_layer_num != value:
self._current_layer_num = value
if self._current_layer_num < 0:
self._current_layer_num = 0
if self._current_layer_num > self._max_layers:
self._current_layer_num = self._max_layers
self._current_layer_mesh = None
self.currentLayerNumChanged.emit()
currentLayerNumChanged = Signal()
def calculateMaxLayers(self):
scene = self.getController().getScene()
renderer = self.getRenderer()
if renderer and self._material:
renderer.setRenderSelection(False)
self._old_max_layers = self._max_layers
## Recalculate num max layers
new_max_layers = 0
for node in DepthFirstIterator(scene.getRoot()):
if not node.render(renderer):
if node.getMeshData() and node.isVisible():
try:
layer_data = node.getMeshData().layerData
except AttributeError:
continue
if new_max_layers < len(layer_data.getLayers()):
new_max_layers = len(layer_data.getLayers()) - 1
if new_max_layers > 0 and new_max_layers != self._old_max_layers:
self._max_layers = new_max_layers
self.maxLayersChanged.emit()
# This makes sure we update the current layer
self.setLayer(int(self._max_layers * (self._current_layer_num / self._old_max_layers)))
maxLayersChanged = Signal()
## Hackish way to ensure the proxy is already created, which ensures that the layerview.qml is already created
# as this caused some issues.
def getProxy(self, engine, script_engine):
return self._proxy
def endRendering(self):
pass
def event(self, event):
if event.type == Event.KeyPressEvent:
if event.key == KeyEvent.UpKey:
self.setLayer(self._current_layer_num + 1)
if event.key == KeyEvent.DownKey:
self.setLayer(self._current_layer_num - 1)

View File

@ -20,10 +20,11 @@ Item
anchors.right : parent.right
orientation: Qt.Vertical
minimumValue: 0;
maximumValue: 100;
maximumValue: UM.LayerView.numLayers;
stepSize: 1
value: 100;
onValueChanged: UM.ActiveView.triggerAction("setLayer", value)
value: UM.LayerView.currentLayer
onValueChanged: UM.LayerView.setCurrentLayer(value)
style: UM.Theme.styles.slider;
}

View File

@ -0,0 +1,44 @@
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty
from UM.Application import Application
import LayerView
class LayerViewProxy(QObject):
def __init__(self, parent = None):
super().__init__(parent)
self._current_layer = 0
self._controller = Application.getInstance().getController()
self._controller.activeViewChanged.connect(self._onActiveViewChanged)
self._onActiveViewChanged()
currentLayerChanged = pyqtSignal()
maxLayersChanged = pyqtSignal()
@pyqtProperty(int, notify = maxLayersChanged)
def numLayers(self):
active_view = self._controller.getActiveView()
#print("num max layers " , active_view.getMaxLayers())
return active_view.getMaxLayers()
#return 100
@pyqtProperty(int, notify = currentLayerChanged)
def currentLayer(self):
active_view = self._controller.getActiveView()
if type(active_view) == LayerView.LayerView.LayerView:
return active_view.getCurrentLayer()
@pyqtSlot(int)
def setCurrentLayer(self, layer_num):
active_view = self._controller.getActiveView()
if type(active_view) == LayerView.LayerView.LayerView:
active_view.setLayer(layer_num)
def _onLayerChanged(self):
self.currentLayerChanged.emit()
def _onMaxLayersChanged(self):
self.maxLayersChanged.emit()
def _onActiveViewChanged(self):
active_view = self._controller.getActiveView()
if type(active_view) == LayerView.LayerView.LayerView:
active_view.currentLayerNumChanged.connect(self._onLayerChanged)
active_view.maxLayersChanged.connect(self._onMaxLayersChanged)

View File

@ -1,7 +1,8 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from . import LayerView
from . import LayerView, LayerViewProxy
from PyQt5.QtQml import qmlRegisterType, qmlRegisterSingletonType
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
@ -21,6 +22,10 @@ def getMetaData():
}
}
def createLayerViewProxy(engine, script_engine):
return LayerViewProxy.LayerViewProxy()
def register(app):
layer_view = LayerView.LayerView()
qmlRegisterSingletonType(LayerViewProxy.LayerViewProxy, "UM", 1, 0, "LayerView", layer_view.getProxy)
return { "view": LayerView.LayerView() }

View File

@ -173,6 +173,10 @@ class PrinterConnection(SignalEmitter):
Logger.log("i", "Could not establish connection on %s: %s. Device is not arduino based." %(self._serial_port,str(e)))
except Exception as e:
Logger.log("i", "Could not establish connection on %s, unknown reasons. Device is not arduino based." % self._serial_port)
if not self._serial or not programmer.serial:
self._is_connecting = False
return
# If the programmer connected, we know its an atmega based version. Not all that usefull, but it does give some debugging information.
for baud_rate in self._getBaudrateList(): # Cycle all baud rates (auto detect)
@ -241,10 +245,17 @@ class PrinterConnection(SignalEmitter):
## Close the printer connection
def close(self):
if self._connect_thread.isAlive():
self._connect_thread.join()
try:
self._connect_thread.join()
except Exception as e:
pass # This should work, but it does fail sometimes for some reason
if self._serial is not None:
self.setIsConnected(False)
self._listen_thread.join()
try:
self._listen_thread.join()
except:
pass
self._serial.close()
self._serial = None

View File

@ -19,8 +19,7 @@ from PyQt5.QtQuick import QQuickView
from PyQt5.QtCore import QUrl, QObject, pyqtSlot, pyqtProperty, pyqtSignal
from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("uranium")
i18n_catalog = i18nCatalog("cura")
class USBPrinterManager(QObject, SignalEmitter, Extension):
def __init__(self, parent = None):
@ -40,6 +39,7 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
self._error_message = ""
## Add menu item to top menu of the application.
self.setMenuName("Firmware")
self.addMenuItem(i18n_catalog.i18n("Update Firmware"), self.updateAllFirmware)
pyqtError = pyqtSignal(str, arguments = ["amount"])

91
resources/i18n/ru/cura.po Normal file
View File

@ -0,0 +1,91 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-05-07 16:35+0200\n"
"PO-Revision-Date: 2015-06-01 18:29+0300\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"Last-Translator: \n"
"Language-Team: \n"
"X-Generator: Poedit 1.8.1\n"
#: /home/ahiemstra/Projects/Ultimaker/cura/src/CuraApplication.py:91
msgctxt "Save button tooltip"
msgid "Save to Disk"
msgstr "Сохранить на диск"
#: /home/ahiemstra/Projects/Ultimaker/cura/src/CuraApplication.py:96
msgctxt "Splash screen message"
msgid "Setting up scene..."
msgstr "Настройка сцены ..."
#: /home/ahiemstra/Projects/Ultimaker/cura/src/CuraApplication.py:130
msgctxt "Splash screen message"
msgid "Loading interface..."
msgstr "Загрузка интерфейса ..."
#: /home/ahiemstra/Projects/Ultimaker/cura/src/CuraApplication.py:373
#, python-brace-format
msgctxt "Save button tooltip. {0} is sd card name"
msgid "Save to SD Card {0}"
msgstr "Сохранить на SD карту {0}"
#: /home/ahiemstra/Projects/Ultimaker/cura/src/CuraApplication.py:421
#, python-brace-format
msgctxt "Saved to SD message, {0} is sdcard, {1} is filename"
msgid "Saved to SD Card {0} as {1}"
msgstr "Сохранено на SD карту {0} как {1}"
#: /home/ahiemstra/Projects/Ultimaker/cura/src/CuraApplication.py:424
msgctxt "Message action"
msgid "Eject"
msgstr "Извлечь"
#: /home/ahiemstra/Projects/Ultimaker/cura/src/CuraApplication.py:426
#, python-brace-format
msgctxt "Message action tooltip, {0} is sdcard"
msgid "Eject SD Card {0}"
msgstr "Извлечь SD карту {0}"
#: /home/ahiemstra/Projects/Ultimaker/cura/plugins/CuraEngineBackend/__init__.py:13
msgctxt "CuraEngine backend plugin description"
msgid "Provides the link to the CuraEngine slicing backend"
msgstr "Обеспечивает связь с Кура слайсинг сервером"
#: /home/ahiemstra/Projects/Ultimaker/cura/plugins/USBPrinting/USBPrinterManager.py:40
msgid "Update Firmware"
msgstr "Обновление прошивки"
#: /home/ahiemstra/Projects/Ultimaker/cura/plugins/USBPrinting/__init__.py:13
msgctxt "USB Printing plugin description"
msgid "Accepts G-Code and sends them to a printer. Plugin can also update firmware"
msgstr "Принимает G-коды и отправляет их на принтер. Плагин также может обновить прошивку."
#: /home/ahiemstra/Projects/Ultimaker/cura/plugins/GCodeWriter/__init__.py:13
msgctxt "GCode Writer Plugin Description"
msgid "Writes GCode to a file"
msgstr "Записывает G-код в файл "
#: /home/ahiemstra/Projects/Ultimaker/cura/plugins/GCodeWriter/__init__.py:18
msgctxt "GCode Writer File Description"
msgid "GCode File"
msgstr "G-код"
#: /home/ahiemstra/Projects/Ultimaker/cura/plugins/LayerView/__init__.py:13
msgctxt "Layer View plugin description"
msgid "Provides the Layer view."
msgstr "Обеспечивает просмотр слоев."
#: /home/ahiemstra/Projects/Ultimaker/cura/plugins/LayerView/__init__.py:16
msgctxt "Layers View mode"
msgid "Layers"
msgstr "Слой"

View File

@ -0,0 +1,430 @@
msgid ""
msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"Project-Id-Version: Cura\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: ru\n"
"X-Generator: Poedit 1.8.1\n"
#. About dialog title
#: ../resources/qml/AboutDialog.qml:12
msgctxt "AboutDialog|"
msgid "About Cura"
msgstr "О Кура"
#. About dialog application description
#: ../resources/qml/AboutDialog.qml:42
msgctxt "AboutDialog|"
msgid "End-to-end solution for fused filament 3D printing."
msgstr "Комплексное решение для 3D печати по технологии послойного накладывание пластика."
#. About dialog application author note
#: ../resources/qml/AboutDialog.qml:47
msgctxt "AboutDialog|"
msgid "Cura has been developed by Ultimaker B.V. in cooperation with the community."
msgstr "Кура была разработана компании Ultimaker BV в сотрудничестве с сообществом."
#. Close about dialog button
#: ../resources/qml/AboutDialog.qml:58
msgctxt "AboutDialog|"
msgid "Close"
msgstr "Закрыть окно"
#. Undo action
#: ../resources/qml/Actions.qml:37
msgctxt "Actions|"
msgid "&Undo"
msgstr "&Отмена"
#. Redo action
#: ../resources/qml/Actions.qml:45
msgctxt "Actions|"
msgid "&Redo"
msgstr "&Повтор"
#. Quit action
#: ../resources/qml/Actions.qml:53
msgctxt "Actions|"
msgid "&Quit"
msgstr "&Выход"
#. Preferences action
#: ../resources/qml/Actions.qml:61
msgctxt "Actions|"
msgid "&Preferences..."
msgstr "&Настройки программы..."
#. Add Printer action
#: ../resources/qml/Actions.qml:68
msgctxt "Actions|"
msgid "&Add Printer..."
msgstr "&Добавит новый принтер"
#. Configure Printers action
#: ../resources/qml/Actions.qml:74
msgctxt "Actions|"
msgid "&Configure Printers"
msgstr "&Настройки принтера"
#. Show Online Documentation action
#: ../resources/qml/Actions.qml:81
msgctxt "Actions|"
msgid "Show Online &Documentation"
msgstr "Показать онлайн &справку"
#. Report a Bug Action
#: ../resources/qml/Actions.qml:89
msgctxt "Actions|"
msgid "Report a &Bug"
msgstr "Сообщить о &проблеме"
#. About action
#: ../resources/qml/Actions.qml:96
msgctxt "Actions|"
msgid "&About..."
msgstr "&О Кура"
#. Delete selection action
#: ../resources/qml/Actions.qml:103
msgctxt "Actions|"
msgid "Delete Selection"
msgstr "Удалить выбранное"
#. Delete object action
#: ../resources/qml/Actions.qml:111
msgctxt "Actions|"
msgid "Delete Object"
msgstr "Удалить объект"
#. Center object action
#: ../resources/qml/Actions.qml:118
msgctxt "Actions|"
msgid "Center Object on Platform"
msgstr "Расположить объект по центру"
#. Duplicate object action
#: ../resources/qml/Actions.qml:124
msgctxt "Actions|"
msgid "Duplicate Object"
msgstr "Умножить объект"
#. Split object action
#: ../resources/qml/Actions.qml:130
msgctxt "Actions|"
msgid "Split Object into Parts"
msgstr "Разбить объект на частей"
#. Clear build platform action
#: ../resources/qml/Actions.qml:137
msgctxt "Actions|"
msgid "Clear Build Platform"
msgstr "Очистить печатающую платформу"
#. Reload all objects action
#: ../resources/qml/Actions.qml:144
msgctxt "Actions|"
msgid "Reload All Objects"
msgstr "Перезагрузить все объекты"
#. Reset all positions action
#: ../resources/qml/Actions.qml:150
msgctxt "Actions|"
msgid "Reset All Object Positions"
msgstr "Сбросить все позиции объектов"
#. Reset all positions action
#: ../resources/qml/Actions.qml:156
msgctxt "Actions|"
msgid "Reset All Object Transformations"
msgstr "Сбросить все преобразования объектов"
#. Open file action
#: ../resources/qml/Actions.qml:162
msgctxt "Actions|"
msgid "&Open..."
msgstr "&Открыть..."
#. Save file action
#: ../resources/qml/Actions.qml:170
msgctxt "Actions|"
msgid "&Save..."
msgstr "&Сохранить..."
#. Show engine log action
#: ../resources/qml/Actions.qml:178
msgctxt "Actions|"
msgid "Show engine &log..."
msgstr "Показать журнал &слайсера"
#. Add Printer dialog title
#. ----------
#. Add Printer wizard page title
#: ../resources/qml/AddMachineWizard.qml:12
#: ../resources/qml/AddMachineWizard.qml:19
msgctxt "AddMachineWizard|"
msgid "Add Printer"
msgstr "Добавить новый принтер"
#. Add Printer wizard page description
#: ../resources/qml/AddMachineWizard.qml:25
msgctxt "AddMachineWizard|"
msgid "Please select the type of printer:"
msgstr "Выберите тип принтера:"
#. Add Printer wizard field label
#: ../resources/qml/AddMachineWizard.qml:40
msgctxt "AddMachineWizard|"
msgid "Printer Name:"
msgstr "Название принтера:"
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:53
msgctxt "AddMachineWizard|"
msgid "Next"
msgstr "Дальше"
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:63
msgctxt "AddMachineWizard|"
msgid "Cancel"
msgstr "Отменить"
#. USB Printing dialog label, %1 is head temperature
#: ../plugins/USBPrinting/ControlWindow.qml:15
#, qt-format
msgctxt "ControlWindow|"
msgid "Extruder Temperature %1"
msgstr "Температура экструдера %1"
#. USB Printing dialog label, %1 is bed temperature
#: ../plugins/USBPrinting/ControlWindow.qml:20
#, qt-format
msgctxt "ControlWindow|"
msgid "Bed Temperature %1"
msgstr "Температура платформы %1"
#. USB Printing dialog start print button
#: ../plugins/USBPrinting/ControlWindow.qml:33
msgctxt "ControlWindow|"
msgid "Print"
msgstr "Печать"
#. USB Printing dialog cancel print button
#: ../plugins/USBPrinting/ControlWindow.qml:40
msgctxt "ControlWindow|"
msgid "Cancel"
msgstr "Отменить"
#. Cura application window title
#: ../resources/qml/Cura.qml:14
msgctxt "Cura|"
msgid "Cura"
msgstr "Кура"
#. File menu
#: ../resources/qml/Cura.qml:26
msgctxt "Cura|"
msgid "&File"
msgstr "&Файл"
#. Edit menu
#: ../resources/qml/Cura.qml:38
msgctxt "Cura|"
msgid "&Edit"
msgstr "&Изменить"
#. Machine menu
#: ../resources/qml/Cura.qml:50
msgctxt "Cura|"
msgid "&Machine"
msgstr "&Принтер"
#. Extensions menu
#: ../resources/qml/Cura.qml:76
msgctxt "Cura|"
msgid "E&xtensions"
msgstr "&Расширения"
#. Settings menu
#: ../resources/qml/Cura.qml:107
msgctxt "Cura|"
msgid "&Settings"
msgstr "&Настройки"
#. Help menu
#: ../resources/qml/Cura.qml:114
msgctxt "Cura|"
msgid "&Help"
msgstr "&Помощь"
#. View Mode toolbar button
#: ../resources/qml/Cura.qml:231
msgctxt "Cura|"
msgid "View Mode"
msgstr "Режим просмотра"
#. View preferences page title
#: ../resources/qml/Cura.qml:273
msgctxt "Cura|"
msgid "View"
msgstr "Просмотр"
#. File open dialog title
#: ../resources/qml/Cura.qml:370
msgctxt "Cura|"
msgid "Open File"
msgstr "Открыть файл"
#. File save dialog title
#: ../resources/qml/Cura.qml:386
msgctxt "Cura|"
msgid "Save File"
msgstr "Сохранить файл"
#. Engine Log dialog title
#: ../resources/qml/EngineLog.qml:11
msgctxt "EngineLog|"
msgid "Engine Log"
msgstr "Журнал слайсера"
#. Close engine log button
#: ../resources/qml/EngineLog.qml:30
msgctxt "EngineLog|"
msgid "Close"
msgstr "Закрыть"
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:16
msgctxt "FirmwareUpdateWindow|"
msgid "Starting firmware update, this may take a while."
msgstr "Начинается обновление прошивки, это может занять некоторое время."
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:21
msgctxt "FirmwareUpdateWindow|"
msgid "Firmware update completed."
msgstr "Обновление прошивки завершено."
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:26
msgctxt "FirmwareUpdateWindow|"
msgid "Updating firmware."
msgstr "Обновление прошивки."
#. Print material amount save button label
#: ../resources/qml/SaveButton.qml:149
#, qt-format
msgctxt "SaveButton|"
msgid "%1m material"
msgstr "%1m материал"
#. Save button label
#: ../resources/qml/SaveButton.qml:191
msgctxt "SaveButton|"
msgid "Please load a 3D model"
msgstr "Пожалуйста, загрузите 3D модель"
#. Save button label
#: ../resources/qml/SaveButton.qml:194
msgctxt "SaveButton|"
msgid "Calculating Print-time"
msgstr "Вычисляется время печати"
#. Save button label
#: ../resources/qml/SaveButton.qml:197
msgctxt "SaveButton|"
msgid "Estimated Print-time"
msgstr "Расчетное время печати"
#. Simple configuration mode option
#: ../resources/qml/Sidebar.qml:105
msgctxt "Sidebar|"
msgid "Simple"
msgstr "Простой"
#. Advanced configuration mode option
#: ../resources/qml/Sidebar.qml:107
msgctxt "Sidebar|"
msgid "Advanced"
msgstr "Продвинутый"
#. Configuration mode label
#: ../resources/qml/SidebarHeader.qml:26
msgctxt "SidebarHeader|"
msgid "Mode:"
msgstr "Режим:"
#. Machine selection label
#: ../resources/qml/SidebarHeader.qml:70
msgctxt "SidebarHeader|"
msgid "Machine:"
msgstr "Принтер:"
#. Sidebar header label
#: ../resources/qml/SidebarHeader.qml:117
msgctxt "SidebarHeader|"
msgid "Print Setup"
msgstr "Настройка Печати"
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:40
msgctxt "SidebarSimple|"
msgid "No Model Loaded"
msgstr "Модель не загружена"
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:45
msgctxt "SidebarSimple|"
msgid "Calculating..."
msgstr "Высчитывается..."
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:50
msgctxt "SidebarSimple|"
msgid "Estimated Print Time"
msgstr "Расчетное время печати"
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:87
msgctxt "SidebarSimple|"
msgid ""
"Minimum\n"
"Draft"
msgstr ""
"Минимальная \n"
"тяга"
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:97
msgctxt "SidebarSimple|"
msgid ""
"Maximum\n"
"Quality"
msgstr ""
"Максимальное\n"
"Качество"
#. Setting checkbox
#: ../resources/qml/SidebarSimple.qml:109
msgctxt "SidebarSimple|"
msgid "Enable Support"
msgstr "Включить Поддержку"
#. View configuration page title
#: ../resources/qml/ViewPage.qml:9
msgctxt "ViewPage|"
msgid "View"
msgstr "Просмотр"
#. Display Overhang preference checkbox
#: ../resources/qml/ViewPage.qml:24
msgctxt "ViewPage|"
msgid "Display Overhang"
msgstr "Показать где есть нависающие части"

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -3,7 +3,6 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import UM 1.0 as UM
@ -12,48 +11,53 @@ UM.Dialog {
id: base
//: About dialog title
title: qsTr("About Cura");
title: qsTr("About Cura")
minimumWidth: 400
minimumHeight: 300
ColumnLayout {
anchors.fill: parent;
Image {
id: logo
width: parent.width * 0.75
height: width * (1/4.25)
Item {
Layout.fillWidth: true;
Layout.fillHeight: true;
}
source: UM.Theme.images.logo
Image {
Layout.alignment: Qt.AlignHCenter;
Layout.preferredWidth: parent.width * 0.75;
Layout.preferredHeight: width * (1/4.25);
sourceSize.width: width
sourceSize.height: height
anchors.centerIn: parent
anchors.verticalCenterOffset : -(height * 0.5)
}
source: UM.Theme.images.logo;
Label {
id: version
sourceSize.width: width;
sourceSize.height: height;
}
text: "Cura 15.06 Beta"
font: UM.Theme.fonts.large
anchors.horizontalCenter : logo.horizontalCenter
anchors.horizontalCenterOffset : (logo.width * 0.25)
anchors.top: logo.bottom
anchors.topMargin : 5
}
Label {
Layout.alignment: Qt.AlignHCenter;
Label {
id: description
width: parent.width
text: "Cura 15.06 Beta";
font: UM.Theme.fonts.large;
}
//: About dialog application description
text: qsTr("End-to-end solution for fused filament 3D printing.")
wrapMode: Text.WordWrap
anchors.top: version.bottom
anchors.topMargin : 10
}
Label {
//: About dialog application description
text: qsTr("End-to-end solution for fused filament 3D printing.")
}
Label {
id: author_note
width: parent.width
Label {
//: About dialog application author note
text: qsTr("Cura has been developed by Ultimaker B.V. in cooperation with the community.")
}
Item {
Layout.fillWidth: true;
Layout.fillHeight: true;
}
//: About dialog application author note
text: qsTr("Cura has been developed by Ultimaker B.V. in cooperation with the community.")
wrapMode: Text.WordWrap
anchors.top: description.bottom
}
rightButtons: Button {

View File

@ -25,6 +25,7 @@ UM.MainWindow {
window: base
Menu {
id: fileMenu
//: File menu
title: qsTr("&File");
@ -33,6 +34,21 @@ UM.MainWindow {
MenuSeparator { }
Instantiator {
model: Printer.recentFiles
MenuItem {
text: {
var path = modelData.toString()
return (index + 1) + ". " + path.slice(path.lastIndexOf("/") + 1);
}
onTriggered: UM.MeshFileHandler.readLocalFile(modelData);
}
onObjectAdded: fileMenu.insertItem(index, object)
onObjectRemoved: fileMenu.removeItem(object)
}
MenuSeparator { }
MenuItem { action: actions.quit; }
}
@ -144,23 +160,6 @@ UM.MainWindow {
}
}
Sidebar {
id: sidebar;
anchors {
top: parent.top;
bottom: parent.bottom;
right: parent.right;
rightMargin: UM.Theme.sizes.window_margin.width;
}
width: UM.Theme.sizes.panel.width;
addMachineAction: actions.addMachine;
configureMachinesAction: actions.configureMachines;
saveAction: actions.save;
}
UM.MessageStack {
anchors {
left: toolbar.right;
@ -195,8 +194,8 @@ UM.MainWindow {
id: openFileButton;
iconSource: UM.Theme.icons.open;
style: UM.Theme.styles.tool_button;
style: UM.Backend.progress < 0 ? UM.Theme.styles.open_file_button : UM.Theme.styles.tool_button;
tooltip: '';
anchors {
top: parent.top;
topMargin: UM.Theme.sizes.window_margin.height;
@ -235,7 +234,7 @@ UM.MainWindow {
iconSource: UM.Theme.icons.viewmode;
style: UM.Theme.styles.tool_button;
tooltip: '';
menu: Menu {
id: viewMenu;
Instantiator {
@ -265,6 +264,35 @@ UM.MainWindow {
bottomMargin: UM.Theme.sizes.window_margin.height;
}
}
Sidebar {
id: sidebar;
anchors {
top: parent.top;
bottom: parent.bottom;
right: parent.right;
}
width: UM.Theme.sizes.panel.width;
addMachineAction: actions.addMachine;
configureMachinesAction: actions.configureMachines;
saveAction: actions.save;
}
Rectangle {
x: base.mouseX + UM.Theme.sizes.default_margin.width;
y: base.mouseY + UM.Theme.sizes.default_margin.height;
width: childrenRect.width;
height: childrenRect.height;
Label {
text: UM.ActiveTool.properties.Rotation != undefined ? "%1°".arg(UM.ActiveTool.properties.Rotation) : "";
}
visible: UM.ActiveTool.valid && UM.ActiveTool.properties.Rotation != undefined;
}
}
}
@ -323,8 +351,8 @@ UM.MainWindow {
preferences.onTriggered: preferences.visible = true;
configureMachines.onTriggered: { preferences.visible = true; preferences.setPage(2); }
documentation.onTriggered: Qt.openUrlExternally("https://ultimaker.com/en/support");
reportBug.onTriggered: Qt.openUrlExternally("https://github.com/Ultimaker/Cura/issues");
documentation.onTriggered: CuraActions.openDocumentation();
reportBug.onTriggered: CuraActions.openBugReportPage();
showEngineLog.onTriggered: engineLog.visible = true;
about.onTriggered: aboutDialog.visible = true;
}
@ -419,3 +447,4 @@ UM.MainWindow {
Component.onCompleted: UM.Theme.load(UM.Resources.getPath(UM.Resources.ThemesLocation, "cura"))
}

View File

@ -8,7 +8,7 @@ import QtQuick.Layouts 1.1
import UM 1.0 as UM
Button {
Rectangle {
id: base;
property Action saveAction;
@ -16,8 +16,6 @@ Button {
property real progress: UM.Backend.progress;
Behavior on progress { NumberAnimation { duration: 250; } }
enabled: progress >= 0.95;
property string currentDevice: "local_file"
property bool defaultOverride: false;
property bool defaultAmbiguous: false;
@ -25,9 +23,6 @@ Button {
property variant printDuration: PrintInformation.currentPrintTime;
property real printMaterialAmount: PrintInformation.materialAmount;
iconSource: UM.Theme.icons[Printer.outputDevices[base.currentDevice].icon];
tooltip: Printer.outputDevices[base.currentDevice].description;
Connections {
target: Printer;
onOutputDevicesChanged: {
@ -51,161 +46,183 @@ Button {
}
}
style: ButtonStyle {
background: UM.AngledCornerRectangle {
implicitWidth: control.width;
implicitHeight: control.height;
Rectangle{
id: background
implicitWidth: base.width;
implicitHeight: parent.height;
color: UM.Theme.colors.save_button_background;
border.width: UM.Theme.sizes.save_button_border.width
border.color: UM.Theme.colors.save_button_border
color: UM.Theme.colors.save_button_border;
cornerSize: UM.Theme.sizes.default_margin.width;
Rectangle {
id: infoBox
width: parent.width - UM.Theme.sizes.default_margin.width * 2;
height: UM.Theme.sizes.save_button_slicing_bar.height
UM.AngledCornerRectangle {
anchors.fill: parent;
anchors.margins: UM.Theme.sizes.save_button_border.width;
cornerSize: UM.Theme.sizes.default_margin.width;
color: UM.Theme.colors.save_button;
}
anchors.top: parent.top
anchors.topMargin: UM.Theme.sizes.default_margin.height;
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
UM.AngledCornerRectangle {
anchors {
left: parent.left;
top: parent.top;
bottom: parent.bottom;
}
width: Math.max(parent.height + (parent.width - parent.height) * control.progress, parent.height);
cornerSize: UM.Theme.sizes.default_margin.width;
color: !control.enabled ? UM.Theme.colors.save_button_inactive : control.hovered ? UM.Theme.colors.save_button_active_hover : UM.Theme.colors.save_button_active;
Behavior on color { ColorAnimation { duration: 50; } }
}
UM.AngledCornerRectangle {
anchors.left: parent.left;
width: parent.height + UM.Theme.sizes.save_button_border.width;
height: parent.height;
cornerSize: UM.Theme.sizes.default_margin.width;
color: UM.Theme.colors.save_button;
}
UM.AngledCornerRectangle {
anchors.left: parent.left;
width: parent.height + UM.Theme.sizes.save_button_border.width;
height: parent.height;
cornerSize: UM.Theme.sizes.default_margin.width;
color: UM.Theme.colors.save_button;
}
UM.AngledCornerRectangle {
id: icon;
anchors.left: parent.left;
width: parent.height;
height: parent.height;
cornerSize: UM.Theme.sizes.default_margin.width;
color: !control.enabled ? UM.Theme.colors.save_button_inactive : control.hovered ? UM.Theme.colors.save_button_active_hover : UM.Theme.colors.save_button_active;
Behavior on color { ColorAnimation { duration: 50; } }
Image {
anchors.centerIn: parent;
width: UM.Theme.sizes.button_icon.width;
height: UM.Theme.sizes.button_icon.height;
sourceSize.width: width;
sourceSize.height: height;
source: control.iconSource;
}
}
}
label: Column {
border.width: UM.Theme.sizes.save_button_border.width
border.color: UM.Theme.colors.save_button_border
color: UM.Theme.colors.save_button_estimated_text_background;
Label {
id: label;
anchors.left: parent.left;
anchors.leftMargin: control.height + UM.Theme.sizes.save_button_label_margin.width;
color: UM.Theme.colors.save_button_text;
font: UM.Theme.fonts.default;
text: control.text;
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.save_button_text_margin.width;
visible: base.progress >= 0 && base.progress < 0.99 ? false : true
color: UM.Theme.colors.save_button_estimated_text;
font: UM.Theme.fonts.small;
text:
if(base.progress < 0) {
//: Save button label
return qsTr("Please load a 3D model");
} else if (base.progress < 0.99) {
//: Save button label
return qsTr("Calculating Print-time");
} else if (base.progress > 0.99){
//: Save button label
return qsTr("Estimated Print-time");
} else if (base.progress == null){
return qsTr("");
}
}
Label {
anchors.left: parent.left;
anchors.leftMargin: control.height + UM.Theme.sizes.save_button_label_margin.width;
color: UM.Theme.colors.save_button_text;
font: UM.Theme.fonts.default;
text: (!control.printDuration || !control.printDuration.valid) ? "" : control.printDuration.getDisplayString(UM.DurationFormat.Long)
id: printDurationLabel
anchors.verticalCenter: parent.verticalCenter
anchors.left: label.right;
anchors.leftMargin: UM.Theme.sizes.save_button_text_margin.width;
color: UM.Theme.colors.save_button_printtime_text;
font: UM.Theme.fonts.small;
visible: base.progress < 0.99 ? false : true
text: (!base.printDuration || !base.printDuration.valid) ? "" : base.printDuration.getDisplayString(UM.DurationFormat.Long);
}
Label {
anchors.left: parent.left;
anchors.leftMargin: control.height + UM.Theme.sizes.save_button_label_margin.width;
color: UM.Theme.colors.save_button_text;
font: UM.Theme.fonts.default;
id: printMaterialLabel
anchors.verticalCenter: parent.verticalCenter
anchors.left: printDurationLabel.right;
anchors.leftMargin: UM.Theme.sizes.save_button_text_margin.width;
color: UM.Theme.colors.save_button_printtime_text;
font: UM.Theme.fonts.small;
visible: base.progress < 0.99 ? false : true
//: Print material amount save button label
text: control.printMaterialAmount < 0 ? "" : qsTr("%1m material").arg(control.printMaterialAmount);
text: base.printMaterialAmount < 0 ? "" : qsTr("%1m material").arg(base.printMaterialAmount);
}
}
}
Rectangle {
id: infoBoxOverlay
anchors {
left: infoBox.left;
top: infoBox.top;
bottom: infoBox.bottom;
}
width: Math.max(infoBox.width * base.progress);
color: UM.Theme.colors.save_button_active
visible: base.progress > 0.99 ? false : true
}
MouseArea {
anchors.fill: parent;
Button {
id: saveToButton
anchors.top: infoBox.bottom
anchors.topMargin: UM.Theme.sizes.save_button_text_margin.height;
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
tooltip: ''
enabled: progress >= 0.99;
acceptedButtons: Qt.RightButton;
onClicked: devicesMenu.popup();
}
Menu {
id: devicesMenu;
Instantiator {
model: Printer.outputDeviceNames;
MenuItem {
text: Printer.outputDevices[modelData].description;
checkable: true;
checked: base.defaultAmbiguous ? false : modelData == base.currentDevice;
exclusiveGroup: devicesMenuGroup;
onTriggered: {
base.defaultOverride = true;
base.currentDevice = modelData;
if(base.defaultAmbiguous) {
base.defaultAmbiguous = false;
Printer.writeToOutputDevice(modelData);
width: infoBox.width/6*4.5
height: UM.Theme.sizes.save_button_save_to_button.height
style: ButtonStyle {
background: Rectangle {
color: !control.enabled ? UM.Theme.colors.save_button_inactive : control.hovered ? UM.Theme.colors.save_button_active_hover : UM.Theme.colors.save_button_active;
Label {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
color: UM.Theme.colors.save_button_safe_to_text;
font: UM.Theme.fonts.sidebar_save_to;
text: Printer.outputDevices[base.currentDevice].description;
}
}
}
onObjectAdded: devicesMenu.insertItem(index, object)
onObjectRemoved: devicesMenu.removeItem(object)
onClicked:
if(base.defaultAmbiguous) {
devicesMenu.popup();
} else {
Printer.writeToOutputDevice(base.currentDevice);
}
}
ExclusiveGroup { id: devicesMenuGroup; }
}
Button {
id: deviceSelectionMenu;
anchors.top: infoBox.bottom
anchors.topMargin: UM.Theme.sizes.save_button_text_margin.height
anchors.right: parent.right
anchors.rightMargin: UM.Theme.sizes.default_margin.width;
tooltip: ''
text: {
if(base.progress < 0) {
//: Save button label
return qsTr("Please load a 3D model");
} else if (base.progress < 0.95) {
//: Save button label
return qsTr("Calculating Print-time");
} else {
//: Save button label
return qsTr("Estimated Print-time");
width: infoBox.width/6*1.3 - UM.Theme.sizes.save_button_text_margin.height;
height: UM.Theme.sizes.save_button_save_to_button.height
style: ButtonStyle {
background: Rectangle {
color: UM.Theme.colors.save_button_background;
border.width: control.hovered ? UM.Theme.sizes.save_button_border.width : 0
border.color: UM.Theme.colors.save_button_border
Rectangle {
id: deviceSelectionIcon
color: UM.Theme.colors.save_button_background;
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.save_button_text_margin.width / 2;
anchors.verticalCenter: parent.verticalCenter;
width: parent.height - UM.Theme.sizes.save_button_text_margin.width ;
height: parent.height - UM.Theme.sizes.save_button_text_margin.width;
UM.RecolorImage {
anchors.centerIn: parent;
width: parent.width;
height: parent.height;
sourceSize.width: width;
sourceSize.height: height;
color: UM.Theme.colors.save_button_active
source: UM.Theme.icons[Printer.outputDevices[base.currentDevice].icon];
}
}
Label {
id: deviceSelectionArrow
anchors.right: parent.right;
anchors.rightMargin: UM.Theme.sizes.save_button_text_margin.height
anchors.verticalCenter: parent.verticalCenter;
text: "▼";
font: UM.Theme.fonts.tiny;
color: UM.Theme.colors.save_button_active;
}
}
}
menu: Menu {
id: devicesMenu;
Instantiator {
model: Printer.outputDeviceNames;
MenuItem {
text: Printer.outputDevices[modelData].description;
checkable: true;
checked: base.defaultAmbiguous ? false : modelData == base.currentDevice;
exclusiveGroup: devicesMenuGroup;
onTriggered: {
base.defaultOverride = true;
base.currentDevice = modelData;
if(base.defaultAmbiguous) {
base.defaultAmbiguous = false;
Printer.writeToOutputDevice(modelData);
}
}
}
onObjectAdded: devicesMenu.insertItem(index, object)
onObjectRemoved: devicesMenu.removeItem(object)
}
ExclusiveGroup { id: devicesMenuGroup; }
}
}
}
onClicked: {
if(base.defaultAmbiguous) {
devicesMenu.popup();
} else {
Printer.writeToOutputDevice(base.currentDevice);
}
}
}
}

View File

@ -8,18 +8,18 @@ import QtQuick.Layouts 1.1
import UM 1.0 as UM
UM.AngledCornerRectangle {
Rectangle {
id: base;
property Action addMachineAction;
property Action configureMachinesAction;
property alias saveAction: saveButton.saveAction;
cornerSize: UM.Theme.sizes.default_margin.width;
color: UM.Theme.colors.sidebar;
function showTooltip(item, position, text) {
tooltip.text = text;
position = item.mapToItem(base, position.x, position.y);
position = item.mapToItem(base, position.x, position.y / 2);
tooltip.show(position);
}
@ -39,7 +39,6 @@ UM.AngledCornerRectangle {
ColumnLayout {
anchors.fill: parent;
anchors.topMargin: UM.Theme.sizes.default_margin.height;
anchors.bottomMargin: UM.Theme.sizes.window_margin.height;
spacing: UM.Theme.sizes.default_margin.height;
@ -73,7 +72,7 @@ UM.AngledCornerRectangle {
property Item sidebar: base;
onLoaded:
{
{
if(item)
{
item.configureSettings = base.configureMachinesAction;
@ -91,13 +90,11 @@ UM.AngledCornerRectangle {
SaveButton {
id: saveButton;
Layout.preferredWidth: base.width - UM.Theme.sizes.default_margin.width * 2;
Layout.preferredHeight: UM.Theme.sizes.button.height;
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter;
implicitWidth: base.width
implicitHeight: UM.Theme.sizes.save_button_text_margin.height * 2 + UM.Theme.sizes.save_button_slicing_bar.height + UM.Theme.sizes.save_button_save_to_button.height + UM.Theme.sizes.default_margin.height
}
}
SidebarTooltip {
id: tooltip;
}
@ -109,4 +106,11 @@ UM.AngledCornerRectangle {
//: Advanced configuration mode option
ListElement { text: QT_TR_NOOP("Advanced"); file: "SidebarAdvanced.qml" }
}
Component.onCompleted: {
for(var i = 0; i < modesListModel.count; ++i)
{
modesListModel.setProperty(i, "text", qsTr(modesListModel.get(i).text));
}
}
}

View File

@ -1,6 +1,13 @@
// Copyright (c) 2015 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.0
import QtQuick.Controls 1.2
import UM 1.0 as UM
UM.SettingView { }
UM.SettingView {
expandedCategories: Printer.expandedCategories;
onExpandedCategoriesChanged: Printer.setExpandedCategories(expandedCategories);
}

View File

@ -33,7 +33,7 @@ Column {
}
ToolButton {
text: base.modesModel ? qsTr(base.modesModel.get(modeMenu.currentIndex).text) : "";
text: base.modesModel ? base.modesModel.get(modeMenu.currentIndex).text : "";
style: UM.Theme.styles.sidebar_header_button;
@ -48,7 +48,7 @@ Column {
model: base.modesModel;
MenuItem {
text: qsTr(model.text);
text: model.text;
checkable: true;
checked: modeMenu.currentIndex == index;
exclusiveGroup: modeMenuGroup;

View File

@ -20,6 +20,9 @@ Item {
property variant minimumPrintTime: PrintInformation.minimumPrintTime;
property variant maximumPrintTime: PrintInformation.maximumPrintTime;
Component.onCompleted: PrintInformation.enabled = true
Component.onDestruction: PrintInformation.enabled = false
ColumnLayout {
anchors.fill: parent;

View File

@ -22,10 +22,10 @@ Rectangle {
function show(position) {
if(position.y + base.height > parent.height) {
x = position.x;
x = position.x - base.width;
y = parent.height - base.height;
} else {
x = position.x;
x = position.x - base.width;
y = position.y;
}
base.opacity = 1;

View File

@ -14,6 +14,24 @@ Item {
width: buttons.width;
height: buttons.height + panel.height;
Rectangle {
id: activeItemBackground;
anchors.bottom: parent.bottom;
anchors.bottomMargin: UM.Theme.sizes.default_margin.height;
width: UM.Theme.sizes.button.width;
height: UM.Theme.sizes.button.height * 2;
opacity: panelBackground.opacity;
color: UM.Theme.colors.tool_panel_background
function setActive(new_x) {
x = new_x;
}
}
RowLayout {
id: buttons;
@ -30,10 +48,10 @@ Item {
Button {
text: model.name;
iconSource: UM.Theme.icons[model.icon];
tooltip: model.description;
checkable: true;
checked: model.active;
onCheckedChanged: if (checked) activeItemBackground.setActive(x);
style: UM.Theme.styles.tool_button;
@ -43,20 +61,33 @@ Item {
anchors.fill: parent;
onClicked: parent.checked ? UM.Controller.setActiveTool(null) : UM.Controller.setActiveTool(model.id);
}
}
}
}
}
Loader {
id: panel
UM.AngledCornerRectangle {
id: panelBackground;
anchors.left: parent.left;
anchors.right: parent.right;
anchors.bottom: buttons.top;
anchors.bottomMargin: UM.Theme.sizes.default_margin.height;
height: childrenRect.height;
width: panel.item ? Math.max(panel.width + 2 * UM.Theme.sizes.default_margin.width, activeItemBackground.x + activeItemBackground.width) : 0;
height: panel.item ? panel.height + 2 * UM.Theme.sizes.default_margin.height : 0;
source: UM.ActiveTool.valid ? UM.ActiveTool.activeToolPanel : "";
opacity: panel.item ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 100 } }
color: UM.Theme.colors.tool_panel_background;
cornerSize: width > 0 ? UM.Theme.sizes.default_margin.width : 0;
Loader {
id: panel
x: UM.Theme.sizes.default_margin.width;
y: UM.Theme.sizes.default_margin.height;
source: UM.ActiveTool.valid ? UM.ActiveTool.activeToolPanel : "";
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,20 @@
"categories": {
"material": {
"visible": false
"settings": {
"material_print_temperature": {
"visible": false
},
"material_bed_temperature": {
"visible": false
},
"material_diameter": {
"visible": false
},
"material_flow": {
"visible": false
}
}
}
}
}

View File

@ -19,6 +19,23 @@
"machine_nozzle_gantry_distance": { "default": 55 },
"machine_nozzle_offset_x_1": { "default": 18.0 },
"machine_nozzle_offset_y_1": { "default": 0.0 },
"machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" }
"machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": {
"default": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E3 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..."
},
"machine_end_gcode": {
"default": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
}
},
"categories": {
"material": {
"settings": {
"material_bed_temperature": {
"visible": false
}
}
}
}
}

View File

@ -1,6 +1,6 @@
{
"id": "ultimaker_original_plus",
"name": "Ultimaker Original Plus",
"name": "Ultimaker Original+",
"icon": "icon_ultimaker.png",
"platform": "ultimaker2_platform.obj",
"platform_texture": "UltimakerPlusbackplate.png",

View File

@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:i="&amp;#38;#38;ns_ai;"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
x="0px"
y="0px"
width="30px"
height="30px"
viewBox="0 0 30 30"
enable-background="new 0 0 30 30"
xml:space="preserve"
id="svg3445"
inkscape:version="0.91 r13725"
sodipodi:docname="category_blackmagic.svg"><metadata
id="metadata3464"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs3462" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1104"
id="namedview3460"
showgrid="false"
inkscape:zoom="15.733333"
inkscape:cx="17.360656"
inkscape:cy="-1.829103"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="g3449" /><switch
id="switch3447"
style="fill:#000000"><foreignObject
requiredExtensions="http://ns.adobe.com/AdobeIllustrator/10.0/"
x="0"
y="0"
width="1"
height="1"><i:pgfRef
xlink:href="#adobe_illustrator_pgf" /></foreignObject><g
i:extraneous="self"
id="g3449"
style="fill:#000000"><g
id="frame_30x30"
display="none"
style="fill:#000000"><rect
display="inline"
width="30"
height="30"
id="rect3452"
style="fill:#000000" /></g><g
id="frame_24x24"
display="none"
style="fill:#000000"><rect
x="3"
y="3"
display="inline"
fill="#C6C7C8"
width="24"
height="24"
id="rect3455"
style="fill:#000000" /></g><g
id="icon"
style="fill:#ffffff"><path
d="M 21,11 24,3 6,3 9,11 3,27 27,27 Z M 9.937,10.648 7.443,4 22.556,4 20.063,10.648 19.932,11 l 0.132,0.352 5.495386,14.648398 c -21.1116911,-0.0086 0,0 -21.1116911,-0.0086 L 9.938,11.352 10.068,11 Z"
id="path3458"
style="fill:#ffffff"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccc" /><text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:18.84262657px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="8.4277077"
y="19.917229"
id="text3477"
sodipodi:linespacing="125%"
transform="scale(1.0563883,0.94662161)"><tspan
sodipodi:role="line"
id="tspan3479"
x="8.4277077"
y="19.917229"
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:gargi;-inkscape-font-specification:'gargi Medium';fill:#ffffff">?</tspan></text>
<path
sodipodi:type="star"
style="fill:#ffffff"
id="path3481"
sodipodi:sides="4"
sodipodi:cx="9.3481913"
sodipodi:cy="22.314709"
sodipodi:r1="2.4681976"
sodipodi:r2="0.83969672"
sodipodi:arg1="-0.57790194"
sodipodi:arg2="0.14505566"
inkscape:flatsided="false"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 11.41558,20.966412 -1.236511,1.469673 0.517419,1.946012 -1.4696728,-1.23651 -1.9460124,0.517419 1.2365104,-1.469673 -0.5174188,-1.946013 1.4696729,1.236511 z"
inkscape:transform-center-x="1.0389927"
inkscape:transform-center-y="0.029898609"
transform="matrix(-0.22728467,0.67950815,-0.70858638,-0.2354929,27.791673,20.846699)" /><path
sodipodi:type="star"
style="fill:#ffffff"
id="path3483"
sodipodi:sides="4"
sodipodi:cx="19.64019"
sodipodi:cy="21.10124"
sodipodi:r1="3.1779661"
sodipodi:r2="1.3224357"
sodipodi:arg1="1.7126934"
sodipodi:arg2="2.4768523"
inkscape:flatsided="false"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 19.190758,24.247266 -0.591427,-2.330275 -2.105167,-1.265183 2.330275,-0.591427 1.265183,-2.105167 0.591427,2.330275 2.105167,1.265183 -2.330275,0.591427 z"
inkscape:transform-center-x="-0.16053709"
inkscape:transform-center-y="0.22160086"
transform="matrix(0.6277977,0.94579165,-0.90860936,0.60311684,26.861228,-9.3621234)" /><path
sodipodi:type="star"
style="fill:#ffffff"
id="path3487"
sodipodi:sides="4"
sodipodi:cx="14.741379"
sodipodi:cy="18.045101"
sodipodi:r1="2.2819479"
sodipodi:r2="0.93399796"
sodipodi:arg1="-1.0101093"
sodipodi:arg2="-0.21584978"
inkscape:flatsided="false"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 15.954846,16.112542 -0.301143,1.732518 1.020235,1.413508 -1.732518,-0.301143 -1.413508,1.020235 0.301142,-1.732517 -1.020234,-1.413509 1.732517,0.301143 z"
inkscape:transform-center-x="-0.17795886"
inkscape:transform-center-y="-0.0146708"
transform="matrix(0.18679438,-0.98239903,0.98239903,0.18679438,-5.8318713,29.017206)" /></g></g></switch><i:pgf
id="adobe_illustrator_pgf" /></svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 246 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 248 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 249 KiB

View File

@ -35,46 +35,42 @@ QtObject {
}
}
property Component tool_button: Component {
property Component open_file_button: Component {
ButtonStyle {
background: UM.AngledCornerRectangle {
property bool down: control.pressed || (control.checkable && control.checked);
background: Item {
implicitWidth: UM.Theme.sizes.button.width;
implicitHeight: UM.Theme.sizes.button.height;
color: {
if(!control.enabled) {
return UM.Theme.colors.button_disabled;
} else if(control.checkable && control.checked && control.hovered) {
return UM.Theme.colors.button_active_hover;
} else if(control.pressed || (control.checkable && control.checked)) {
return UM.Theme.colors.button_active;
} else if(control.hovered) {
return UM.Theme.colors.button_hover;
} else {
return UM.Theme.colors.button;
}
}
Behavior on color { ColorAnimation { duration: 50; } }
cornerSize: UM.Theme.sizes.default_margin.width;
Rectangle {
anchors.bottom: parent.top;
anchors.bottom: parent.verticalCenter;
width: parent.width;
height: control.hovered ? label.height : 0;
Behavior on height { NumberAnimation { duration: 75; } }
height: control.hovered ? parent.height / 2 + label.height : 0;
Behavior on height { NumberAnimation { duration: 100; } }
opacity: control.hovered ? 1.0 : 0.0;
Behavior on opacity { NumberAnimation { duration: 75; } }
Behavior on opacity { NumberAnimation { duration: 100; } }
Label {
id: label
id: label;
anchors.horizontalCenter: parent.horizontalCenter;
text: control.text;
text: control.text.replace("&", "");
font: UM.Theme.fonts.button_tooltip;
color: UM.Theme.colors.button_tooltip_text;
}
}
UM.AngledCornerRectangle {
anchors.fill: parent;
color: {
if(control.hovered) {
return UM.Theme.colors.button_active_hover;
} else {
return UM.Theme.colors.button_active;
}
}
Behavior on color { ColorAnimation { duration: 50; } }
cornerSize: UM.Theme.sizes.default_margin.width;
}
}
label: Item {
@ -91,6 +87,110 @@ QtObject {
}
}
property Component tool_button: Component {
ButtonStyle {
background: Item {
implicitWidth: UM.Theme.sizes.button.width;
implicitHeight: UM.Theme.sizes.button.height;
Rectangle {
anchors.bottom: parent.verticalCenter;
width: parent.width;
height: control.hovered ? parent.height / 2 + label.height : 0;
Behavior on height { NumberAnimation { duration: 100; } }
opacity: control.hovered ? 1.0 : 0.0;
Behavior on opacity { NumberAnimation { duration: 100; } }
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter;
width: childrenRect.width;
height: childrenRect.height;
Label {
id: label
text: control.text.replace("&", "");
font: UM.Theme.fonts.button_tooltip;
color: UM.Theme.colors.button_tooltip_text;
}
}
}
UM.AngledCornerRectangle {
id: buttonFace;
anchors.fill: parent;
property bool down: control.pressed || (control.checkable && control.checked);
color: {
if(!control.enabled) {
return UM.Theme.colors.button_disabled;
} else if(control.checkable && control.checked && control.hovered) {
return UM.Theme.colors.button_active_hover;
} else if(control.pressed || (control.checkable && control.checked)) {
return UM.Theme.colors.button_active;
} else if(control.hovered) {
return UM.Theme.colors.button_hover;
} else {
return UM.Theme.colors.button;
}
}
Behavior on color { ColorAnimation { duration: 50; } }
cornerSize: UM.Theme.sizes.default_margin.width;
}
}
label: Item {
Image {
anchors.centerIn: parent;
source: control.iconSource;
width: UM.Theme.sizes.button_icon.width;
height: UM.Theme.sizes.button_icon.height;
sourceSize: UM.Theme.sizes.button_icon;
}
}
}
}
property Component progressbar: Component{
ProgressBarStyle {
background: UM.AngledCornerRectangle {
cornerSize: UM.Theme.sizes.progressbar_control.height
implicitWidth: UM.Theme.sizes.progressbar.width
implicitHeight: UM.Theme.sizes.progressbar.height
color: UM.Theme.colors.progressbar_background
}
progress: UM.AngledCornerRectangle {
cornerSize: UM.Theme.sizes.progressbar_control.height
color: control.indeterminate ? "transparent" : UM.Theme.colors.progressbar_control
UM.AngledCornerRectangle {
cornerSize: UM.Theme.sizes.progressbar_control.height
color: UM.Theme.colors.progressbar_control
width: UM.Theme.sizes.progressbar_control.width
height: UM.Theme.sizes.progressbar_control.height
visible: control.indeterminate
SequentialAnimation on x {
id: xAnim
property int animEndPoint: UM.Theme.sizes.progressbar.width - UM.Theme.sizes.progressbar_control.width
running: control.indeterminate
loops: Animation.Infinite
NumberAnimation { from: 0; to: xAnim.animEndPoint; duration: 2000;}
NumberAnimation { from: xAnim.animEndPoint; to: 0; duration: 2000;}
}
}
}
}
}
property Component sidebar_category: Component {
ButtonStyle {
background: UM.AngledCornerRectangle {
@ -121,6 +221,8 @@ QtObject {
Image {
anchors.verticalCenter: parent.verticalCenter;
source: control.iconSource;
width: UM.Theme.sizes.section_icon.width;
height: UM.Theme.sizes.section_icon.height;
}
Label {
@ -243,4 +345,32 @@ QtObject {
}
}
}
property Component text_field: Component {
TextFieldStyle {
textColor: UM.Theme.colors.setting_control_text;
font: UM.Theme.fonts.default;
background: Rectangle
{
implicitHeight: control.height;
implicitWidth: control.width;
border.width: 1;
border.color: UM.Theme.colors.setting_control_border;
color: UM.Theme.colors.setting_validation_ok;
Label {
anchors.right: parent.right;
anchors.rightMargin: UM.Theme.sizes.setting_unit_margin.width;
anchors.verticalCenter: parent.verticalCenter;
text: control.unit ? control.unit : ""
color: UM.Theme.colors.setting_unit;
font: UM.Theme.fonts.default;
}
}
}
}
}

View File

@ -27,6 +27,10 @@
"capitalize": true,
"family": "Roboto"
},
"sidebar_save_to": {
"size": 1.0,
"family": "Roboto"
},
"timeslider_time": {
"size": 1.0,
"bold": true,
@ -44,23 +48,26 @@
},
"colors": {
"sidebar": [255, 255, 255, 255],
"primary": [12, 169, 227, 255],
"primary_hover": [34, 150, 190, 255],
"primary_text": [255, 255, 255, 255],
"border": [205, 202, 201, 255],
"secondary": [205, 202, 201, 255],
"text": [174, 174, 174, 255],
"text_inactive": [205, 202, 201, 255],
"text": [140, 144, 154, 255],
"text_inactive": [174, 174, 174, 255],
"text_hover": [35, 35, 35, 255],
"text_pressed": [12, 169, 227, 255],
"button": [205, 202, 201, 255],
"button_hover": [174, 174, 174, 255],
"button": [160, 163, 171, 255],
"button_hover": [140, 144, 154, 255],
"button_active": [12, 169, 227, 255],
"button_active_hover": [34, 150, 190, 255],
"button_active_hover": [34, 150, 199, 255],
"button_text": [255, 255, 255, 255],
"button_disabled": [245, 245, 245, 255],
"button_tooltip_text": [35, 35, 35, 255],
"scrollbar_background": [245, 245, 245, 255],
"scrollbar_handle": [205, 202, 201, 255],
@ -74,7 +81,7 @@
"setting_category_active_hover": [34, 150, 190, 255],
"setting_category_text": [255, 255, 255, 255],
"setting_label": [174, 174, 174, 255],
"setting_label": [140, 144, 154, 255],
"setting_control": [255, 255, 255, 255],
"setting_control_highlight": [245, 245, 245, 255],
"setting_control_border": [174, 174, 174, 255],
@ -85,6 +92,9 @@
"setting_validation_warning": [255, 186, 15, 255],
"setting_validation_ok": [255, 255, 255, 255],
"progressbar_background": [245, 245, 245, 255],
"progressbar_control": [12, 169, 227, 255],
"slider_groove": [245, 245, 245, 255],
"slider_groove_border": [205, 202, 201, 255],
"slider_groove_fill": [205, 202, 201, 255],
@ -95,19 +105,24 @@
"checkbox_hover": [245, 245, 245, 255],
"checkbox_border": [174, 174, 174, 255],
"checkbox_mark": [35, 35, 35, 255],
"checkbox_text": [174, 174, 174, 255],
"checkbox_text": [140, 144, 154, 255],
"tooltip": [255, 225, 146, 255],
"save_button": [255, 255, 255, 255],
"save_button_border": [205, 202, 201, 255],
"save_button_inactive": [205, 202, 201, 255],
"save_button_active": [12, 159, 227, 255],
"save_button_active_hover": [34, 150, 190, 255],
"save_button_text": [35, 35, 35, 255],
"save_button_safe_to_text": [255, 255, 255, 255],
"save_button_estimated_text": [140, 144, 154, 255],
"save_button_estimated_text_background": [255, 255, 255, 255],
"save_button_printtime_text": [12, 169, 227, 255],
"save_button_background": [249, 249, 249, 255],
"message": [205, 202, 201, 255],
"message_text": [35, 35, 35, 255]
"message_text": [35, 35, 35, 255],
"tool_panel_background": [255, 255, 255, 255]
},
"sizes": {
@ -128,7 +143,11 @@
"setting_unit_margin": [0.5, 0.5],
"button": [4.25, 4.25],
"button_icon": [3.57, 3.57],
"button_icon": [2.9, 2.9],
"progressbar": [26.0, 0.5],
"progressbar_control": [8.0, 0.5],
"progressbar_padding": [0.0, 1.0],
"scrollbar": [0.5, 0.5],
@ -141,7 +160,10 @@
"tooltip_margins": [1.0, 1.0],
"save_button_border": [0.06, 0.06],
"save_button_text_margin": [0.6, 0.6],
"save_button_slicing_bar": [0.0, 2.2],
"save_button_label_margin": [0.5, 0.5],
"save_button_save_to_button": [0.3, 2.7],
"message": [30.0, 5.0],
"message_close": [1.25, 1.25]

View File

@ -22,7 +22,7 @@ def copytree(src, dst, symlinks=False, ignore=None):
else:
shutil.copy2(s, d)
includes = ["sip", "ctypes", "UM", "PyQt5.QtNetwork", "PyQt5._QOpenGLFunctions_2_0", "serial", "Arcus", "google", "google.protobuf", "google.protobuf.descriptor", "xml.etree", "xml.etree.ElementTree", "src"]
includes = ["sip", "ctypes", "UM", "PyQt5.QtNetwork", "PyQt5._QOpenGLFunctions_2_0", "serial", "Arcus", "google", "google.protobuf", "google.protobuf.descriptor", "xml.etree", "xml.etree.ElementTree", "cura"]
# Include all the UM modules in the includes. As py2exe fails to properly find all the dependencies due to the plugin architecture.
for dirpath, dirnames, filenames in os.walk(os.path.dirname(UM.__file__)):
if "__" in dirpath:
@ -41,20 +41,20 @@ print("Removing previous distribution package")
shutil.rmtree("dist", True)
setup(name="Cura",
version="2.0",
version="15.05.95",
author="Ultimaker",
author_email="d.braam@ultimaker.com",
url="http://software.ultimaker.com/",
license="GNU AFFERO GENERAL PUBLIC LICENSE (AGPL)",
scripts=["cura_app.py"],
#windows=[{"script": "printer.py", "dest_name": "Cura"}],
console=[{"script": "cura_app.py"}],
windows=[{"script": "cura_app.py", "dest_name": "Cura", "icon_resources": [(1, "icons/cura.ico")]}],
#console=[{"script": "cura_app.py"}],
options={"py2exe": {"skip_archive": False, "includes": includes}})
print("Coping Cura plugins.")
shutil.copytree(os.path.dirname(UM.__file__) + "/../plugins", "dist/plugins")
shutil.copytree(os.path.dirname(UM.__file__) + "/../plugins", "dist/plugins", ignore = shutil.ignore_patterns("ConsoleLogger", "OBJWriter", "MLPWriter", "MLPReader"))
for path in os.listdir("plugins"):
shutil.copytree("plugins/" + path, "dist/plugins/" + path)
shutil.copytree("plugins/" + path, "dist/plugins/" + path)
print("Coping resources.")
shutil.copytree(os.path.dirname(UM.__file__) + "/../resources", "dist/resources")
copytree("resources", "dist/resources")
@ -70,3 +70,7 @@ for site_package in site.getsitepackages():
shutil.copytree(os.path.join(qt_origin_path, "qml/QtQuick.2"), "dist/qml/QtQuick.2")
print("Coping PyQt5 svg library from: %s" % qt_origin_path)
shutil.copy(os.path.join(qt_origin_path, "Qt5Svg.dll"), "dist/Qt5Svg.dll")
print("Copying Angle libraries from %s" % qt_origin_path)
shutil.copy(os.path.join(qt_origin_path, "libEGL.dll"), "dist/libEGL.dll")
shutil.copy(os.path.join(qt_origin_path, "libGLESv2.dll"), "dist/libGLESv2.dll")
os.rename("dist/cura_app.exe", "dist/Cura.exe")