mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-21 21:58:01 -06:00
Merge branch 'main' into CURA-9221_show_message_cloud_approval
This commit is contained in:
commit
9b20a1b37f
26 changed files with 639 additions and 172 deletions
2
.github/workflows/conan-package-create.yml
vendored
2
.github/workflows/conan-package-create.yml
vendored
|
@ -149,5 +149,5 @@ jobs:
|
|||
run: conan upload "*" -r cura --all -c
|
||||
|
||||
- name: Upload the Package(s) community
|
||||
if: ${{ always() && inputs.conan_upload_community == 'true' }}
|
||||
if: ${{ always() && inputs.conan_upload_community == true }}
|
||||
run: conan upload "*" -r cura-ce -c
|
||||
|
|
2
.github/workflows/conan-recipe-export.yml
vendored
2
.github/workflows/conan-recipe-export.yml
vendored
|
@ -102,5 +102,5 @@ jobs:
|
|||
run: conan upload "*" -r cura --all -c
|
||||
|
||||
- name: Upload the Package(s) community
|
||||
if: ${{ always() && inputs.conan_upload_community == 'true' }}
|
||||
if: ${{ always() && inputs.conan_upload_community == true }}
|
||||
run: conan upload "*" -r cura-ce -c
|
||||
|
|
3
.github/workflows/conan-recipe-version.yml
vendored
3
.github/workflows/conan-recipe-version.yml
vendored
|
@ -135,6 +135,9 @@ jobs:
|
|||
user = "_"
|
||||
channel = "_"
|
||||
else:
|
||||
if latest_branch_version.prerelease and not "." in latest_branch_version.prerelease:
|
||||
# The prerealese did not contain a version number, default it to 1
|
||||
latest_branch_version.prerelease += ".1"
|
||||
if event_name == "pull_request":
|
||||
actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{latest_branch_version.patch}-{latest_branch_version.prerelease.lower()}+{buildmetadata}pr_{issue_number}_{no_commits}"
|
||||
else:
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
conan!=1.51.0,!=1.51.1
|
||||
sip==6.5.1
|
||||
conan!=1.51.0,!=1.51.1,!=1.51.2,!=1.51.3
|
||||
sip
|
||||
|
|
25
.run_templates/pycharm_cura_run.run.xml.jinja
Normal file
25
.run_templates/pycharm_cura_run.run.xml.jinja
Normal file
|
@ -0,0 +1,25 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="{{ name }}" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
|
||||
<module name="{{ module_name }}" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />{% for key, value in env_vars.items() %}
|
||||
<env name="{{ key }}" value="{{ value }}" />{% endfor %}
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="{{ sdk_path }}" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/{{ script_name }}" />
|
||||
<option name="PARAMETERS" value="{{ parameters }}" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
23
.run_templates/pycharm_cura_test.run.xml.jinja
Normal file
23
.run_templates/pycharm_cura_test.run.xml.jinja
Normal file
|
@ -0,0 +1,23 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="{{ name }}" type="tests" factoryName="py.test" nameIsGenerated="true">
|
||||
<module name="{{ module_name }}" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />{% for key, value in env_vars.items() %}
|
||||
<env name="{{ key }}" value="{{ value }}" />{% endfor %}
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="{{ sdk_path }}" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/tests" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<option name="_new_keywords" value="""" />
|
||||
<option name="_new_parameters" value="""" />
|
||||
<option name="_new_additionalArguments" value="""" />
|
||||
<option name="_new_target" value=""$PROJECT_DIR$/{{ script_name }}"" />
|
||||
<option name="_new_targetType" value=""PATH"" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
|
@ -11,3 +11,4 @@ CuraCloudAPIVersion = "{{ cura_cloud_api_version }}"
|
|||
CuraCloudAccountAPIRoot = "{{ cura_cloud_account_api_root }}"
|
||||
CuraMarketplaceRoot = "{{ cura_marketplace_root }}"
|
||||
CuraDigitalFactoryURL = "{{ cura_digital_factory_url }}"
|
||||
CuraLatestURL = "{{ cura_latest_url }}"
|
||||
|
|
132
README.md
132
README.md
|
@ -1,64 +1,96 @@
|
|||
# Cura
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/Ultimaker/Cura/actions/workflows/unit-test.yml" alt="Unit Tests">
|
||||
<img src="https://github.com/Ultimaker/Cura/actions/workflows/unit-test.yml/badge.svg" /></a>
|
||||
<a href="https://github.com/Ultimaker/Cura/actions/workflows/conan-package.yml" alt="Unit Tests">
|
||||
<img src="https://github.com/Ultimaker/Cura/actions/workflows/conan-package.yml/badge.svg" /></a>
|
||||
<a href="https://github.com/Ultimaker/Cura/issues" alt="Open Issues">
|
||||
<img src="https://img.shields.io/github/issues/ultimaker/cura" /></a>
|
||||
<a href="https://github.com/Ultimaker/Cura/issues?q=is%3Aissue+is%3Aclosed" alt="Closed Issues">
|
||||
<img src="https://img.shields.io/github/issues-closed/ultimaker/cura?color=g" /></a>
|
||||
<a href="https://github.com/Ultimaker/Cura/pulls" alt="Pull Requests">
|
||||
<img src="https://img.shields.io/github/issues-pr/ultimaker/cura" /></a>
|
||||
<a href="https://github.com/Ultimaker/Cura/graphs/contributors" alt="Contributors">
|
||||
<img src="https://img.shields.io/github/contributors/ultimaker/cura" /></a>
|
||||
<a href="https://github.com/Ultimaker/Cura" alt="Repo Size">
|
||||
<img src="https://img.shields.io/github/repo-size/ultimaker/cura?style=flat" /></a>
|
||||
<a href="https://github.com/Ultimaker/Cura/blob/master/LICENSE" alt="License">
|
||||
<img src="https://img.shields.io/github/license/ultimaker/cura?style=flat" /></a>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
Ultimaker Cura is a state-of-the-art slicer application to prepare your 3D models for printing with a 3D printer. With hundreds of settings
|
||||
and hundreds of community-managed print profiles, Ultimaker Cura is sure to lead your next project to a success.
|
||||
<div align = center>
|
||||
|
||||

|
||||
[![Badge Issues]][Issues]
|
||||
[![Badge PullRequests]][PullRequests]
|
||||
[![Badge Closed]][Closed]
|
||||
|
||||
## Logging Issues
|
||||
[![Badge Size]][#]
|
||||
[![Badge License]][License]
|
||||
[![Badge Contributors]][Contributors]
|
||||
|
||||
For crashes and similar issues, please attach the following information:
|
||||
[![Badge Test]][Test]
|
||||
[![Badge Conan]][Conan]
|
||||
|
||||
* (On Windows) The log as produced by dxdiag (start -> run -> dxdiag -> save output)
|
||||
* The Cura GUI log file, located at
|
||||
* `%APPDATA%\cura\<Cura version>\cura.log` (Windows), or usually `C:\Users\<your username>\AppData\Roaming\cura\<Cura version>\cura.log`
|
||||
* `$HOME/Library/Application Support/cura/<Cura version>/cura.log` (OSX)
|
||||
* `$HOME/.local/share/cura/<Cura version>/cura.log` (Ubuntu/Linux)
|
||||
<br>
|
||||
<br>
|
||||
|
||||
If the Cura user interface still starts, you can also reach this directory from the application menu in Help -> Show settings folder.
|
||||
An alternative is to install the [ExtensiveSupportLogging plugin](https://marketplace.ultimaker.com/app/cura/plugins/UltimakerPackages/ExtensiveSupportLogging)
|
||||
this creates a zip folder of the relevant log files. If you're experiencing performance issues, we might ask you to connect the CPU profiler
|
||||
in this plugin and attach the collected data to your support ticket.
|
||||
![Logo]
|
||||
|
||||
## Running from Source
|
||||
Please check our [Wiki page](https://github.com/Ultimaker/Cura/wiki/Running-Cura-from-Source) for details about running Cura from source.
|
||||
# Ultimaker Cura
|
||||
|
||||
## Plugins
|
||||
Please check our [Wiki page](https://github.com/Ultimaker/Cura/wiki/Plugin-Directory) for details about creating and using plugins.
|
||||
*State-of-the-art slicer app to prepare* <br>
|
||||
*your 3D models for your 3D printer.*
|
||||
|
||||
## Supported printers
|
||||
Please check our [Wiki page](https://github.com/Ultimaker/Cura/wiki/Adding-new-machine-profiles-to-Cura) for guidelines about adding support
|
||||
for new machines.
|
||||
*With hundreds of settings & community-managed print profiles,* <br>
|
||||
*Ultimaker Cura is sure to lead your next project to a success.*
|
||||
|
||||
## Configuring Cura
|
||||
Please check out [Wiki page](https://github.com/Ultimaker/Cura/wiki/Cura-Settings) about configuration options for developers.
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Translating Cura
|
||||
Please check out [Wiki page](https://github.com/Ultimaker/Cura/wiki/Translating-Cura) about how to translate Cura into other languages.
|
||||
[![Button Building]][Building]
|
||||
[![Button Plugins]][Plugins]
|
||||
[![Button Machines]][Machines]
|
||||
|
||||
[![Button Report]][Report]
|
||||
[![Button Settings]][Settings]
|
||||
[![Button Localize]][Localize]
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: light)" srcset="./cura-logo.PNG">
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./cura-logo-dark.PNG">
|
||||
<img alt="Shows cura open on the preview screen with a large benchy model in the center." src="./cura-logo.PNG">
|
||||
</picture>
|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
<!----------------------------------------------------------------------------->
|
||||
|
||||
[Contributors]: https://github.com/Ultimaker/Cura/graphs/contributors
|
||||
[PullRequests]: https://github.com/Ultimaker/Cura/pulls
|
||||
[Machines]: https://github.com/Ultimaker/Cura/wiki/Adding-new-machine-profiles-to-Cura
|
||||
[Building]: https://github.com/Ultimaker/Cura/wiki/Running-Cura-from-Source
|
||||
[Localize]: https://github.com/Ultimaker/Cura/wiki/Translating-Cura
|
||||
[Settings]: https://github.com/Ultimaker/Cura/wiki/Cura-Settings
|
||||
[Plugins]: https://github.com/Ultimaker/Cura/wiki/Plugin-Directory
|
||||
[Closed]: https://github.com/Ultimaker/Cura/issues?q=is%3Aissue+is%3Aclosed
|
||||
[Issues]: https://github.com/Ultimaker/Cura/issues
|
||||
[Conan]: https://github.com/Ultimaker/Cura/actions/workflows/conan-package.yml
|
||||
[Test]: https://github.com/Ultimaker/Cura/actions/workflows/unit-test.yml
|
||||
|
||||
[License]: LICENSE
|
||||
[Report]: docs/Report.md
|
||||
[Logo]: resources/images/cura-icon.png
|
||||
[#]: #
|
||||
|
||||
|
||||
<!---------------------------------[ Badges ]---------------------------------->
|
||||
|
||||
[Badge Contributors]: https://img.shields.io/github/contributors/ultimaker/cura?style=for-the-badge&logoColor=white&labelColor=db5e8a&color=ab4a6c&logo=GitHub
|
||||
[Badge PullRequests]: https://img.shields.io/github/issues-pr/ultimaker/cura?style=for-the-badge&logoColor=white&labelColor=bb9f3e&color=937d31&logo=GitExtensions
|
||||
[Badge License]: https://img.shields.io/badge/License-LGPL3-336887.svg?style=for-the-badge&labelColor=458cb5&logoColor=white&logo=GNU
|
||||
[Badge Closed]: https://img.shields.io/github/issues-closed/ultimaker/cura?style=for-the-badge&logoColor=white&labelColor=629944&color=446a30&logo=AddThis
|
||||
[Badge Issues]: https://img.shields.io/github/issues/ultimaker/cura?style=for-the-badge&logoColor=white&labelColor=c34360&color=933349&logo=AdBlock
|
||||
[Badge Conan]: https://img.shields.io/github/workflow/status/Ultimaker/Cura/conan-package?style=for-the-badge&logoColor=white&labelColor=6185aa&color=4c6987&logo=Conan&label=Conan%20Package
|
||||
[Badge Test]: https://img.shields.io/github/workflow/status/Ultimaker/Cura/unit-test?style=for-the-badge&logoColor=white&labelColor=4a999d&color=346c6e&logo=Codacy&label=Unit%20Test
|
||||
[Badge Size]: https://img.shields.io/github/repo-size/ultimaker/cura?style=for-the-badge&logoColor=white&labelColor=715a97&color=584674&logo=GoogleAnalytics
|
||||
|
||||
|
||||
<!---------------------------------[ Buttons ]--------------------------------->
|
||||
|
||||
[Button Localize]: https://img.shields.io/badge/Help_Localize-e2467d?style=for-the-badge&logoColor=white&logo=GoogleTranslate
|
||||
[Button Machines]: https://img.shields.io/badge/Adding_Machines-yellow?style=for-the-badge&logoColor=white&logo=CloudFoundry
|
||||
[Button Settings]: https://img.shields.io/badge/Configuration-00979D?style=for-the-badge&logoColor=white&logo=CodeReview
|
||||
[Button Building]: https://img.shields.io/badge/Building_Cura-blue?style=for-the-badge&logoColor=white&logo=GitBook
|
||||
[Button Plugins]: https://img.shields.io/badge/Plugin_Usage-569A31?style=for-the-badge&logoColor=white&logo=ROS
|
||||
[Button Report]: https://img.shields.io/badge/Report_Issues-C9284D?style=for-the-badge&logoColor=white&logo=Cliqz
|
||||
|
||||
## License
|
||||

|
||||
Cura is released under terms of the LGPLv3 or higher. A copy of this license should be included with the software. Terms of the license can be found in the LICENSE file. Or at
|
||||
http://www.gnu.org/licenses/lgpl.html
|
||||
|
||||
> But in general it boils down to:
|
||||
> **You need to share the source of any Cura modifications**
|
||||
|
|
136
conandata.yml
136
conandata.yml
|
@ -20,6 +20,9 @@
|
|||
- "fdm_materials/(latest)@ultimaker/testing"
|
||||
- "cura_binary_data/(latest)@ultimaker/testing"
|
||||
- "cpython/3.10.4"
|
||||
internal_requirements:
|
||||
- "fdm_materials_private/(latest)@ultimaker/testing"
|
||||
- "cura_private_data/(latest)@ultimaker/testing"
|
||||
runinfo:
|
||||
entrypoint: "cura_app.py"
|
||||
pyinstaller:
|
||||
|
@ -32,6 +35,11 @@
|
|||
package: "cura"
|
||||
src: "resources"
|
||||
dst: "share/cura/resources"
|
||||
cura_private_data:
|
||||
package: "cura_private_data"
|
||||
src: "resources"
|
||||
dst: "share/cura/resources"
|
||||
internal: true
|
||||
uranium_plugins:
|
||||
package: "uranium"
|
||||
src: "plugins"
|
||||
|
@ -60,6 +68,11 @@
|
|||
package: "fdm_materials"
|
||||
src: "materials"
|
||||
dst: "share/cura/resources/materials"
|
||||
fdm_materials_private:
|
||||
package: "fdm_materials_private"
|
||||
src: "resources/materials"
|
||||
dst: "share/cura/resources/materials"
|
||||
internal: true
|
||||
tcl:
|
||||
package: "tcl"
|
||||
src: "lib/tcl8.6"
|
||||
|
@ -112,6 +125,9 @@
|
|||
- "fdm_materials/(latest)@ultimaker/testing"
|
||||
- "cura_binary_data/(latest)@ultimaker/testing"
|
||||
- "cpython/3.10.4"
|
||||
internal_requirements:
|
||||
- "fdm_materials_private/(latest)@ultimaker/testing"
|
||||
- "cura_private_data/(latest)@ultimaker/testing"
|
||||
runinfo:
|
||||
entrypoint: "cura_app.py"
|
||||
pyinstaller:
|
||||
|
@ -124,6 +140,11 @@
|
|||
package: "cura"
|
||||
src: "resources"
|
||||
dst: "share/cura/resources"
|
||||
cura_private_data:
|
||||
package: "cura_private_data"
|
||||
src: "resources"
|
||||
dst: "share/cura/resources"
|
||||
internal: true
|
||||
uranium_plugins:
|
||||
package: "uranium"
|
||||
src: "plugins"
|
||||
|
@ -152,6 +173,11 @@
|
|||
package: "fdm_materials"
|
||||
src: "materials"
|
||||
dst: "share/cura/resources/materials"
|
||||
fdm_materials_private:
|
||||
package: "fdm_materials_private"
|
||||
src: "resources/materials"
|
||||
dst: "share/cura/resources/materials"
|
||||
internal: true
|
||||
tcl:
|
||||
package: "tcl"
|
||||
src: "lib/tcl8.6"
|
||||
|
@ -286,3 +312,113 @@
|
|||
Windows: "./icons/Cura.ico"
|
||||
Macos: "./icons/cura.icns"
|
||||
Linux: "./icons/cura-128.png"
|
||||
pycharm_targets:
|
||||
- jinja_path: .run_templates/pycharm_cura_run.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: cura
|
||||
script_name: cura_app.py
|
||||
- jinja_path: .run_templates/pycharm_cura_run.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: cura_external_engine
|
||||
parameters: --external-backend
|
||||
script_name: cura_app.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in tests
|
||||
script_name: tests/
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestBuildVolume.py
|
||||
script_name: tests/TestBuildVolume.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestConvexHullDecorator.py
|
||||
script_name: tests/TestConvexHullDecorator.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestCuraSceneNode.py
|
||||
script_name: tests/TestCuraSceneNode.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestCuraSceneNode.py
|
||||
script_name: tests/TestExtruderManager.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestGCodeListDecorator.py
|
||||
script_name: tests/TestGCodeListDecorator.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestIntentManager.py
|
||||
script_name: tests/TestIntentManager.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestLayer.py
|
||||
script_name: tests/TestLayer.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestMachineAction.py
|
||||
script_name: tests/TestMachineAction.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestMachineManager.py
|
||||
script_name: tests/TestMachineManager.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestOAuth2.py
|
||||
script_name: tests/TestOAuth2.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestObjectsModel.py
|
||||
script_name: tests/TestObjectsModel.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestPrintInformation.py
|
||||
script_name: tests/TestPrintInformation.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestProfileRequirements.py
|
||||
script_name: tests/TestProfileRequirements.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestThemes.py
|
||||
script_name: tests/TestThemes.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestContainerManager.py
|
||||
script_name: tests/Settings/TestContainerManager.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestCuraContainerRegistry.py
|
||||
script_name: tests/Settings/TestCuraContainerRegistry.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestCuraStackBuilder.py
|
||||
script_name: tests/Settings/TestCuraStackBuilder.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestDefinitionContainer.py
|
||||
script_name: tests/Settings/TestDefinitionContainer.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestExtruderStack.py
|
||||
script_name: tests/Settings/TestExtruderStack.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestGlobalStack.py
|
||||
script_name: tests/Settings/TestGlobalStack.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestProfiles.py
|
||||
script_name: tests/Settings/TestProfiles.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestSettingInheritanceManager.py
|
||||
script_name: tests/Settings/TestSettingInheritanceManager.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestSettingOverrideDecorator.py
|
||||
script_name: tests/Settings/TestSettingOverrideDecorator.py
|
||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||
module_name: Cura
|
||||
name: pytest in TestSettingVisibilityPresets.py
|
||||
script_name: tests/Settings/TestSettingVisibilityPresets.py
|
||||
|
|
54
conanfile.py
54
conanfile.py
|
@ -1,11 +1,6 @@
|
|||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from io import StringIO
|
||||
|
||||
from platform import python_version
|
||||
|
||||
from jinja2 import Template
|
||||
|
||||
from conans import tools
|
||||
|
@ -14,7 +9,7 @@ from conan.tools import files
|
|||
from conan.tools.env import VirtualRunEnv, Environment
|
||||
from conan.errors import ConanInvalidConfiguration
|
||||
|
||||
required_conan_version = ">=1.47.0"
|
||||
required_conan_version = ">=1.48.0"
|
||||
|
||||
|
||||
class CuraConan(ConanFile):
|
||||
|
@ -59,18 +54,9 @@ class CuraConan(ConanFile):
|
|||
"revision": "auto"
|
||||
}
|
||||
|
||||
# TODO: Add unit tests (but they need a different jinja template
|
||||
_pycharm_targets = [{
|
||||
"name": "cura",
|
||||
"module_name": "Cura",
|
||||
"script_name": "cura_app.py",
|
||||
}, {
|
||||
"name": "cura_external_engine",
|
||||
"module_name": "Cura",
|
||||
"script_name": "cura_app.py",
|
||||
"parameters": "--external-backend"
|
||||
}
|
||||
]
|
||||
@property
|
||||
def _pycharm_targets(self):
|
||||
return self.conan_data["pycharm_targets"]
|
||||
|
||||
# FIXME: These env vars should be defined in the runenv.
|
||||
_cura_env = None
|
||||
|
@ -114,6 +100,10 @@ class CuraConan(ConanFile):
|
|||
def _digital_factory_url(self):
|
||||
return "https://digitalfactory-staging.ultimaker.com" if self._staging else "https://digitalfactory.ultimaker.com"
|
||||
|
||||
@property
|
||||
def _cura_latest_url(self):
|
||||
return "https://software.ultimaker.com/latest.json"
|
||||
|
||||
@property
|
||||
def requirements_txts(self):
|
||||
if self.options.devtools:
|
||||
|
@ -175,12 +165,16 @@ class CuraConan(ConanFile):
|
|||
cura_cloud_api_version = self.options.cloud_api_version,
|
||||
cura_cloud_account_api_root = self._cloud_account_api_root,
|
||||
cura_marketplace_root = self._marketplace_root,
|
||||
cura_digital_factory_url = self._digital_factory_url))
|
||||
cura_digital_factory_url = self._digital_factory_url,
|
||||
cura_latest_url = self._cura_latest_url))
|
||||
|
||||
def _generate_pyinstaller_spec(self, location, entrypoint_location, icon_path, entitlements_file):
|
||||
pyinstaller_metadata = self._um_data()["pyinstaller"]
|
||||
datas = [(str(self._base_dir.joinpath("conan_install_info.json")), ".")]
|
||||
for data in pyinstaller_metadata["datas"].values():
|
||||
if not self.options.internal and data.get("internal", False):
|
||||
continue
|
||||
|
||||
if "package" in data: # get the paths from conan package
|
||||
if data["package"] == self.name:
|
||||
if self.in_local_cache:
|
||||
|
@ -262,6 +256,9 @@ class CuraConan(ConanFile):
|
|||
def requirements(self):
|
||||
for req in self._um_data()["requirements"]:
|
||||
self.requires(req)
|
||||
if self.options.internal:
|
||||
for req in self._um_data()["internal_requirements"]:
|
||||
self.requires(req)
|
||||
|
||||
def layout(self):
|
||||
self.folders.source = "."
|
||||
|
@ -300,11 +297,17 @@ class CuraConan(ConanFile):
|
|||
self.copy("*.fdm_material", root_package = "fdm_materials", src = "@resdirs", dst = "resources/materials", keep_path = False)
|
||||
self.copy("*.sig", root_package = "fdm_materials", src = "@resdirs", dst = "resources/materials", keep_path = False)
|
||||
|
||||
if self.options.internal:
|
||||
self.copy("*.fdm_material", root_package = "fdm_materials_private", src = "@resdirs", dst = "resources/materials", keep_path = False)
|
||||
self.copy("*.sig", root_package = "fdm_materials_private", src = "@resdirs", dst = "resources/materials", keep_path = False)
|
||||
self.copy("*", root_package = "cura_private_data", src = self.deps_cpp_info["cura_private_data"].resdirs[0],
|
||||
dst = self._share_dir.joinpath("cura", "resources"), keep_path = True)
|
||||
|
||||
# Copy resources of cura_binary_data
|
||||
self.copy("*", root_package = "cura_binary_data", src = self.deps_cpp_info["cura_binary_data"].resdirs[0],
|
||||
dst = "venv/share/cura", keep_path = True)
|
||||
dst = self._share_dir.joinpath("cura", "resources"), keep_path = True)
|
||||
self.copy("*", root_package = "cura_binary_data", src = self.deps_cpp_info["cura_binary_data"].resdirs[1],
|
||||
dst = "venv/share/uranium", keep_path = True)
|
||||
dst =self._share_dir.joinpath("uranium", "resources"), keep_path = True)
|
||||
|
||||
self.copy("*.dll", src = "@bindirs", dst = self._site_packages)
|
||||
self.copy("*.pyd", src = "@libdirs", dst = self._site_packages)
|
||||
|
@ -332,6 +335,15 @@ class CuraConan(ConanFile):
|
|||
self.copy_deps("*.sig", root_package = "fdm_materials", src = self.deps_cpp_info["fdm_materials"].resdirs[0],
|
||||
dst = self._share_dir.joinpath("cura", "resources", "materials"), keep_path = False)
|
||||
|
||||
# Copy internal resources
|
||||
if self.options.internal:
|
||||
self.copy_deps("*.fdm_material", root_package = "fdm_materials_private", src = self.deps_cpp_info["fdm_materials_private"].resdirs[0],
|
||||
dst = self._share_dir.joinpath("cura", "resources", "materials"), keep_path = False)
|
||||
self.copy_deps("*.sig", root_package = "fdm_materials_private", src = self.deps_cpp_info["fdm_materials_private"].resdirs[0],
|
||||
dst = self._share_dir.joinpath("cura", "resources", "materials"), keep_path = False)
|
||||
self.copy_deps("*", root_package = "cura_private_data", src = self.deps_cpp_info["cura_private_data"].resdirs[0],
|
||||
dst = self._share_dir.joinpath("cura", "resources"), keep_path = True)
|
||||
|
||||
# Copy resources of Uranium (keep folder structure)
|
||||
self.copy_deps("*", root_package = "uranium", src = self.deps_cpp_info["uranium"].resdirs[0],
|
||||
dst = self._share_dir.joinpath("uranium", "resources"), keep_path = True)
|
||||
|
|
BIN
cura-logo-dark.PNG
Normal file
BIN
cura-logo-dark.PNG
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 MiB |
BIN
cura-logo.PNG
BIN
cura-logo.PNG
Binary file not shown.
Before Width: | Height: | Size: 520 KiB After Width: | Height: | Size: 1 MiB |
|
@ -9,12 +9,20 @@ DEFAULT_CURA_DISPLAY_NAME = "Ultimaker Cura"
|
|||
DEFAULT_CURA_VERSION = "dev"
|
||||
DEFAULT_CURA_BUILD_TYPE = ""
|
||||
DEFAULT_CURA_DEBUG_MODE = False
|
||||
DEFAULT_CURA_LATEST_URL = "https://software.ultimaker.com/latest.json"
|
||||
|
||||
# Each release has a fixed SDK version coupled with it. It doesn't make sense to make it configurable because, for
|
||||
# example Cura 3.2 with SDK version 6.1 will not work. So the SDK version is hard-coded here and left out of the
|
||||
# CuraVersion.py.in template.
|
||||
CuraSDKVersion = "8.1.0"
|
||||
|
||||
try:
|
||||
from cura.CuraVersion import CuraLatestURL
|
||||
if CuraLatestURL == "":
|
||||
CuraLatestURL = DEFAULT_CURA_LATEST_URL
|
||||
except ImportError:
|
||||
CuraLatestURL = DEFAULT_CURA_LATEST_URL
|
||||
|
||||
try:
|
||||
from cura.CuraVersion import CuraAppName # type: ignore
|
||||
if CuraAppName == "":
|
||||
|
|
|
@ -145,6 +145,8 @@ class CuraApplication(QtApplication):
|
|||
DefinitionChangesContainer = Resources.UserType + 10
|
||||
SettingVisibilityPreset = Resources.UserType + 11
|
||||
IntentInstanceContainer = Resources.UserType + 12
|
||||
AbstractMachineStack = Resources.UserType + 13
|
||||
|
||||
|
||||
pyqtEnum(ResourceTypes)
|
||||
|
||||
|
@ -152,6 +154,7 @@ class CuraApplication(QtApplication):
|
|||
super().__init__(name = ApplicationMetadata.CuraAppName,
|
||||
app_display_name = ApplicationMetadata.CuraAppDisplayName,
|
||||
version = ApplicationMetadata.CuraVersion if not ApplicationMetadata.IsAlternateVersion else ApplicationMetadata.CuraBuildType,
|
||||
latest_url = ApplicationMetadata.CuraLatestURL,
|
||||
api_version = ApplicationMetadata.CuraSDKVersion,
|
||||
build_type = ApplicationMetadata.CuraBuildType,
|
||||
is_debug_mode = ApplicationMetadata.CuraDebugMode,
|
||||
|
@ -422,6 +425,7 @@ class CuraApplication(QtApplication):
|
|||
Resources.addStorageType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
|
||||
Resources.addStorageType(self.ResourceTypes.SettingVisibilityPreset, "setting_visibility")
|
||||
Resources.addStorageType(self.ResourceTypes.IntentInstanceContainer, "intent")
|
||||
Resources.addStorageType(self.ResourceTypes.AbstractMachineStack, "abstract_machine_instances")
|
||||
|
||||
self._container_registry.addResourceType(self.ResourceTypes.QualityInstanceContainer, "quality")
|
||||
self._container_registry.addResourceType(self.ResourceTypes.QualityChangesInstanceContainer, "quality_changes")
|
||||
|
@ -432,6 +436,7 @@ class CuraApplication(QtApplication):
|
|||
self._container_registry.addResourceType(self.ResourceTypes.MachineStack, "machine")
|
||||
self._container_registry.addResourceType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
|
||||
self._container_registry.addResourceType(self.ResourceTypes.IntentInstanceContainer, "intent")
|
||||
self._container_registry.addResourceType(self.ResourceTypes.AbstractMachineStack, "abstract_machine")
|
||||
|
||||
Resources.addType(self.ResourceTypes.QmlFiles, "qml")
|
||||
Resources.addType(self.ResourceTypes.Firmware, "firmware")
|
||||
|
@ -480,6 +485,7 @@ class CuraApplication(QtApplication):
|
|||
("variant", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.VariantInstanceContainer, "application/x-uranium-instancecontainer"),
|
||||
("setting_visibility", SettingVisibilityPresetsModel.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.SettingVisibilityPreset, "application/x-uranium-preferences"),
|
||||
("machine", 2): (Resources.DefinitionContainers, "application/x-uranium-definitioncontainer"),
|
||||
("abstract_machine", 1): (Resources.DefinitionContainers, "application/x-uranium-definitioncontainer"),
|
||||
("extruder", 2): (Resources.DefinitionContainers, "application/x-uranium-definitioncontainer")
|
||||
}
|
||||
)
|
||||
|
|
|
@ -45,11 +45,7 @@ class MachineErrorChecker(QObject):
|
|||
|
||||
self._start_time = 0. # measure checking time
|
||||
|
||||
# This timer delays the starting of error check so we can react less frequently if the user is frequently
|
||||
# changing settings.
|
||||
self._error_check_timer = QTimer(self)
|
||||
self._error_check_timer.setInterval(100)
|
||||
self._error_check_timer.setSingleShot(True)
|
||||
self._setCheckTimer()
|
||||
|
||||
self._keys_to_check = set() # type: Set[str]
|
||||
|
||||
|
@ -66,6 +62,18 @@ class MachineErrorChecker(QObject):
|
|||
|
||||
self._onMachineChanged()
|
||||
|
||||
def _setCheckTimer(self) -> None:
|
||||
"""A QTimer to regulate error check frequency
|
||||
|
||||
This timer delays the starting of error check
|
||||
so we can react less frequently if the user is frequently
|
||||
changing settings.
|
||||
"""
|
||||
|
||||
self._error_check_timer = QTimer(self)
|
||||
self._error_check_timer.setInterval(100)
|
||||
self._error_check_timer.setSingleShot(True)
|
||||
|
||||
def _onMachineChanged(self) -> None:
|
||||
if self._global_stack:
|
||||
self._global_stack.propertyChanged.disconnect(self.startErrorCheckPropertyChanged)
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class Peripheral:
|
||||
"""Data class that represents a peripheral for a printer.
|
||||
|
||||
Output device plug-ins may specify that the printer has a certain set of
|
||||
peripherals. This set is then possibly shown in the interface of the monitor
|
||||
stage.
|
||||
"""
|
||||
|
||||
def __init__(self, peripheral_type: str, name: str) -> None:
|
||||
"""Constructs the peripheral.
|
||||
|
||||
:param peripheral_type: A unique ID for the type of peripheral.
|
||||
:param name: A human-readable name for the peripheral.
|
||||
Args:
|
||||
type (string): A unique ID for the type of peripheral.
|
||||
name (string): A human-readable name for the peripheral.
|
||||
"""
|
||||
self.type = peripheral_type
|
||||
self.name = name
|
||||
type: str
|
||||
name: str
|
||||
|
|
35
cura/Settings/AbstractMachine.py
Normal file
35
cura/Settings/AbstractMachine.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
from typing import List
|
||||
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
||||
from cura.Settings.GlobalStack import GlobalStack
|
||||
from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
|
||||
|
||||
class AbstractMachine(GlobalStack):
|
||||
""" Represents a group of machines of the same type. This allows the user to select settings before selecting a printer. """
|
||||
|
||||
def __init__(self, container_id: str) -> None:
|
||||
super().__init__(container_id)
|
||||
self.setMetaDataEntry("type", "abstract_machine")
|
||||
|
||||
def getMachines(self) -> List[ContainerStack]:
|
||||
from cura.CuraApplication import CuraApplication
|
||||
|
||||
application = CuraApplication.getInstance()
|
||||
registry = application.getContainerRegistry()
|
||||
|
||||
printer_type = self.definition.getId()
|
||||
return [machine for machine in registry.findContainerStacks(type="machine") if machine.definition.id == printer_type and ConnectionType.CloudConnection in machine.configuredConnectionTypes]
|
||||
|
||||
|
||||
## private:
|
||||
_abstract_machine_mime = MimeType(
|
||||
name = "application/x-cura-abstract-machine",
|
||||
comment = "Cura Abstract Machine",
|
||||
suffixes = ["global.cfg"]
|
||||
)
|
||||
|
||||
MimeTypeDatabase.addMimeType(_abstract_machine_mime)
|
||||
ContainerRegistry.addContainerTypeByName(AbstractMachine, "abstract_machine", _abstract_machine_mime.name)
|
|
@ -108,7 +108,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||
:param container_type: :type{string} Type of the container (machine, quality, ...)
|
||||
:param container_name: :type{string} Name to check
|
||||
"""
|
||||
container_class = ContainerStack if container_type == "machine" else InstanceContainer
|
||||
container_class = ContainerStack if "machine" in container_type else InstanceContainer
|
||||
|
||||
return self.findContainersMetadata(container_type = container_class, id = container_name, type = container_type, ignore_case = True) or \
|
||||
self.findContainersMetadata(container_type = container_class, name = container_name, type = container_type)
|
||||
|
|
|
@ -427,4 +427,4 @@ class _ContainerIndexes:
|
|||
}
|
||||
|
||||
# Reverse lookup: type -> index
|
||||
TypeIndexMap = dict([(v, k) for k, v in IndexTypeMap.items()])
|
||||
TypeIndexMap = {v: k for k, v in IndexTypeMap.items()}
|
||||
|
|
|
@ -9,6 +9,7 @@ from UM.Settings.Interfaces import DefinitionContainerInterface
|
|||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
|
||||
from cura.Machines.ContainerTree import ContainerTree
|
||||
from .AbstractMachine import AbstractMachine
|
||||
from .GlobalStack import GlobalStack
|
||||
from .ExtruderStack import ExtruderStack
|
||||
|
||||
|
@ -27,7 +28,7 @@ class CuraStackBuilder:
|
|||
:return: The new global stack or None if an error occurred.
|
||||
"""
|
||||
|
||||
from cura.CuraApplication import CuraApplication
|
||||
from cura.CuraApplication import CuraApplication # inline import needed due to circular import
|
||||
application = CuraApplication.getInstance()
|
||||
registry = application.getContainerRegistry()
|
||||
container_tree = ContainerTree.getInstance()
|
||||
|
@ -91,7 +92,7 @@ class CuraStackBuilder:
|
|||
:param extruder_position: The position of the current extruder.
|
||||
"""
|
||||
|
||||
from cura.CuraApplication import CuraApplication
|
||||
from cura.CuraApplication import CuraApplication # inline import needed due to circular import
|
||||
application = CuraApplication.getInstance()
|
||||
registry = application.getContainerRegistry()
|
||||
|
||||
|
@ -199,13 +200,21 @@ class CuraStackBuilder:
|
|||
|
||||
:return: A new Global stack instance with the specified parameters.
|
||||
"""
|
||||
|
||||
from cura.CuraApplication import CuraApplication
|
||||
application = CuraApplication.getInstance()
|
||||
registry = application.getContainerRegistry()
|
||||
|
||||
stack = GlobalStack(new_stack_id)
|
||||
stack.setDefinition(definition)
|
||||
cls.createUserContainer(new_stack_id, definition, stack, variant_container, material_container, quality_container)
|
||||
return stack
|
||||
|
||||
@classmethod
|
||||
def createUserContainer(cls, new_stack_id: str, definition: DefinitionContainerInterface,
|
||||
stack: GlobalStack,
|
||||
variant_container: "InstanceContainer",
|
||||
material_container: "InstanceContainer",
|
||||
quality_container: "InstanceContainer") -> None:
|
||||
from cura.CuraApplication import CuraApplication
|
||||
application = CuraApplication.getInstance()
|
||||
|
||||
registry = application.getContainerRegistry()
|
||||
|
||||
# Create user container
|
||||
user_container = cls.createUserChangesContainer(new_stack_id + "_user", definition.getId(), new_stack_id,
|
||||
|
@ -221,8 +230,6 @@ class CuraStackBuilder:
|
|||
|
||||
registry.addContainer(user_container)
|
||||
|
||||
return stack
|
||||
|
||||
@classmethod
|
||||
def createUserChangesContainer(cls, container_name: str, definition_id: str, stack_id: str,
|
||||
is_global_stack: bool) -> "InstanceContainer":
|
||||
|
@ -259,3 +266,49 @@ class CuraStackBuilder:
|
|||
container_stack.definitionChanges = definition_changes_container
|
||||
|
||||
return definition_changes_container
|
||||
|
||||
@classmethod
|
||||
def createAbstractMachine(cls, definition_id: str) -> Optional[AbstractMachine]:
|
||||
"""Create a new instance of an abstract machine.
|
||||
|
||||
:param definition_id: The ID of the machine definition to use.
|
||||
|
||||
:return: The new Abstract Machine or None if an error occurred.
|
||||
"""
|
||||
abstract_machine_id = definition_id + "_abstract_machine"
|
||||
|
||||
from cura.CuraApplication import CuraApplication
|
||||
application = CuraApplication.getInstance()
|
||||
registry = application.getContainerRegistry()
|
||||
container_tree = ContainerTree.getInstance()
|
||||
|
||||
if registry.findContainerStacks(type = "abstract_machine", id = abstract_machine_id):
|
||||
# This abstract machine already exists
|
||||
return None
|
||||
|
||||
match registry.findDefinitionContainers(type = "machine", id = definition_id):
|
||||
case []:
|
||||
# It should not be possible for the definition to be missing since an abstract machine will only
|
||||
# be created as a result of a machine with definition_id being created.
|
||||
Logger.error(f"Definition {definition_id} was not found!")
|
||||
return None
|
||||
case [machine_definition, *_definitions]:
|
||||
machine_node = container_tree.machines[machine_definition.getId()]
|
||||
name = machine_definition.getName()
|
||||
|
||||
stack = AbstractMachine(abstract_machine_id)
|
||||
stack.setDefinition(machine_definition)
|
||||
cls.createUserContainer(
|
||||
name,
|
||||
machine_definition,
|
||||
stack,
|
||||
application.empty_variant_container,
|
||||
application.empty_material_container,
|
||||
machine_node.preferredGlobalQuality().container,
|
||||
)
|
||||
|
||||
stack.setName(name)
|
||||
|
||||
registry.addContainer(stack)
|
||||
|
||||
return stack
|
||||
|
|
|
@ -10,10 +10,13 @@ if TYPE_CHECKING:
|
|||
|
||||
|
||||
#
|
||||
# This class manages a all registered upon-exit checks that need to be perform when the application tries to exit.
|
||||
# For example, to show a confirmation dialog when there is USB printing in progress, etc. All callbacks will be called
|
||||
# in the order of when they got registered. If all callbacks "passes", that is, for example, if the user clicks "yes"
|
||||
# on the exit confirmation dialog or nothing that's blocking the exit, then the application will quit after that.
|
||||
# This class manages all registered upon-exit checks
|
||||
# that need to be performed when the application tries to exit.
|
||||
# For example, show a confirmation dialog when there is USB printing in progress.
|
||||
# All callbacks will be called in the order of when they were registered.
|
||||
# If all callbacks "pass", for example:
|
||||
# if the user clicks "yes" on the exit confirmation dialog
|
||||
# and nothing else is blocking the exit, then the application will quit.
|
||||
#
|
||||
class OnExitCallbackManager:
|
||||
|
||||
|
@ -35,10 +38,12 @@ class OnExitCallbackManager:
|
|||
def getIsAllChecksPassed(self) -> bool:
|
||||
return self._is_all_checks_passed
|
||||
|
||||
# Trigger the next callback if available. If not, it means that all callbacks have "passed", which means we should
|
||||
# not block the application to quit, and it will call the application to actually quit.
|
||||
# Trigger the next callback if there is one.
|
||||
# If not, all callbacks have "passed",
|
||||
# which means we should not prevent the application from quitting,
|
||||
# and we call the application to actually quit.
|
||||
def triggerNextCallback(self) -> None:
|
||||
# Get the next callback and schedule that if
|
||||
# Get the next callback and schedule it
|
||||
this_callback = None
|
||||
if self._current_callback_idx < len(self._on_exit_callback_list):
|
||||
this_callback = self._on_exit_callback_list[self._current_callback_idx]
|
||||
|
@ -55,10 +60,11 @@ class OnExitCallbackManager:
|
|||
# Tell the application to exit
|
||||
self._application.callLater(self._application.closeApplication)
|
||||
|
||||
# This is the callback function which an on-exit callback should call when it finishes, it should provide the
|
||||
# "should_proceed" flag indicating whether this check has "passed", or in other words, whether quitting the
|
||||
# application should be blocked. If the last on-exit callback doesn't block the quitting, it will call the next
|
||||
# registered on-exit callback if available.
|
||||
# Callback function which an on-exit callback calls when it finishes.
|
||||
# It provides a "should_proceed" flag indicating whether the check has "passed",
|
||||
# or whether quitting the application should be blocked.
|
||||
# If the last on-exit callback doesn't block quitting, it will call the next
|
||||
# registered on-exit callback if one is available.
|
||||
def onCurrentCallbackFinished(self, should_proceed: bool = True) -> None:
|
||||
if not should_proceed:
|
||||
Logger.log("d", "on-app-exit callback finished and we should not proceed.")
|
||||
|
|
81
docs/Report.md
Normal file
81
docs/Report.md
Normal file
|
@ -0,0 +1,81 @@
|
|||
|
||||
# Reporting Issues
|
||||
|
||||
Please attach the following information in case <br>
|
||||
you want to report crashing or similar issues.
|
||||
|
||||
<br>
|
||||
|
||||
## DxDiag
|
||||
|
||||
### ![Badge Windows]
|
||||
|
||||
The log as produced by **dxdiag**.
|
||||
|
||||
<kbd> start </kbd> » <kbd> run </kbd> » <kbd> dxdiag </kbd> » <kbd> save output </kbd>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Cura GUI Log
|
||||
|
||||
If the Cura user interface still starts, you can also <br>
|
||||
reach these directories from the application menu:
|
||||
|
||||
<kbd> Help </kbd> » <kbd> Show settings folder </kbd>
|
||||
|
||||
<br>
|
||||
|
||||
### ![Badge Windows]
|
||||
|
||||
```
|
||||
%APPDATA%\cura\<Cura Version>\cura.log
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
C:\Users\<your username>\AppData\Roaming\cura\<Cura Version>\cura.log
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### ![Badge Linux]
|
||||
|
||||
```
|
||||
~/.local/share/cura/<Cura Version>/cura.log
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### ![Badge MacOS]
|
||||
|
||||
```
|
||||
~/Library/Application Support/cura/<Cura Version>/cura.log
|
||||
```
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Alternative
|
||||
|
||||
An alternative is to install the **[ExtensiveSupportLogging]** <br>
|
||||
plugin this creates a zip folder of the relevant log files.
|
||||
|
||||
If you're experiencing performance issues, we might ask <br>
|
||||
you to connect the CPU profiler in this plugin and attach <br>
|
||||
the collected data to your support ticket.
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
<!----------------------------------------------------------------------------->
|
||||
|
||||
[ExtensiveSupportLogging]: https://marketplace.ultimaker.com/app/cura/plugins/UltimakerPackages/ExtensiveSupportLogging
|
||||
|
||||
|
||||
<!---------------------------------[ Badges ]---------------------------------->
|
||||
|
||||
[Badge Windows]: https://img.shields.io/badge/Windows-0078D6?style=for-the-badge&logoColor=white&logo=Windows
|
||||
[Badge Linux]: https://img.shields.io/badge/Linux-00A95C?style=for-the-badge&logoColor=white&logo=Linux
|
||||
[Badge MacOS]: https://img.shields.io/badge/MacOS-403C3D?style=for-the-badge&logoColor=white&logo=MacOS
|
|
@ -2,32 +2,77 @@ Setting Properties
|
|||
====
|
||||
Each setting in Cura has a number of properties. It's not just a key and a value. This page lists the properties that a setting can define.
|
||||
|
||||
* `key` (string): The identifier by which the setting is referenced. This is not a human-readable name, but just a reference string, such as `layer_height_0`. Typically these are named with the most significant category first, in order to sort them better, such as `material_print_temperature`. This is not actually a real property but just an identifier; it can't be changed.
|
||||
* `value` (optional): The current value of the setting. This can be a function, an arbitrary Python expression that depends on the values of other settings. If it's not present, the `default_value` is used.
|
||||
* `default_value`: A default value for the setting if `value` is undefined. This property is required however. It can't be a Python expression, but it can be any JSON type. This is made separate so that CuraEngine can read it out as well for its debugging mode via the command line, without needing a complete Python interpreter.
|
||||
* `label` (string): The human-readable name for the setting. This label is translated.
|
||||
* `description` (string): A longer description of what the setting does when you change it. This description is translated as well.
|
||||
* `type` (string): The type of value that this setting contains. Allowed types are: `bool`, `str`, `float`, `int`, `enum`, `category`, `[int]`, `vec3`, `polygon` and `polygons`.
|
||||
* `unit` (optional string): A unit that is displayed at the right-hand side of the text field where the user enters the setting value.
|
||||
* `resolve` (optional string): A Python expression that resolves disagreements for global settings if multiple per-extruder profiles define different values for a setting. Typically this takes the values for the setting from all stacks and computes one final value for it that will be used for the global setting. For instance, the `resolve` function for the build plate temperature is `max(extruderValues('material_bed_temperature')`, meaning that it will use the hottest bed temperature of all materials of the extruders in use.
|
||||
* `limit_to_extruder` (optional): A Python expression that indicates which extruder a setting will be obtained from. This is used for settings that may be extruder-specific but the extruder is not necessarily the current extruder. For instance, support settings need to be evaluated for the support extruder. Infill settings need to be evaluated for the infill extruder if the infill extruder is changed.
|
||||
* `enabled` (optional string or boolean): Whether the setting can currently be made visible for the user. This can be a simple true/false, or a Python expression that depends on other settings. Typically used for settings that don't apply when another setting is disabled, such as to hide the support settings if support is disabled.
|
||||
* `minimum_value` (optional): The lowest acceptable value for this setting. If it's any lower, Cura will not allow the user to slice. By convention this is used to prevent setting values that are technically or physically impossible, such as a layer height of 0mm. This property only applies to numerical settings.
|
||||
* `maximum_value` (optional): The highest acceptable value for this setting. If it's any higher, Cura will not allow the user to slice. By convention this is used to prevent setting values that are technically or physically impossible, such as a support overhang angle of more than 90 degrees. This property only applies to numerical settings.
|
||||
* `minimum_value_warning` (optional): The threshold under which a warning is displayed to the user. By convention this is used to indicate that it will probably not print very nicely with such a low setting value. This property only applies to numerical settings.
|
||||
* `maximum_value_warning` (optional): The threshold above which a warning is displayed to the user. By convention this is used to indicate that it will probably not print very nicely with such a high setting value. This property only applies to numerical settings.
|
||||
* `settable_globally` (optional boolean): Whether the setting can be changed globally. For some mesh-type settings such as `support_mesh` this doesn't make sense, so those can't be changed globally. They are not displayed in the main settings list then.
|
||||
* `settable_per_meshgroup` (optional boolean): Whether a setting can be changed per group of meshes. Currently unused in Cura.
|
||||
* `settable_per_extruder` (optional boolean): Whether a setting can be changed per extruder. Some settings, like the build plate temperature, can't be adjusted separately for each extruder. An icon is shown in the interface to indicate this. If the user changes these settings they are stored in the global stack.
|
||||
* `settable_per_mesh` (optional boolean): Whether a setting can be changed per mesh. The settings that can be changed per mesh are shown in the list of available settings in the per-object settings tool.
|
||||
* `children` (optional list): A list of child settings. These are displayed with an indentation. If all child settings are overridden by the user, the parent setting gets greyed out to indicate that the parent setting has no effect any more. This is not strictly always the case though, because that would depend on the inheritance functions in the `value`.
|
||||
* `icon` (optional string): A path to an icon to be displayed. Only applies to setting categories.
|
||||
* `allow_empty` (optional bool): Whether the setting is allowed to be empty. If it's not, this will be treated as a setting error and Cura will not allow the user to slice. Only applies to string-type settings.
|
||||
* `warning_description` (optional string): A warning message to display when the setting has a warning value. This is currently unused by Cura.
|
||||
* `error_description` (optional string): An error message to display when the setting has an error value. This is currently unused by Cura.
|
||||
* `options` (dictionary): A list of values that the user can choose from. The keys of this dictionary are keys that CuraEngine identifies the option with. The values are human-readable strings and will be translated. Only applies to (and only required for) enum-type settings.
|
||||
* `comments` (optional string): Comments to other programmers about the setting. This is not used by Cura.
|
||||
* `is_uuid` (optional boolean): Whether or not this setting indicates a UUID-4. If it is, the setting will indicate an error if it's not in the correct format. Only applies to string-type settings.
|
||||
* `regex_blacklist_pattern` (optional string): A regular expression, where if the setting value matches with this regular expression, it gets an error state. Only applies to string-type settings.
|
||||
* `error_value` (optional): If the setting value is equal to this value, it will show a setting error. This is used to display errors for non-numerical settings such as checkboxes.
|
||||
* `warning_value` (optional): If the setting value is equal to this value, it will show a setting warning. This is used to display warnings for non-numerical settings such as checkboxes.
|
||||
* `key` (string): __The identifier by which the setting is referenced.__
|
||||
* This is not a human-readable name, but just a reference string, such as `layer_height_0`.
|
||||
* This is not actually a real property but just an identifier; it can't be changed.
|
||||
* Typically these are named with the most significant category first, in order to sort them better, such as `material_print_temperature`.
|
||||
* `value` (optional): __The current value of the setting.__
|
||||
* This can be a function (an arbitrary Python expression) that depends on the values of other settings.
|
||||
* If it's not present, the `default_value` is used.
|
||||
* `default_value`: __A default value for the setting if `value` is undefined.__
|
||||
* This property is required.
|
||||
* It can't be a Python expression, but it can be any JSON type.
|
||||
* This is made separate so that CuraEngine can read it out for its debugging mode via the command line, without needing a complete Python interpreter.
|
||||
* `label` (string): __The human-readable name for the setting.__
|
||||
* This label is translated.
|
||||
* `description` (string): __A longer description of what the setting does when you change it.__
|
||||
* This description is translated.
|
||||
* `type` (string): __The type of value that this setting contains.__
|
||||
* Allowed types are: `bool`, `str`, `float`, `int`, `enum`, `category`, `[int]`, `vec3`, `polygon` and `polygons`.
|
||||
* `unit` (optional string): __A unit that is displayed at the right-hand side of the text field where the user enters the setting value.__
|
||||
* `resolve` (optional string): __A Python expression that resolves disagreements for global settings if multiple per-extruder profiles define different values for a setting.__
|
||||
* Typically this takes the values for the setting from all stacks and computes one final value for it that will be used for the global setting. For instance, the `resolve` function for the build plate temperature is `max(extruderValues('material_bed_temperature')`, meaning that it will use the hottest bed temperature of all materials of the extruders in use.
|
||||
* `limit_to_extruder` (optional): __A Python expression that indicates which extruder a setting will be obtained from.__
|
||||
* This is used for settings that may be extruder-specific but the extruder is not necessarily the current extruder. For instance, support settings need to be evaluated for the support extruder. Infill settings need to be evaluated for the infill extruder if the infill extruder is changed.
|
||||
* `enabled` (optional string or boolean): __Whether the setting can currently be made visible for the user.__
|
||||
* This can be a simple true/false, or a Python expression that depends on other settings.
|
||||
* Typically used for settings that don't apply when another setting is disabled, such as to hide the support settings if support is disabled.
|
||||
* `minimum_value` (optional): __The lowest acceptable value for this setting.__
|
||||
* If it's any lower, Cura will not allow the user to slice.
|
||||
* This property only applies to numerical settings.
|
||||
* By convention this is used to prevent setting values that are technically or physically impossible, such as a layer height of 0mm.
|
||||
* `maximum_value` (optional): __The highest acceptable value for this setting.__
|
||||
* If it's any higher, Cura will not allow the user to slice.
|
||||
* This property only applies to numerical settings.
|
||||
* By convention this is used to prevent setting values that are technically or physically impossible, such as a support overhang angle of more than 90 degrees.
|
||||
* `minimum_value_warning` (optional): __The threshold under which a warning is displayed to the user.__
|
||||
* This property only applies to numerical settings.
|
||||
* By convention this is used to indicate that it will probably not print very nicely with such a low setting value.
|
||||
* `maximum_value_warning` (optional): __The threshold above which a warning is displayed to the user.__
|
||||
* This property only applies to numerical settings.
|
||||
* By convention this is used to indicate that it will probably not print very nicely with such a high setting value.
|
||||
* `settable_globally` (optional boolean): __Whether the setting can be changed globally.__
|
||||
* For some mesh-type settings such as `support_mesh` this doesn't make sense, so those can't be changed globally. They are not displayed in the main settings list then.
|
||||
* `settable_per_meshgroup` (optional boolean): __Whether a setting can be changed per group of meshes.__
|
||||
* *This is currently unused by Cura.*
|
||||
* `settable_per_extruder` (optional boolean): __Whether a setting can be changed per extruder.__
|
||||
* Some settings, like the build plate temperature, can't be adjusted separately for each extruder. An icon is shown in the interface to indicate this.
|
||||
* If the user changes these settings they are stored in the global stack.
|
||||
* `settable_per_mesh` (optional boolean): __Whether a setting can be changed per mesh.__
|
||||
* The settings that can be changed per mesh are shown in the list of available settings in the per-object settings tool.
|
||||
* `children` (optional list): __A list of child settings.__
|
||||
* These are displayed with an indentation. If all child settings are overridden by the user, the parent setting gets greyed out to indicate that the parent setting has no effect any more. This is not strictly always the case though, because that would depend on the inheritance functions in the `value`.
|
||||
* `icon` (optional string): __A path to an icon to be displayed.__
|
||||
* Only applies to setting categories.
|
||||
* `allow_empty` (optional bool): __Whether the setting is allowed to be empty.__
|
||||
* If it's not, this will be treated as a setting error and Cura will not allow the user to slice.
|
||||
* Only applies to string-type settings.
|
||||
* `warning_description` (optional string): __A warning message to display when the setting has a warning value.__
|
||||
* *This is currently unused by Cura.*
|
||||
* `error_description` (optional string): __An error message to display when the setting has an error value.__
|
||||
* *This is currently unused by Cura.*
|
||||
* `options` (dictionary): __A list of values that the user can choose from.__
|
||||
* The keys of this dictionary are keys that CuraEngine identifies the option with.
|
||||
* The values are human-readable strings and will be translated.
|
||||
* Only applies to (and only required for) enum-type settings.
|
||||
* `comments` (optional string): __Comments to other programmers about the setting.__
|
||||
* *This is currently unused by Cura.*
|
||||
* `is_uuid` (optional boolean): __Whether or not this setting indicates a UUID-4.__
|
||||
* If it is, the setting will indicate an error if it's not in the correct format.
|
||||
* Only applies to string-type settings.
|
||||
* `regex_blacklist_pattern` (optional string): __A regular expression, where if the setting value matches with this regular expression, it gets an error state.__
|
||||
* Only applies to string-type settings.
|
||||
* `error_value` (optional): __If the setting value is equal to this value, it will show a setting error.__
|
||||
* This is used to display errors for non-numerical settings such as checkboxes.
|
||||
* `warning_value` (optional): __If the setting value is equal to this value, it will show a setting warning.__
|
||||
* This is used to display warnings for non-numerical settings such as checkboxes.
|
||||
|
|
|
@ -400,11 +400,13 @@ class CloudOutputDeviceManager:
|
|||
# We do not use use MachineManager.addMachine here because we need to set the cluster ID before activating it.
|
||||
new_machine = CuraStackBuilder.createMachine(device.name, device.printerType, show_warning_message=False)
|
||||
if not new_machine:
|
||||
Logger.log("e", "Failed creating a new machine")
|
||||
Logger.error(f"Failed creating a new machine for {device.name}")
|
||||
return False
|
||||
|
||||
self._setOutputDeviceMetadata(device, new_machine)
|
||||
|
||||
_abstract_machine = CuraStackBuilder.createAbstractMachine(device.printerType)
|
||||
|
||||
if activate:
|
||||
CuraApplication.getInstance().getMachineManager().setActiveMachine(new_machine.getId())
|
||||
|
||||
|
|
|
@ -1225,20 +1225,7 @@
|
|||
"default_value": 0.3,
|
||||
"value": "min_wall_line_width",
|
||||
"type": "float",
|
||||
"settable_per_mesh": true,
|
||||
"children":
|
||||
{
|
||||
"wall_split_middle_threshold": {
|
||||
"label": "Split Middle Line Threshold",
|
||||
"description": "The smallest line width, as a factor of the normal line width, above which the middle line (if there is one) will be split into two. Reduce this setting to use more, thinner lines. Increase to use fewer, wider lines. Note that this applies -as if- the entire shape should be filled with wall, so the middle here refers to the middle of the object between two outer edges of the shape, even if there actually is fill or (other) skin in the print instead of wall.",
|
||||
"type": "float",
|
||||
"unit": "%",
|
||||
"default_value": 50,
|
||||
"value": "max(1, min(99, 100 * (2 * min_even_wall_line_width - wall_line_width_0) / wall_line_width_0))",
|
||||
"minimum_value": "1",
|
||||
"maximum_value": "99"
|
||||
}
|
||||
}
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"min_odd_wall_line_width":
|
||||
{
|
||||
|
@ -1250,20 +1237,7 @@
|
|||
"default_value": 0.3,
|
||||
"value": "min_wall_line_width",
|
||||
"type": "float",
|
||||
"settable_per_mesh": true,
|
||||
"children":
|
||||
{
|
||||
"wall_add_middle_threshold": {
|
||||
"label": "Add Middle Line Threshold",
|
||||
"description": "The smallest line width, as a factor of the normal line width, above which a middle line (if there wasn't one already) will be added. Reduce this setting to use more, thinner lines. Increase to use fewer, wider lines. Note that this applies -as if- the entire shape should be filled with wall, so the middle here refers to the middle of the object between two outer edges of the shape, even if there actually is fill or (other) skin in the print instead of wall.",
|
||||
"type": "float",
|
||||
"unit": "%",
|
||||
"default_value": 75,
|
||||
"value": "max(1, min(99, 100 * min_odd_wall_line_width / wall_line_width_x))",
|
||||
"minimum_value": "1",
|
||||
"maximum_value": "99"
|
||||
}
|
||||
}
|
||||
"settable_per_mesh": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -8049,7 +8023,7 @@
|
|||
"label": "Remove Raft Inside Corners",
|
||||
"description": "Remove inside corners from the raft, causing the raft to become convex.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"default_value": true,
|
||||
"resolve": "any(extruderValues('raft_remove_inside_corners'))",
|
||||
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
|
||||
"settable_per_mesh": false,
|
||||
|
|
|
@ -51,7 +51,17 @@ Item
|
|||
{
|
||||
target: infillSlider
|
||||
property: "value"
|
||||
value: parseInt(infillDensity.properties.value)
|
||||
value: {
|
||||
// The infill slider has a max value of 100. When it is given a value > 100 onValueChanged updates the setting to be 100.
|
||||
// When changing to an intent with infillDensity > 100, it would always be clamped to 100.
|
||||
// This will force the slider to ignore the first onValueChanged for values > 100 so higher values can be set.
|
||||
var density = parseInt(infillDensity.properties.value)
|
||||
if (density > 100) {
|
||||
infillSlider.ignoreValueChange = true
|
||||
}
|
||||
|
||||
return density
|
||||
}
|
||||
}
|
||||
|
||||
// Here are the elements that are shown in the left column
|
||||
|
@ -84,6 +94,8 @@ Item
|
|||
{
|
||||
id: infillSlider
|
||||
|
||||
property var ignoreValueChange: false
|
||||
|
||||
width: parent.width
|
||||
height: UM.Theme.getSize("print_setup_slider_handle").height // The handle is the widest element of the slider
|
||||
|
||||
|
@ -157,7 +169,13 @@ Item
|
|||
target: infillSlider
|
||||
function onValueChanged()
|
||||
{
|
||||
// Don't round the value if it's already the same
|
||||
if (infillSlider.ignoreValueChange)
|
||||
{
|
||||
infillSlider.ignoreValueChange = false
|
||||
return
|
||||
}
|
||||
|
||||
// Don't update if the setting value, if the slider has the same value
|
||||
if (parseInt(infillDensity.properties.value) == infillSlider.value)
|
||||
{
|
||||
return
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue