diff --git a/.gitignore b/.gitignore index 81c9421e..98739513 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,43 @@ -.gdbinit -.vs -.vscode build +calculate-ctm.txt class-template.txt +cleaned.txt copy-to-usb-stick.sh deps-junk-1.txt deps-junk-2.txt deps-junk-3.txt +display-args.func +dlp4710/set-projector-power +dlp4710/set-projector-power.o do-it.sh +fresh-pkg-list.txt +.gdbinit gpg/gpg-agent.conf gpg/openpgp-revocs.d gpg/private-keys-v1.d gpg/random_seed +images/focus-image.png +images/white-field.png +installer +install-overlap.txt +listcomp.pl +listfilter.pl model-library +mountmon/build mountmon/.gdbinit -mountmon/.qmake.stash mountmon/Makefile -mountmon/build +mountmon/.qmake.stash newConfigureUbuntuAndInstallLightField.sh out packaging +rpi4_packages-overlap.txt +rpi4_packages-to-install.txt +src/version.h superclean.sh +ubuntu-cosmic-18.10-packages.txt +usb-driver/dlpc350_api.o +usb-driver/dlpc350_usb.o +usb-driver/main.o usb-driver/set-projector-power +.vs +.vscode diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b1b6626..a5457b9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ set (PROJECT_VERSION "${LF_VERSION_MAJOR}.${LF_VERSION_MINOR}.${LF_VERSION_PATCH if(WIN32) # Set the Qt5 path -set(Qt5_DIR "F:\\\\Qt\\\\5.13.1\\\\msvc2017_64\\\\lib\\\\cmake\\\\Qt5") +set(Qt5_DIR "F:\\\\Qt\\\\5.14.0\\\\msvc2017_64\\\\lib\\\\cmake\\\\Qt5") endif(WIN32) project(lf) @@ -50,8 +50,11 @@ src/mesh.cpp src/pngdisplayer.cpp src/preparetab.cpp src/printmanager.cpp +src/printprofile.cpp +src/printprofilemanager.cpp src/printtab.cpp src/processrunner.cpp +src/profilestab.cpp src/shepherd.cpp src/signalhandler.cpp src/statustab.cpp @@ -93,8 +96,12 @@ src/pngdisplayer.h src/preparetab.h src/printjob.h src/printmanager.h +src/printprofile.h +src/printprofilemanager.h +src/printpumpingparameters.h src/printtab.h src/processrunner.h +src/profilestab.h src/shepherd.h src/signalhandler.h src/statustab.h diff --git a/change-version-number.sh b/change-version-number.sh index 83b6f909..5f3b87a5 100755 --- a/change-version-number.sh +++ b/change-version-number.sh @@ -1,68 +1,119 @@ #!/bin/bash +# shellcheck disable=SC2164 -function blue-bar () { - echo -e "\r\x1B[1;37;44m$*\x1B[K\x1B[0m" 1>&2 -} +LIGHTFIELD_ROOT="${PWD}" -function red-bar () { - echo -e "\r\x1B[1;33;41m$*\x1B[K\x1B[0m" 1>&2 -} +######################################################### +## ## +## No user-serviceable parts below this point. ## +## ## +######################################################### -function error-trap () { - red-bar Failed\! +function usage () { + cat 1>&2 <] +Changes the LightField version in all the relevant places in the source. + + -t Sets the release train. Default: ${DEFAULT_RELEASE_TRAIN} + Available release trains: + base LightField with DLPC350 support + dlpc4710 LightField with DLP4710 support + Version number. If the fourth element is omitted, + it defaults to 0. +HERE exit 1 } -if [ -z "$1" ] +# shellcheck disable=SC1090 +source "${LIGHTFIELD_ROOT}/shared-stuff.sh" + +ARGS=$(getopt -n 'change-version-number.sh' -o 't:' -- "${@}") +# shellcheck disable=SC2181 +if [ ${?} -ne 0 ] then - red-bar 'Usage: change-version-number.sh ' - exit 1 + usage fi +eval set -- "$ARGS" + +while [ -n "${1}" ] +do + case "${1}" in + '-t') + RELEASE_TRAIN="${2}" + shift + ;; + + '--') + shift + break + ;; + esac + shift +done -VER=( $(IFS="."; echo $1) ) -if [ "${#VER[@]}" -lt 3 ] +if [ -z "${1}" ] then - red-bar 'Too few components to version number -- must be at least three.' - exit 1 -elif [ "${#VER[@]}" -eq 3 ] + red-bar 'No version number given.' + usage +elif [ -n "${2}" ] then - VER[3]=0 -elif [ "${#VER[@]}" -gt 4 ] + red-bar 'Too many arguments given.' + usage +else + VERSION="${1}" +fi + +mapfile -t -d. VER < <(echo -n "${VERSION}") +COUNT=${#VER[@]} + +if [ "${COUNT}" -lt 3 ] then - red-bar 'Too many components to version number -- must be at most four.' - exit 1 + red-bar 'Too few components in version number -- must be at least three.' + usage +elif [ "${COUNT}" -gt 4 ] +then + red-bar 'Too many components in version number -- must be at most four.' + usage +fi + +if [ "${COUNT}" -eq 3 ] +then + VER[3]=0 fi + STRINGVER="${VER[0]}.${VER[1]}.${VER[2]}.${VER[3]}" -LIGHTFIELD_ROOT="/home/lumen/Volumetric/LightField" -LIGHTFIELD_SRC="${LIGHTFIELD_ROOT}/src" +if [ -z "${RELEASE_TRAIN}" ] +then + RELEASE_TRAIN=base +fi + +#cat < "version.h" +cp version.h.in version.h + +apply-atsign-substitution VERSION_STRING "${STRINGVER}" version.h +apply-atsign-substitution VERSION_MAJOR "${VER[0]}" version.h +apply-atsign-substitution VERSION_MINOR "${VER[1]}" version.h +apply-atsign-substitution VERSION_TEENY "${VER[2]}" version.h +apply-atsign-substitution VERSION_BUILD "${VER[3]}" version.h +apply-atsign-substitution RELEASE_TRAIN "${RELEASE_TRAIN}" version.h cd "${LIGHTFIELD_ROOT}" blue-bar 'Updating build and packaging scripts' -perl \ - -lpi \ - -e "s/^\s*VERSION=\\d+\\.\\d+\\.\\d+(?:\\.\\d+)?\s*$/VERSION=${STRINGVER}/g;" \ - install-lightfield.sh \ - make-deb-package.sh \ - make-upgrade-kit.sh \ - unpack-kit-manually.sh - -perl \ - -lpi \ - -e "s/lightfield-(debug|release)_\\d+\\.\\d+\\.\\d+(?:\\.\\d+)?_amd64/lightfield-\$1_${STRINGVER}_amd64/g;" \ - debian/lightfield-debug.postinst \ - debian/lightfield-release.postinst + +apply-assignment-substitution ARCHITECTURE "${ARCHITECTURE}" shared-stuff.sh +apply-assignment-substitution RELEASE_TRAIN "${RELEASE_TRAIN}" shared-stuff.sh +apply-assignment-substitution VERSION "${STRINGVER}" shared-stuff.sh + +blue-bar 'Done!' diff --git a/debian/changelog b/debian/changelog index 950b8ec8..27d7ba5c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +lightfield (1.0.11.0) stable; urgency=medium + + * New: Support for DLP4710 projector. + + -- LightField packager Thu, 09 Jan 2020 17:18:06 -0800 + lightfield (1.0.10.0) stable; urgency=medium * Fixed: LightField will now notice a USB stick that was connected before it starts. diff --git a/debian/debug-control b/debian/control.in similarity index 75% rename from debian/debug-control rename to debian/control.in index c15345e8..33158484 100644 --- a/debian/debug-control +++ b/debian/control.in @@ -12,13 +12,14 @@ Homepage: https://github.com/VolumetricBio/LightField Vcs-Browser: https://github.com/VolumetricBio/LightField Vcs-Git: https://github.com/VolumetricBio/LightField.git -Package: lightfield-debug +Package: lightfield@@RELEASE_TRAIN@@-@@BUILDTYPE@@ Architecture: any -Breaks: lightfield-release -Conflicts: lightfield-release -Replaces: lightfield-release +Provides: lightfield-@@BUILDTYPE@@ +Breaks: lightfield-@@ANTIBUILDTYPE@@ +Conflicts: lightfield-@@ANTIBUILDTYPE@@ +Replaces: lightfield-@@ANTIBUILDTYPE@@ Depends: - lightfield-common (= ${binary:Version}), + lightfield-common@@RELEASE_TRAIN@@ (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends}, libhidapi-libusb0 (>> 0.8), @@ -34,9 +35,10 @@ Recommends: fonts-font-awesome (>= 5.0.10) Description: Printer software for Volumetric's Lumen X 3D printer - debug version -Package: lightfield-common +Package: lightfield-common@@RELEASE_TRAIN@@ Architecture: all Multi-Arch: foreign +Provides: lightfield-common Depends: ${misc:Depends}, python3 (>= 3.6), diff --git a/debian/lightfield-common.install b/debian/lightfield-common-base.install similarity index 100% rename from debian/lightfield-common.install rename to debian/lightfield-common-base.install diff --git a/debian/lightfield-common-dlp4710.install b/debian/lightfield-common-dlp4710.install new file mode 100644 index 00000000..2b417a51 --- /dev/null +++ b/debian/lightfield-common-dlp4710.install @@ -0,0 +1,13 @@ +files/etc/apt/trusted.gpg.d/volumetric-keyring.gpg etc/apt/trusted.gpg.d +files/etc/sudoers.d/lumen-lightfield etc/sudoers.d +files/home/lumen/.bash_profile home/lumen +files/home/lumen/.real_bash_profile home/lumen +files/home/lumen/.gnupg/pubring.gpg home/lumen/.gnupg +files/home/lumen/.gnupg/pubring.kbx home/lumen/.gnupg +files/home/lumen/.gnupg/trustdb.gpg home/lumen/.gnupg +files/lib/udev/rules.d/90-dlp4710.rules lib/udev/rules.d +files/usr/share/lightfield/libexec/reset-lumen-arduino-port usr/share/lightfield/libexec +files/usr/share/lightfield/libexec/reset-lumen-projector-port usr/share/lightfield/libexec +files/usr/share/lightfield/libexec/printrun/* usr/share/lightfield/libexec/printrun +files/usr/share/lightfield/libexec/stdio-shepherd/* usr/share/lightfield/libexec/stdio-shepherd +files/usr/share/X11/xorg.conf.d/99-waveshare.conf usr/share/X11/xorg.conf.d diff --git a/debian/lightfield-common.postinst b/debian/lightfield-common.postinst index 0498545a..dc60412f 100644 --- a/debian/lightfield-common.postinst +++ b/debian/lightfield-common.postinst @@ -17,8 +17,6 @@ # for details, see https://www.debian.org/doc/debian-policy/ or # the debian-policy package - -#echo "+ lightfield-common.postinst: args are $*" 1>&2 case "$1" in configure) mkdir -p \ diff --git a/debian/lightfield-common.postrm b/debian/lightfield-common.postrm index 789a65a4..e99aaf3e 100644 --- a/debian/lightfield-common.postrm +++ b/debian/lightfield-common.postrm @@ -1,5 +1,5 @@ #!/bin/sh -# postrm script for lightfield-debug +# postrm script for lightfield-common # # see: dh_installdeb(1) # @@ -18,8 +18,6 @@ # for details, see https://www.debian.org/doc/debian-policy/ or # the debian-policy package - -#echo "+ lightfield-debug.postrm: args are $*" 1>&2 case "$1" in remove) rm /etc/apt/sources.list.d/volumetric-lightfield.list 2>/dev/null diff --git a/debian/lightfield-common.preinst b/debian/lightfield-common.preinst index 43641611..7c118901 100644 --- a/debian/lightfield-common.preinst +++ b/debian/lightfield-common.preinst @@ -1,5 +1,5 @@ #!/bin/sh -# preinst script for lightfield-debug +# preinst script for lightfield-common # # see: dh_installdeb(1) # @@ -13,8 +13,6 @@ # for details, see https://www.debian.org/doc/debian-policy/ or # the debian-policy package - -#echo "+ lightfield-debug.preinst: args are $*" 1>&2 case "$1" in install) rm /etc/sudoers.d/lumen-lightfield 2>/dev/null diff --git a/debian/lightfield-debug.postinst b/debian/lightfield-debug.postinst deleted file mode 100644 index 00da6d2d..00000000 --- a/debian/lightfield-debug.postinst +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/sh -# postinst script for lightfield-debug -# -# see: dh_installdeb(1) -# -#set -e -# -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see https://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -#echo "+ lightfield-debug.postinst: args are $*" 1>&2 -case "$1" in - configure) - perl -lp -i -e 's/^(?!##LF## )/##LF## /;' /etc/apt/sources.list /etc/apt/sources.list.d/* 2>/dev/null - - echo "deb file:/var/lib/lightfield/software-updates/lightfield-debug_1.0.10.0_amd64 ./" > /etc/apt/sources.list.d/volumetric-lightfield.list - chown lumen:lumen /etc/apt/sources.list.d/volumetric-lightfield.list - chmod 644 /etc/apt/sources.list.d/volumetric-lightfield.list - - systemctl daemon-reload - systemctl set-default multi-user.target - systemctl enable --now set-projector-power.service clean-up-mount-points.service - systemctl enable getty@tty1.service - systemctl daemon-reload - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument '$1'" 1>&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 diff --git a/debian/lightfield-release.install b/debian/lightfield-release.install deleted file mode 100644 index ea4bc7c8..00000000 --- a/debian/lightfield-release.install +++ /dev/null @@ -1,6 +0,0 @@ -files/etc/systemd/system/getty@tty1.service.d/override.conf etc/systemd/system/getty@tty1.service.d -files/lib/systemd/system/clean-up-mount-points.service lib/systemd/system -files/lib/systemd/system/set-projector-power.service lib/systemd/system -files/usr/bin/lf usr/bin -files/usr/bin/mountmon usr/bin -files/usr/bin/set-projector-power usr/bin diff --git a/debian/lightfield-release.postrm b/debian/lightfield-release.postrm deleted file mode 100644 index 427410eb..00000000 --- a/debian/lightfield-release.postrm +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh -# postrm script for lightfield-release -# -# see: dh_installdeb(1) -# -#set -e -# -# summary of how this script can be called: -# * `remove' -# * `purge' -# * `upgrade' -# * `failed-upgrade' -# * `abort-install' -# * `abort-install' -# * `abort-upgrade' -# * `disappear' -# -# for details, see https://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -#echo "+ lightfield-release.postrm: args are $*" 1>&2 -case "$1" in - remove) - echo + Setting default back to graphical.target - systemctl set-default graphical.target - echo + Getting default - systemctl get-default - echo + Starting tty1 - systemctl start getty@tty1 - ;; - - purge|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) - ;; - - *) - echo "postrm called with unknown argument '$1'" 1>&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 diff --git a/debian/lightfield-release.preinst b/debian/lightfield-release.preinst deleted file mode 100644 index f18ca28b..00000000 --- a/debian/lightfield-release.preinst +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh -# preinst script for lightfield-release -# -# see: dh_installdeb(1) -# -#set -e -# -# summary of how this script can be called: -# * `install' -# * `install' -# * `upgrade' -# * `abort-upgrade' -# for details, see https://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -#echo "+ lightfield-release.preinst: args are $*" 1>&2 -case "$1" in - install|upgrade|abort-upgrade) - ;; - - *) - echo "preinst called with unknown argument '$1'" 1>&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 diff --git a/debian/lightfield-release.prerm b/debian/lightfield-release.prerm deleted file mode 100644 index b66a61cc..00000000 --- a/debian/lightfield-release.prerm +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -# prerm script for lightfield-release -# -# see: dh_installdeb(1) -# -#set -e -# -# summary of how this script can be called: -# * `remove' -# * `upgrade' -# * `failed-upgrade' -# * `remove' `in-favour' -# * `deconfigure' `in-favour' -# `removing' -# -# for details, see https://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -#echo "+ lightfield-release.prerm: args are $*" 1>&2 -case "$1" in - remove) - systemctl daemon-reload - systemctl disable --now set-projector-power.service clean-up-mount-points.service getty@tty1.service - rm -rf /etc/systemd/system/getty@tty1.service.d - systemctl daemon-reload - ;; - - upgrade|deconfigure|failed-upgrade) - ;; - - *) - echo "prerm called with unknown argument '$1'" 1>&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 diff --git a/debian/lightfield-debug.install b/debian/lightfield.install similarity index 100% rename from debian/lightfield-debug.install rename to debian/lightfield.install diff --git a/debian/lightfield-release.postinst b/debian/lightfield.postinst.in similarity index 70% rename from debian/lightfield-release.postinst rename to debian/lightfield.postinst.in index d5cd0902..f5dda33d 100644 --- a/debian/lightfield-release.postinst +++ b/debian/lightfield.postinst.in @@ -1,5 +1,5 @@ #!/bin/sh -# postinst script for lightfield-release +# postinst script for lightfield # # see: dh_installdeb(1) # @@ -17,13 +17,22 @@ # for details, see https://www.debian.org/doc/debian-policy/ or # the debian-policy package +RELEASE_TRAIN=@@RELEASE_TRAIN@@ +BUILDTYPE=@@BUILDTYPE@@ +VERSION=@@VERSION@@ +ARCHITECTURE=@@ARCHITECTURE@@ +if [ "${RELEASE_TRAIN}" = "base" ] +then + SUFFIX=${BUILDTYPE} +else + SUFFIX=${RELEASE_TRAIN}-${BUILDTYPE} +fi -#echo "+ lightfield-release.postinst: args are $*" 1>&2 case "$1" in configure) - perl -lp -i -e 's/^(?!##LF## )/##LF## /;' /etc/apt/sources.list /etc/apt/sources.list.d/* 2>/dev/null + perl -lpi -e 's/^(?!##LF## )/##LF## /;' /etc/apt/sources.list /etc/apt/sources.list.d/* 2>/dev/null - echo "deb file:/var/lib/lightfield/software-updates/lightfield-release_1.0.10.0_amd64 ./" > /etc/apt/sources.list.d/volumetric-lightfield.list + echo "deb file:/var/lib/lightfield/software-updates/lightfield-${SUFFIX}_${VERSION}_${ARCHITECTURE} ./" > /etc/apt/sources.list.d/volumetric-lightfield.list chown lumen:lumen /etc/apt/sources.list.d/volumetric-lightfield.list chmod 644 /etc/apt/sources.list.d/volumetric-lightfield.list @@ -32,6 +41,11 @@ case "$1" in systemctl enable --now set-projector-power.service clean-up-mount-points.service systemctl enable getty@tty1.service systemctl daemon-reload + + if [ "${RELEASE_TRAIN}" = "dlp4710" ] + then + set-projector-power --first-time + fi ;; abort-upgrade|abort-remove|abort-deconfigure) diff --git a/debian/lightfield-debug.postrm b/debian/lightfield.postrm similarity index 74% rename from debian/lightfield-debug.postrm rename to debian/lightfield.postrm index 8765353e..bbed455a 100644 --- a/debian/lightfield-debug.postrm +++ b/debian/lightfield.postrm @@ -1,5 +1,5 @@ #!/bin/sh -# postrm script for lightfield-debug +# postrm script for lightfield # # see: dh_installdeb(1) # @@ -18,19 +18,13 @@ # for details, see https://www.debian.org/doc/debian-policy/ or # the debian-policy package - -#echo "+ lightfield-debug.postrm: args are $*" 1>&2 case "$1" in - remove) - echo + Setting default back to graphical.target + remove|purge) systemctl set-default graphical.target - echo + Getting default - systemctl get-default - echo + Starting tty1 systemctl start getty@tty1 ;; - purge|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) ;; *) diff --git a/debian/lightfield-debug.preinst b/debian/lightfield.preinst similarity index 87% rename from debian/lightfield-debug.preinst rename to debian/lightfield.preinst index 78bc4b08..b6b40f1a 100644 --- a/debian/lightfield-debug.preinst +++ b/debian/lightfield.preinst @@ -1,5 +1,5 @@ #!/bin/sh -# preinst script for lightfield-debug +# preinst script for lightfield # # see: dh_installdeb(1) # @@ -13,8 +13,6 @@ # for details, see https://www.debian.org/doc/debian-policy/ or # the debian-policy package - -#echo "+ lightfield-debug.preinst: args are $*" 1>&2 case "$1" in install|upgrade|abort-upgrade) ;; diff --git a/debian/lightfield-debug.prerm b/debian/lightfield.prerm similarity index 92% rename from debian/lightfield-debug.prerm rename to debian/lightfield.prerm index ce68d423..0601fbe1 100644 --- a/debian/lightfield-debug.prerm +++ b/debian/lightfield.prerm @@ -1,5 +1,5 @@ #!/bin/sh -# prerm script for lightfield-debug +# prerm script for lightfield # # see: dh_installdeb(1) # @@ -16,8 +16,6 @@ # for details, see https://www.debian.org/doc/debian-policy/ or # the debian-policy package - -#echo "+ lightfield-debug.prerm: args are $*" 1>&2 case "$1" in remove) systemctl daemon-reload diff --git a/debian/release-control b/debian/release-control deleted file mode 100644 index 703b15e3..00000000 --- a/debian/release-control +++ /dev/null @@ -1,44 +0,0 @@ -Source: lightfield -Section: misc -Priority: optional -Maintainer: LightField packager -Build-Depends: - debhelper (>= 11), - libhidapi-dev (>> 0.8), - python3 (>> 3.6), - qtbase5-dev (>= 5.11.1) -Standards-Version: 4.1.3 -Homepage: https://github.com/VolumetricBio/LightField -Vcs-Browser: https://github.com/VolumetricBio/LightField -Vcs-Git: https://github.com/VolumetricBio/LightField.git - -Package: lightfield-release -Architecture: any -Breaks: lightfield-debug -Conflicts: lightfield-debug -Replaces: lightfield-debug -Depends: - lightfield-common (= ${binary:Version}), - ${shlibs:Depends}, - ${misc:Depends}, - libhidapi-libusb0 (>> 0.8), - libqt5dbus5 (>= 5.11.1), - libqt5network5 (>= 5.11.1), - avrdude (>= 6.3), - gpg (>= 2.2.8), - graphicsmagick (>> 1.3), - slic3r (>= 1.2.9), - sudo (>= 1.8.23) -Recommends: - fonts-montserrat (>= 7.200), - fonts-font-awesome (>= 5.0.10) -Description: Printer software for Volumetric's Lumen X 3D printer - release version - -Package: lightfield-common -Architecture: all -Multi-Arch: foreign -Depends: - ${misc:Depends}, - python3 (>= 3.6), - python3-serial (>= 3.4), -Description: Printer software for Volumetric's Lumen X 3D printer - common files diff --git a/dlp4710/90-dlp4710.rules b/dlp4710/90-dlp4710.rules new file mode 100644 index 00000000..33fb2cc3 --- /dev/null +++ b/dlp4710/90-dlp4710.rules @@ -0,0 +1,3 @@ +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="0666", GROUP="plugdev" +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", KERNEL=="ttyUSB[0-9]*", MODE="0666", GROUP="plugdev", SYMLINK+="lumen-projector" +ATTRS{idVendor}=="27b1", ATTRS{idProduct}=="0001", KERNEL=="ttyACM[0-9]*", MODE="0666", GROUP="plugdev", SYMLINK+="lumen-arduino" diff --git a/dlp4710/Makefile b/dlp4710/Makefile new file mode 100644 index 00000000..58a25106 --- /dev/null +++ b/dlp4710/Makefile @@ -0,0 +1,34 @@ +BUILD = debug + +CXX = g++ +LD = g++ +RM = rm + +TARGET = set-projector-power +SOURCES = set-projector-power.cpp +OBJECTS = $(SOURCES:.cpp=.o) + +CFLAGS = -std=gnu++17 -Wall -Wextra -pedantic +LFLAGS = +ifeq ($(BUILD),debug) +CFLAGS += -D_DEBUG -g -Og +LFLAGS += -g +else ifeq ($(BUILD),release) +CFLAGS += -DNDEBUG -O3 +LFLAGS += -s +endif + +all: $(TARGET) + +%.o: %.cpp + $(CXX) $(CFLAGS) -c $< + +$(TARGET): $(OBJECTS) + $(LD) $(LFLAGS) -o $@ $^ + +clean: + -$(RM) $(TARGET) $(OBJECTS) + +## Dependencies + +set-projector-power.o: set-projector-power.cpp diff --git a/dlp4710/set-projector-power.cpp b/dlp4710/set-projector-power.cpp new file mode 100644 index 00000000..96024eac --- /dev/null +++ b/dlp4710/set-projector-power.cpp @@ -0,0 +1,428 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + + enum class Mode { + QueryPowerLevel, + SetPowerLevel, + FirstTimeConfiguration, + }; + + namespace Option { + int const Help = 'h'; + int const FirstTime = 'f'; + int const Monitor = 'm'; + } + + char const ShortOptions[] { ":h?fm" }; + + option const LongOptions[] { + { "help", no_argument, nullptr, Option::Help }, + { "first-time", no_argument, nullptr, Option::FirstTime }, + { "monitor", no_argument, nullptr, Option::Monitor }, + }; + + bool StringToUnsignedLong( char const* ptr, int const radix, unsigned long* result ) { + char* endptr = NULL; + + errno = 0; + unsigned long ret = strtoul( ptr, &endptr, radix ); + if ( endptr != ( ptr + strlen( ptr ) ) ) { + return false; + } + if ( errno == ERANGE && ret == ULONG_MAX ) { + return false; + } + if ( errno != 0 && ret == 0UL ) { + return false; + } + + *result = ret; + return true; + } + + template + bool WriteCommandToProjector( int const fd, char const* format, Args... args ) { + char buf[4096] { }; + snprintf( buf, 4093, format, args... ); + strcat( buf, "\r\n" ); + auto len = strlen( buf ); + auto rc = write( fd, buf, len ); + if ( rc < 0 ) { + perror( "set-projector-power: write" ); + return false; + } else if ( static_cast( rc ) < len ) { + fprintf( stderr, "+ WriteCommandToProjector: short write: %zu expected, %ld written\n", len, rc ); + return false; + } + return true; + } + + bool ReadResponseFromProjector( int const fd, char* buffer, size_t const bufferLength ) { + size_t index = 0; + + memset( buffer, '\0', bufferLength ); + while ( index < bufferLength ) { + auto rc = read( fd, &buffer[index], 1 ); + if ( rc < 0 ) { + perror( "set-projector-power: read" ); + return false; + } else if ( rc == 0 ) { + fprintf( stderr, "+ ReadResponseFromProjector: EOF??\n" ); + return false; + } + + if ( ( index > 0 ) && ( buffer[index - 1] == '\r' ) && ( buffer[index] == '\n' ) ) { + buffer[index - 1] = '\0'; + return true; + } + + ++index; + } + return true; + } + + template + bool SendCommand( int const fd, char* responseBuffer, char const* format, Args... args ) { + if ( !WriteCommandToProjector( fd, format, args... ) ) { + fprintf( stderr, "SendCommand: WriteCommandToProjector failed\n" ); + return false; + } + + if ( !ReadResponseFromProjector( fd, responseBuffer, 4095 ) ) { + fprintf( stderr, "SendCommand: ReadResponseFromProjector failed\n" ); + return false; + } + + return true; + } + + bool IsGoodResponse( char const* result ) { + return ( 0 != strcmp( "ERROR", result ) ); + } + + bool CheckChecksum( unsigned const value, unsigned const checksum ) { + unsigned tempChecksum = 0; + unsigned tempValue = value; + + while ( tempValue > 0 ) { + tempChecksum += tempValue % 10; + tempValue /= 10; + } + + return ( checksum == tempChecksum ); + } + + [[noreturn]] + void PrintUsageAndExit( bool success = false ) { + fprintf( stderr, + "Usage: set-projector-power --first-time\n" + " or: set-projector-power [--monitor] [ []]\n" + "Where:\n" + " -h, -?, --help display this help and exit\n" + " -f, --first-time perform first-time projector configuration\n" + " -m, --monitor monitor projector brightness and temperature\n" + " brightness, range 0..1023\n" + " milliseconds, range 1..65535\n" + ); + exit( success ? EXIT_SUCCESS : EXIT_FAILURE ); + } + + void MonitorPowerAndTemperature( int const fd ) { + unsigned checksum; + unsigned brightness; + unsigned temperature; + siginfo_t sigInfo; + sigset_t sigset; + int sig; + timespec const timeout { 1, 0 }; + char buf[4096] { }; + + sigemptyset( &sigset ); + sigaddset( &sigset, SIGHUP ); + sigaddset( &sigset, SIGINT ); + sigaddset( &sigset, SIGQUIT ); + sigaddset( &sigset, SIGTERM ); + + while ( true ) { + // + // Query LED brightness + // + + if ( !SendCommand( fd, buf, "WT+GLGT" ) ) { + fprintf( stderr, "\nset-projector-power: command WT+GLGT: failed to send command" ); + return; + } + if ( !IsGoodResponse( buf ) ) { + fprintf( stderr, "\nset-projector-power: command WT+GLGT: got negative response '%s'\n", buf ); + return; + } + + errno = 0; + if ( 2 != sscanf( buf, "OK:%u:%u", &brightness, &checksum ) ) { + auto err = errno; + if ( err == 0 ) { + fprintf( stderr, "\nset-projector-power: command WT+GLGT: couldn't parse response '%s'\n", buf ); + } else { + fprintf( stderr, "\nset-projector-power: command WT+GLGT: couldn't parse response '%s': %s [%d]\n", buf, strerror( err ), err ); + } + return; + } + if ( !CheckChecksum( brightness, checksum ) ) { + fprintf( stderr, "\nset-projector-power: command WT+GLGT: got bad checksum\n" ); + goto next; + } + + // + // Query LED temperature + // + + if ( !SendCommand( fd, buf, "WT+GTMP" ) ) { + fprintf( stderr, "\nset-projector-power: command WT+GTMP: failed to send command" ); + return; + } + if ( !IsGoodResponse( buf ) ) { + fprintf( stderr, "\nset-projector-power: command WT+GTMP: got negative response '%s'\n", buf ); + return; + } + + errno = 0; + if ( 2 != sscanf( buf, "OK:%u:%u", &temperature, &checksum ) ) { + auto err = errno; + if ( err == 0 ) { + fprintf( stderr, "\nset-projector-power: command WT+GTMP: couldn't parse response '%s'\n", buf ); + } else { + fprintf( stderr, "\nset-projector-power: command WT+GTMP: couldn't parse response '%s': %s [%d]\n", buf, strerror( err ), err ); + } + return; + } + if ( !CheckChecksum( temperature, checksum ) ) { + fprintf( stderr, "\nset-projector-power: command WT+GTMP: got bad checksum\n" ); + goto next; + } + + printf( "\rbrightness: %4u, temperature: %4u °C", brightness, temperature ); + + next: + sig = sigtimedwait( &sigset, &sigInfo, &timeout ); + if ( -1 == sig ) { + if ( ( EAGAIN == errno ) || ( EINTR == errno ) ) { + continue; + } else { + fputc( '\n', stdout ); + perror( "set-projector-power: sigtimedwait" ); + } + } else if ( SIGINT == sig ) { + fputc( '\n', stdout ); + exit( 0 ); + } else { + fprintf( stderr, "\n+ sigtimedwait: got unknown signal %d?\n", sig ); + } + } + } + +} + +int main( int argc, char** argv ) { + Mode mode { Mode::QueryPowerLevel }; + unsigned long powerLevel { }; + unsigned long duration { 0 }; + int ret { 1 }; + char buf[4096] { }; + int fd { }; + termios term { }; + bool monitor { }; + + setvbuf( stdout, nullptr, _IONBF, 0 ); + + int opt; + do { + opt = getopt_long( argc, argv, ShortOptions, LongOptions, nullptr ); + if ( -1 == opt ) { + break; + } + + if ( Option::FirstTime == opt ) { + if ( monitor ) { + fprintf( stderr, "set-projector-power: options --first-time and --monitor may not be combined\n" ); + PrintUsageAndExit( ); + } + mode = Mode::FirstTimeConfiguration; + } else if ( Option::Monitor == opt ) { + if ( Mode::FirstTimeConfiguration == mode ) { + fprintf( stderr, "set-projector-power: options --first-time and --monitor may not be combined\n" ); + PrintUsageAndExit( ); + } + monitor = true; + } else if ( Option::Help == opt ) { + PrintUsageAndExit( true ); + } else { + PrintUsageAndExit( ); + } + } while ( opt != -1 ); + + if ( Mode::FirstTimeConfiguration != mode ) { + if ( optind < argc ) { + if ( StringToUnsignedLong( argv[optind], 10, &powerLevel ) ) { + if ( powerLevel > 1023 ) { + fprintf( stderr, "set-projector-power: brightness value %lu out of range\n", powerLevel ); + PrintUsageAndExit( ); + } + mode = Mode::SetPowerLevel; + } + ++optind; + } + if ( optind < argc ) { + if ( StringToUnsignedLong( argv[optind], 10, &duration ) ) { + if ( ( 0 == duration ) || ( duration > 65535 ) ) { + fprintf( stderr, "set-projector-power: duration value %lu out of range\n", duration ); + PrintUsageAndExit( ); + } + } + ++optind; + } + } + + fd = open( "/dev/lumen-projector", O_RDWR ); + if ( -1 == fd ) { + perror( "set-projector-power: open" ); + goto bail1; + } + + if ( -1 == tcgetattr( fd, &term ) ) { + perror( "set-projector-power: tcgetattr" ); + goto bail2; + } + + if ( -1 == cfsetispeed( &term, B115200 ) ) { + perror( "set-projector-power: cfsetispeed" ); + goto bail2; + } + if ( -1 == cfsetospeed( &term, B115200 ) ) { + perror( "set-projector-power: cfsetospeed" ); + goto bail2; + } + + cfmakeraw( &term ); + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 5; + + if ( -1 == tcsetattr( fd, TCSANOW, &term ) ) { + perror( "set-projector-power: tcsetattr" ); + goto bail2; + } + + if ( !SendCommand( fd, buf, "WT+PWRE=%d", 1 ) ) { + fprintf( stderr, "set-projector-power: command WT+PWRE: failed to send command" ); + goto bail2; + } + if ( !IsGoodResponse( buf ) ) { + fprintf( stderr, "set-projector-power: command WT+PWRE: got negative response ('%s')\n", buf ); + goto bail2; + } + + switch ( mode ) { + case Mode::FirstTimeConfiguration: + printf( "Setting default boot state\n" ); + if ( !SendCommand( fd, buf, "WT+SPWR=%d", 1 ) ) { + fprintf( stderr, "set-projector-power: command WT+SPWR: failed to send command" ); + goto bail2; + } + if ( !IsGoodResponse( buf ) ) { + fprintf( stderr, "set-projector-power: command WT+SPWR: got negative response ('%s')\n", buf ); + goto bail2; + } + + printf( "Setting default LED state\n" ); + if ( !SendCommand( fd, buf, "WT+SLED=%d", 0 ) ) { + fprintf( stderr, "set-projector-power: command WT+SLED: failed to send command" ); + goto bail2; + } + if ( !IsGoodResponse( buf ) ) { + fprintf( stderr, "set-projector-power: command WT+SLED: got negative response ('%s')\n", buf ); + goto bail2; + } + + printf( "Setting default brightness\n" ); + if ( !SendCommand( fd, buf, "WT+SBTN=%d", 0 ) ) { + fprintf( stderr, "set-projector-power: command WT+SBTN: failed to send command" ); + goto bail2; + } + if ( !IsGoodResponse( buf ) ) { + fprintf( stderr, "set-projector-power: command WT+SBTN: got negative response ('%s')\n", buf ); + goto bail2; + } + + printf( "Done!\n" ); + break; + + case Mode::SetPowerLevel: + if ( !SendCommand( fd, buf, "WT+LEDE=%d", ( 0 == powerLevel ) ? 0 : 1 ) ) { + fprintf( stderr, "set-projector-power: command WT+LEDE: failed to send command" ); + goto bail2; + } + if ( !IsGoodResponse( buf ) ) { + fprintf( stderr, "set-projector-power: command WT+LEDE: got negative response ('%s')\n", buf ); + goto bail2; + } + + if ( !SendCommand( fd, buf, "WT+LEDS=%lu", powerLevel ) ) { + fprintf( stderr, "set-projector-power: command WT+LEDS: failed to send command" ); + goto bail2; + } + if ( !IsGoodResponse( buf ) ) { + fprintf( stderr, "set-projector-power: command WT+LEDS: got negative response ('%s')\n", buf ); + goto bail2; + } + + if ( duration > 0 ) { + if ( !SendCommand( fd, buf, "WT+LEDT=%lu", duration ) ) { + fprintf( stderr, "set-projector-power: command WT+LEDT: failed to send command" ); + goto bail2; + } + if ( !IsGoodResponse( buf ) ) { + fprintf( stderr, "set-projector-power: command WT+LEDT: got negative response ('%s')\n", buf ); + goto bail2; + } + } + // FALLTHROUGH + + case Mode::QueryPowerLevel: + if ( !SendCommand( fd, buf, "WT+LEDR" ) ) { + fprintf( stderr, "set-projector-power: command WT+LEDR: failed to send command" ); + goto bail2; + } + if ( !IsGoodResponse( buf ) ) { + fprintf( stderr, "set-projector-power: command WT+LEDR: got negative response ('%s')\n", buf ); + goto bail2; + } + if ( !StringToUnsignedLong( buf, 10, &powerLevel ) ) { + fprintf( stderr, "set-projector-power: command WT+LEDR: couldn't convert '%s' to a number\n", buf ); + goto bail2; + } + printf( "LED brightness: %lu\n", powerLevel ); + break; + } + + if ( monitor ) { + MonitorPowerAndTemperature( fd ); + } + + ret = 0; + +bail2: + close( fd ); + +bail1: + return ret; +} diff --git a/gpg/new-pubring.gpg b/gpg/new-pubring.gpg deleted file mode 100644 index 7682049b..00000000 Binary files a/gpg/new-pubring.gpg and /dev/null differ diff --git a/gpg/old-pubring.gpg b/gpg/old-pubring.gpg new file mode 100644 index 00000000..041ebb20 Binary files /dev/null and b/gpg/old-pubring.gpg differ diff --git a/gpg/pubring.gpg b/gpg/pubring.gpg index 041ebb20..7682049b 100644 Binary files a/gpg/pubring.gpg and b/gpg/pubring.gpg differ diff --git a/gpg/new-pubring.kbx b/gpg/pubring.kbx similarity index 100% rename from gpg/new-pubring.kbx rename to gpg/pubring.kbx diff --git a/gpg/trustdb.gpg b/gpg/trustdb.gpg index 9b907aed..11879061 100644 Binary files a/gpg/trustdb.gpg and b/gpg/trustdb.gpg differ diff --git a/images/dlp4710-focus-image.png b/images/dlp4710-focus-image.png new file mode 100644 index 00000000..c371c01f Binary files /dev/null and b/images/dlp4710-focus-image.png differ diff --git a/images/dlp4710-white-field.png b/images/dlp4710-white-field.png new file mode 100644 index 00000000..62fda7d2 Binary files /dev/null and b/images/dlp4710-white-field.png differ diff --git a/images/focus-image.png b/images/dlpc350-focus-image.png similarity index 100% rename from images/focus-image.png rename to images/dlpc350-focus-image.png diff --git a/images/white-field.png b/images/dlpc350-white-field.png similarity index 100% rename from images/white-field.png rename to images/dlpc350-white-field.png diff --git a/images/focus-image.svg b/images/focus-image.svg new file mode 100644 index 00000000..ab903ab5 --- /dev/null +++ b/images/focus-image.svg @@ -0,0 +1,526 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 300 + + + 350 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 200 + + + 200 + + + 200 + + + 200 + + + 300 + + + 300 + + + 300 + + + 300 + + + 400 + + + 400 + + + 400 + + + 400 + + + 500 + + + 500 + + + 500 + + + 500 + + + 600 + + + 600 + + + 600 + + + 600 + + + + + + + + + + + + + + + + + + + + + + + 150 + + + 150 + + + 150 + + + 150 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 200 + + + 200 + + + 200 + + + 200 + + + 200 + + + 200 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 200 + + + 200 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + 9 + + 8 + 0 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 4 + + 3 + + 2 + + + + + + + + + + + + + EIA + RESOLUTION + + CHART + + 1956 + + + + + + + + 700 + + + 800 + + + 600 + + + 500 + + + 400 + + + 400 + + + 300 + + + 200 + + + + + + + + + + + 700 + + + 800 + + + 600 + + + 500 + + + 400 + + + 400 + + + 300 + + + 200 + + + + + + + + + + + 700 + + + 800 + + + 600 + + + 500 + + + 400 + + + 400 + + + 300 + + + 200 + + + + + + + + + + + + 700 + + + 800 + + + 600 + + + 500 + + + 400 + + + 400 + + + 300 + + + 200 + + + + + + + + + + + diff --git a/install-lightfield.sh b/install-lightfield.sh index 5ce1d738..b7dbf6ec 100755 --- a/install-lightfield.sh +++ b/install-lightfield.sh @@ -1,6 +1,6 @@ #!/bin/bash -VERSION=1.0.10.0 +LIGHTFIELD_ROOT="${PWD}" ######################################################### ## ## @@ -8,63 +8,54 @@ VERSION=1.0.10.0 ## ## ######################################################### -if [ "${UID}" != "0" ] -then - echo This script must be run as root. - exit 1 -fi - -function clear () { - echo -ne "\x1B[0m\x1B[H\x1B[J\x1B[3J" -} - -function blue-bar () { - echo -e "\r\x1B[1;37;44m$*\x1B[K\x1B[0m" 1>&2 -} - -function red-bar () { - echo -e "\r\x1B[1;33;41m$*\x1B[K\x1B[0m" 1>&2 -} - -function error-trap () { - red-bar Failed\! - exit 1 -} +[ "${UID}" != "0" ] && exec sudo "${0}" "${@}" function usage () { cat </dev/null -echo "deb file:/var/lib/lightfield/software-updates/lightfield-debug_${VERSION}_amd64 ./" > /etc/apt/sources.list.d/volumetric-lightfield.list +perl -lpi -e 's/^(?!##LF## )/##LF## /;' /etc/apt/sources.list /etc/apt/sources.list.d/* 2>/dev/null + +echo "deb file:/var/lib/lightfield/software-updates/lightfield${SUFFIX}_${VERSION}_${ARCHITECTURE} ./" > /etc/apt/sources.list.d/volumetric-lightfield.list chown ${CHXXXVERBOSE} lumen:lumen /etc/apt/sources.list.d/volumetric-lightfield.list systemctl daemon-reload diff --git a/make-deb-package.sh b/make-deb-package.sh index 120e2297..fd3291b1 100755 --- a/make-deb-package.sh +++ b/make-deb-package.sh @@ -1,7 +1,10 @@ #!/bin/bash +# shellcheck disable=SC2103 +# shellcheck disable=SC2164 -VERSION=1.0.10.0 -PACKAGE_BUILD_ROOT=/home/lumen/Volumetric/LightField/packaging +BUILDTYPE= +LIGHTFIELD_ROOT="${PWD}" +PACKAGE_BUILD_ROOT=${LIGHTFIELD_ROOT}/packaging ######################################################### ## ## @@ -9,127 +12,167 @@ PACKAGE_BUILD_ROOT=/home/lumen/Volumetric/LightField/packaging ## ## ######################################################### -function blue-bar () { - echo -e "\r\x1B[1;37;44m$*\x1B[K\x1B[0m" 1>&2 -} - -function red-bar () { - echo -e "\r\x1B[1;33;41m$*\x1B[K\x1B[0m" 1>&2 -} - -function error-trap () { - red-bar Failed\! - exit 1 -} - function usage () { - cat <&2 <&2 -} - -function red-bar () { - echo -e "\r\x1B[1;33;41m$*\x1B[K\x1B[0m" 1>&2 -} - -function error-trap () { - red-bar Failed\! - exit 1 -} - function usage () { cat < Packages.xz -apt-ftparchive --config-file ${LIGHTFIELD_SRC}/apt-files/release.conf release . | tee Release | xz -ceT0 > Release.xz +apt-ftparchive --config-file "${LIGHTFIELD_ROOT}/apt-files/release.conf" release . | tee Release | xz -ceT0 > Release.xz -gpg \ - ${VERBOSE} \ - --batch \ - --armor \ - --local-user "${REPO_KEY_ID}" \ - --output InRelease \ - --clearsign \ +gpg \ + ${VERBOSE} \ + --batch \ + --armor \ + --local-user "${REPO_KEY_ID}" \ + --output InRelease \ + --clearsign \ Release -gpg \ - ${VERBOSE} \ - --batch \ - --armor \ - --local-user "${REPO_KEY_ID}" \ - --output Release.gpg \ - --detach-sign \ +gpg \ + ${VERBOSE} \ + --batch \ + --armor \ + --local-user "${REPO_KEY_ID}" \ + --output Release.gpg \ + --detach-sign \ Release -rm ${VERBOSE} -f \ - version.inf \ +rm ${VERBOSE} -f \ + version.inf \ version.inf.sig -sha256sum -b * | sed -r -e 's/^/ /' -e 's/ +\*/ /' > .hashes +sha256sum -- -b * | sed -r -e 's/^/ /' -e 's/ +\*/ /' > .hashes ( - sed -e "s/@@VERSION@@/${VERSION}/g" -e "s/@@BUILDTYPE@@/${BUILDTYPE}/g" -e "s/@@RELEASEDATE@@/${RELEASEDATE}/g" "${LIGHTFIELD_SRC}/apt-files/version.inf.in" - - # extract description from ${LIGHTFIELD_SRC}/debian/changelog - linecount=$(grep -n '^ -- LightField packager' ${LIGHTFIELD_SRC}/debian/changelog | head -1 | cut -d: -f1 || echo 0) - if [ -z "${linecount}" -o \( "${linecount}" -lt 1 \) ] + sed \ + -e "s/@@ARCHITECTURE@@/${ARCHITECTURE}/g" \ + -e "s/@@BUILDTYPE@@/${BUILDTYPE}/g" \ + -e "s/@@RELEASEDATE@@/${RELEASEDATE}/g" \ + -e "s/@@RELEASE_TRAIN@@/${RELEASE_TRAIN}/g" \ + -e "s/@@VERSION@@/${VERSION}/g" \ + "${LIGHTFIELD_ROOT}/apt-files/version.inf.in" + + # extract description from ${LIGHTFIELD_ROOT}/debian/changelog + linecount=$(grep -n '^ -- LightField packager' "${LIGHTFIELD_ROOT}/debian/changelog" | head -1 | cut -d: -f1 || echo 0) + if [ -z "${linecount}" ] || [ "${linecount}" -lt 1 ] then - red-bar " *** Can't find end of first change in ${LIGHTFIELD_SRC}/debian/changelog, aborting" + red-bar "!!! Can't find end of first change in ${LIGHTFIELD_ROOT}/debian/changelog, aborting" exit 1 fi - head -$((linecount - 2)) ${LIGHTFIELD_SRC}/debian/changelog | tail +3 | perl -lpe 's/\s+$//; s/^$/./; s/^/ /' + head -$((linecount - 2)) "${LIGHTFIELD_ROOT}/debian/changelog" | tail +3 | perl -lpe 's/\s+$//; s/^$/./; s/^/ /' echo 'Checksums-SHA256:' cat .hashes ) > version.inf rm .hashes -gpg \ - ${VERBOSE} \ - --batch \ - --armor \ - --local-user "${PKG_KEY_ID}" \ - --output version.inf.sig \ - --detach-sign \ +gpg \ + ${VERBOSE} \ + --batch \ + --armor \ + --local-user "${PKG_KEY_ID}" \ + --output version.inf.sig \ + --detach-sign \ version.inf -rm \ - ${VERBOSE} \ - -f \ - "${KIT_DIR}/lightfield-${BUILDTYPE}_${VERSION}_amd64.kit" \ - "${KIT_DIR}/lightfield-${BUILDTYPE}_${VERSION}_amd64.kit.sig" \ - "${KIT_DIR}/lightfield-${BUILDTYPE}_${VERSION}_amd64.kit.zip" - -tar \ - ${VERBOSE} ${VERBOSE} \ - -c \ - -f "${KIT_DIR}/lightfield-${BUILDTYPE}_${VERSION}_amd64.kit" \ - --owner=root \ - --group=root \ - --sort=name \ +rm \ + ${VERBOSE} \ + -f \ + "${KIT_DIR}/lightfield-${SUFFIX}_${VERSION}_${ARCHITECTURE}.kit" \ + "${KIT_DIR}/lightfield-${SUFFIX}_${VERSION}_${ARCHITECTURE}.kit.sig" \ + "${KIT_DIR}/lightfield-${SUFFIX}_${VERSION}_${ARCHITECTURE}.kit.zip" + +tar \ + ${VERBOSE} ${VERBOSE} \ + -c \ + -f "${KIT_DIR}/lightfield-${SUFFIX}_${VERSION}_${ARCHITECTURE}.kit" \ + --owner=root \ + --group=root \ + --sort=name \ + -- \ * -cd ${KIT_DIR} +cd "${KIT_DIR}" -gpg \ - ${VERBOSE} \ - --batch \ - --armor \ - --local-user "${PKG_KEY_ID}" \ - --output "lightfield-${BUILDTYPE}_${VERSION}_amd64.kit.sig" \ - --detach-sign \ - "lightfield-${BUILDTYPE}_${VERSION}_amd64.kit" +gpg \ + ${VERBOSE} \ + --batch \ + --armor \ + --local-user "${PKG_KEY_ID}" \ + --output "lightfield-${SUFFIX}_${VERSION}_${ARCHITECTURE}.kit.sig" \ + --detach-sign \ + "lightfield-${SUFFIX}_${VERSION}_${ARCHITECTURE}.kit" -zip \ - -0joq \ - "lightfield-${BUILDTYPE}_${VERSION}_amd64.kit.zip" \ - "lightfield-${BUILDTYPE}_${VERSION}_amd64.kit" \ - "lightfield-${BUILDTYPE}_${VERSION}_amd64.kit.sig" +zip \ + -0joq \ + "lightfield-${SUFFIX}_${VERSION}_${ARCHITECTURE}.kit.zip" \ + "lightfield-${SUFFIX}_${VERSION}_${ARCHITECTURE}.kit" \ + "lightfield-${SUFFIX}_${VERSION}_${ARCHITECTURE}.kit.sig" -blue-bar • Cleaning up +blue-bar "• Cleaning up" cd .. -rm ${VERBOSE} -rf ${REPO_DIR} +rm ${VERBOSE} -rf "${REPO_DIR}" blue-bar "" blue-bar "• Done!" diff --git a/mountmon/CMakeLists.txt b/mountmon/CMakeLists.txt index 5f071dbb..69ae720c 100644 --- a/mountmon/CMakeLists.txt +++ b/mountmon/CMakeLists.txt @@ -13,7 +13,7 @@ set(MOUNTMON_VERSION_PATCH "0") set(PROJECT_VERSION "${MOUNTMON_VERSION_MAJOR}.${MOUNTMON_VERSION_MINOR}.${MOUNTMON_VERSION_PATCH}") if(WIN32) -set (Qt5_DIR "F:\\\\Qt\\\\5.13.1\\\\msvc2017_64\\\\lib\\\\cmake\\\\Qt5") +set (Qt5_DIR "F:\\\\Qt\\\\5.14.0\\\\msvc2017_64\\\\lib\\\\cmake\\\\Qt5") endif(WIN32) project(mountmon) diff --git a/LightFieldSymlinksFix.sh b/old-scripts/LightFieldSymlinksFix.sh similarity index 100% rename from LightFieldSymlinksFix.sh rename to old-scripts/LightFieldSymlinksFix.sh diff --git a/MakeLightFieldDirectories b/old-scripts/MakeLightFieldDirectories similarity index 100% rename from MakeLightFieldDirectories rename to old-scripts/MakeLightFieldDirectories diff --git a/PrepareSystem.sh b/old-scripts/PrepareSystem.sh similarity index 100% rename from PrepareSystem.sh rename to old-scripts/PrepareSystem.sh diff --git a/SetUp b/old-scripts/SetUp similarity index 100% rename from SetUp rename to old-scripts/SetUp diff --git a/print-profiles/.print-profiles.json.swp b/print-profiles/.print-profiles.json.swp new file mode 100644 index 00000000..74072201 Binary files /dev/null and b/print-profiles/.print-profiles.json.swp differ diff --git a/print-profiles/print-profiles-schema.json b/print-profiles/print-profiles-schema.json new file mode 100644 index 00000000..3bb84840 --- /dev/null +++ b/print-profiles/print-profiles-schema.json @@ -0,0 +1,244 @@ + 1 { + 2 "definitions": {}, + 3 "$schema": "", + 4 "$id": "http://example.com/root.json", + 5 "type": "array", + 6 "title": "Print profiles", + 7 "description": "List of print profiles", + 8 "default": null, + 9 "readOnly": false, + 10 "items": { + 11 "$id": "#/items", + 12 "type": "object", + 13 "title": "PrintProfile", + 14 "description": "Single print profile", + 15 "default": null, + 16 "readOnly": false, + 17 "additionalProperties": false, + 18 "required": [ + 19 "name", + 20 "baseLayerCount", + 21 "baseLayersPumpingParameters", + 22 "bodyLayersPumpingParameters" + 23 ], + 24 "properties": { + 25 "name": { + 26 "$id": "#/items/properties/name", + 27 "type": "string", + 28 "title": "The Name Schema", + 29 "default": "", + 30 "examples": [ + 31 "exampleProfile" + 32 ], + 33 "pattern": "^(.*)$" + 34 }, + 35 "baseLayerCount": { + 36 "$id": "#/items/properties/baseLayerCount", + 37 "type": "integer", + 38 "title": "The Baselayercount Schema", + 39 "default": 0, + 40 "examples": [ + 41 1 + 42 ] + 43 }, + 44 "baseLayersPumpingParameters": { + 45 "$id": "#/items/properties/baseLayersPumpingParameters", + 46 "type": "object", + 47 "title": "The Baselayerspumpingparameters Schema", + 48 "required": [ + 49 "pumpUpDistance", + 50 "pumpUpTime", + 51 "pumpUpPause", + 52 "pumpDownPause", + 53 "noPumpUpVelocity", + 54 "pumpEveryNthLayer", + 55 "layerThickness", + 56 "layerExposureTime", + 57 "powerLevel" + 58 ], + 59 "properties": { + 60 "pumpUpDistance": { + 61 "$id": "#/items/properties/baseLayersPumpingParameters/properties/pumpUpDistance", + 62 "type": "number", + 63 "title": "The Pumpupdistance Schema", + 64 "default": 0, + 65 "examples": [ + 66 2 + 67 ] + 68 }, + 69 "pumpUpTime": { + 70 "$id": "#/items/properties/baseLayersPumpingParameters/properties/pumpUpTime", + 71 "type": "integer", + 72 "title": "The Pumpuptime Schema", + 73 "default": 0, + 74 "examples": [ + 75 600 + 76 ] + 77 }, + 78 "pumpUpPause": { + 79 "$id": "#/items/properties/baseLayersPumpingParameters/properties/pumpUpPause", + 80 "type": "integer", + 81 "title": "The Pumpuppause Schema", + 82 "default": 0, + 83 "examples": [ + 84 2000 + 85 ] + 86 }, + 87 "pumpDownPause": { + 88 "$id": "#/items/properties/baseLayersPumpingParameters/properties/pumpDownPause", + 89 "type": "integer", + 90 "title": "The Pumpdownpause Schema", + 91 "default": 0, + 92 "examples": [ + 93 4000 + 94 ] + 95 }, + 96 "noPumpUpVelocity": { + 97 "$id": "#/items/properties/baseLayersPumpingParameters/properties/noPumpUpVelocity", + 98 "type": "integer", + 99 "title": "The Nopumpupvelocity Schema", +100 "default": 0, +101 "examples": [ +102 200 +103 ] +104 }, +105 "pumpEveryNthLayer": { +106 "$id": "#/items/properties/baseLayersPumpingParameters/properties/pumpEveryNthLayer", +107 "type": "integer", +108 "title": "The Pumpeverynthlayer Schema", +109 "default": 0, +110 "examples": [ +111 1 +112 ] +113 }, +114 "layerThickness": { +115 "$id": "#/items/properties/baseLayersPumpingParameters/properties/layerThickness", +116 "type": "integer", +117 "title": "The Layerthickness Schema", +118 "default": 0, +119 "examples": [ +120 100 +121 ] +122 }, +123 "layerExposureTime": { +124 "$id": "#/items/properties/baseLayersPumpingParameters/properties/layerExposureTime", +125 "type": "integer", +126 "title": "The Layerexposuretime Schema", +127 "default": 0, +128 "examples": [ +129 1000 +130 ] +131 }, +132 "powerLevel": { +133 "$id": "#/items/properties/baseLayersPumpingParameters/properties/powerLevel", +134 "type": "number", +135 "title": "The Powerlevel Schema", +136 "default": 0, +137 "examples": [ +138 50 +139 ] +140 } +141 } +142 }, +143 "bodyLayersPumpingParameters": { +144 "$id": "#/items/properties/bodyLayersPumpingParameters", +145 "type": "object", +146 "title": "The Bodylayerspumpingparameters Schema", +147 "required": [ +148 "pumpUpDistance", +149 "pumpUpTime", +150 "pumpUpPause", +151 "pumpDownPause", +152 "noPumpUpVelocity", +153 "pumpEveryNthLayer", +154 "layerThickness", +155 "layerExposureTime", +156 "powerLevel" +157 ], +158 "properties": { +159 "pumpUpDistance": { +160 "$id": "#/items/properties/bodyLayersPumpingParameters/properties/pumpUpDistance", +161 "type": "number", +162 "title": "The Pumpupdistance Schema", +163 "default": 0, +164 "examples": [ +165 2 +166 ] +167 }, +168 "pumpUpTime": { +169 "$id": "#/items/properties/bodyLayersPumpingParameters/properties/pumpUpTime", +170 "type": "integer", +171 "title": "The Pumpuptime Schema", +172 "default": 0, +173 "examples": [ +174 600 +175 ] +176 }, +177 "pumpUpPause": { +178 "$id": "#/items/properties/bodyLayersPumpingParameters/properties/pumpUpPause", +179 "type": "integer", +180 "title": "The Pumpuppause Schema", +181 "default": 0, +182 "examples": [ +183 2000 +184 ] +185 }, +186 "pumpDownPause": { +187 "$id": "#/items/properties/bodyLayersPumpingParameters/properties/pumpDownPause", +188 "type": "integer", +189 "title": "The Pumpdownpause Schema", +190 "default": 0, +191 "examples": [ +192 4000 +193 ] +194 }, +195 "noPumpUpVelocity": { +196 "$id": "#/items/properties/bodyLayersPumpingParameters/properties/noPumpUpVelocity", +197 "type": "integer", +198 "title": "The Nopumpupvelocity Schema", +199 "default": 0, +200 "examples": [ +201 200 +202 ] +203 }, +204 "pumpEveryNthLayer": { +205 "$id": "#/items/properties/bodyLayersPumpingParameters/properties/pumpEveryNthLayer", +206 "type": "integer", +207 "title": "The Pumpeverynthlayer Schema", +208 "default": 0, +209 "examples": [ +210 1 +211 ] +212 }, +213 "layerThickness": { +214 "$id": "#/items/properties/bodyLayersPumpingParameters/properties/layerThickness", +215 "type": "integer", +216 "title": "The Layerthickness Schema", +217 "default": 0, +218 "examples": [ +219 100 +220 ] +221 }, +222 "layerExposureTime": { +223 "$id": "#/items/properties/bodyLayersPumpingParameters/properties/layerExposureTime", +224 "type": "integer", +225 "title": "The Layerexposuretime Schema", +226 "default": 0, +227 "examples": [ +228 1000 +229 ] +230 }, +231 "powerLevel": { +232 "$id": "#/items/properties/bodyLayersPumpingParameters/properties/powerLevel", +233 "type": "number", +234 "title": "The Powerlevel Schema", +235 "default": 0, +236 "examples": [ +237 50 +238 ] +239 } +240 } +241 } +242 } +243 } +244 } diff --git a/print-profiles/print-profiles.json b/print-profiles/print-profiles.json new file mode 100644 index 00000000..814ab89d --- /dev/null +++ b/print-profiles/print-profiles.json @@ -0,0 +1,28 @@ +[ + { + "name": "exampleProfile", + "baseLayerCount": 1, + "baseLayersPumpingParameters": { + "pumpUpDistance": 2.00, + "pumpUpTime": 600, + "pumpUpPause": 2000, + "pumpDownPause": 4000, + "noPumpUpVelocity": 200, + "pumpEveryNthLayer": 1, + "layerThickness": 100, + "layerExposureTime": 1000, + "powerLevel": 50.0 + }, + "bodyLayersPumpingParameters": { + "pumpUpDistance": 2.00, + "pumpUpTime": 600, + "pumpUpPause": 2000, + "pumpDownPause": 4000, + "noPumpUpVelocity": 200, + "pumpEveryNthLayer": 1, + "layerThickness": 100, + "layerExposureTime": 1000, + "powerLevel": 50.0 + } + } +] diff --git a/qt/lf.pro b/qt/lf.pro index 87cbdc3c..41a38653 100644 --- a/qt/lf.pro +++ b/qt/lf.pro @@ -7,88 +7,105 @@ QMAKE_CXXFLAGS_RELEASE -= -O2 QMAKE_CXXFLAGS_RELEASE += -O3 -DNDEBUG -Wall -Wextra -Winvalid-pch -Wno-unused-result QMAKE_CXXFLAGS_DEBUG += -Og -D_DEBUG -Wall -Wextra -Winvalid-pch -Wno-unused-result -SOURCES += \ - ../src/advancedtab.cpp \ - ../src/app.cpp \ - ../src/backdrop.cpp \ - ../src/buildinfo.cpp \ - ../src/canvas.cpp \ - ../src/constants.cpp \ - ../src/debug.cpp \ - ../src/debuglogcopier.cpp \ - ../src/filecopier.cpp \ - ../src/filetab.cpp \ - ../src/gesturelistview.cpp \ - ../src/glmesh.cpp \ - ../src/gpgsignaturechecker.cpp \ - ../src/hasher.cpp \ - ../src/lightfieldstyle.cpp \ - ../src/loader.cpp \ - ../src/main.cpp \ - ../src/mesh.cpp \ - ../src/pngdisplayer.cpp \ - ../src/preparetab.cpp \ - ../src/printmanager.cpp \ - ../src/printtab.cpp \ - ../src/processrunner.cpp \ - ../src/shepherd.cpp \ - ../src/signalhandler.cpp \ - ../src/statustab.cpp \ - ../src/stdiologger.cpp \ - ../src/strings.cpp \ - ../src/svgrenderer.cpp \ - ../src/systemtab.cpp \ - ../src/tabbase.cpp \ - ../src/timinglogger.cpp \ - ../src/upgradekitunpacker.cpp \ - ../src/upgrademanager.cpp \ - ../src/upgradeselector.cpp \ - ../src/usbmountmanager.cpp \ - ../src/utils.cpp \ +SOURCES += \ + ../src/advancedtab.cpp \ + ../src/advancedtabselectionmodel.cpp \ + ../src/app.cpp \ + ../src/backdrop.cpp \ + ../src/buildinfo.cpp \ + ../src/canvas.cpp \ + ../src/constants.cpp \ + ../src/debug.cpp \ + ../src/debuglogcopier.cpp \ + ../src/filecopier.cpp \ + ../src/filetab.cpp \ + ../src/gesturelistview.cpp \ + ../src/glmesh.cpp \ + ../src/gpgsignaturechecker.cpp \ + ../src/hasher.cpp \ + ../src/key.cpp \ + ../src/keyboard.cpp \ + ../src/lightfieldstyle.cpp \ + ../src/loader.cpp \ + ../src/main.cpp \ + ../src/mesh.cpp \ + ../src/paramslider.cpp \ + ../src/pngdisplayer.cpp \ + ../src/preparetab.cpp \ + ../src/printmanager.cpp \ + ../src/printprofile.cpp \ + ../src/printprofilemanager.cpp \ + ../src/printtab.cpp \ + ../src/processrunner.cpp \ + ../src/profilestab.cpp \ + ../src/shepherd.cpp \ + ../src/signalhandler.cpp \ + ../src/statustab.cpp \ + ../src/stdiologger.cpp \ + ../src/strings.cpp \ + ../src/svgrenderer.cpp \ + ../src/systemtab.cpp \ + ../src/tabbase.cpp \ + ../src/timinglogger.cpp \ + ../src/upgradekitunpacker.cpp \ + ../src/upgrademanager.cpp \ + ../src/upgradeselector.cpp \ + ../src/usbmountmanager.cpp \ + ../src/utils.cpp \ ../src/window.cpp -HEADERS += \ - ../src/advancedtab.h \ - ../src/app.h \ - ../src/backdrop.h \ - ../src/buildinfo.h \ - ../src/canvas.h \ - ../src/constants.h \ - ../src/coordinate.h \ - ../src/debug.h \ - ../src/debuglogcopier.h \ - ../src/filecopier.h \ - ../src/filetab.h \ - ../src/gesturelistview.h \ - ../src/glmesh.h \ - ../src/gpgsignaturechecker.h \ - ../src/hasher.h \ - ../src/initialshoweventmixin.h \ - ../src/lightfieldstyle.h \ - ../src/loader.h \ - ../src/mesh.h \ - ../src/pngdisplayer.h \ - ../src/preparetab.h \ - ../src/printjob.h \ - ../src/printmanager.h \ - ../src/printtab.h \ - ../src/processrunner.h \ - ../src/shepherd.h \ - ../src/signalhandler.h \ - ../src/statustab.h \ - ../src/stdiologger.h \ - ../src/strings.h \ - ../src/svgrenderer.h \ - ../src/systemtab.h \ - ../src/tabbase.h \ - ../src/timinglogger.h \ - ../src/upgradekitunpacker.h \ - ../src/upgrademanager.h \ - ../src/upgradeselector.h \ - ../src/usbmountmanager.h \ - ../src/utils.h \ - ../src/version.h \ - ../src/vertex.h \ +HEADERS += \ + ../src/advancedtab.h \ + ../src/advancedtabselectionmodel.h \ + ../src/app.h \ + ../src/backdrop.h \ + ../src/buildinfo.h \ + ../src/canvas.h \ + ../src/constants.h \ + ../src/coordinate.h \ + ../src/debug.h \ + ../src/debuglogcopier.h \ + ../src/filecopier.h \ + ../src/filetab.h \ + ../src/gesturelistview.h \ + ../src/glmesh.h \ + ../src/gpgsignaturechecker.h \ + ../src/hasher.h \ + ../src/inputdialog.h \ + ../src/key.h \ + ../src/keyboard.h \ + ../src/initialshoweventmixin.h \ + ../src/lightfieldstyle.h \ + ../src/loader.h \ + ../src/mesh.h \ + ../src/paramslider.h \ + ../src/pngdisplayer.h \ + ../src/preparetab.h \ + ../src/printjob.h \ + ../src/printmanager.h \ + ../src/printprofile.h \ + ../src/printprofilemanager.h \ + ../src/printpumpingparameters.h \ + ../src/printtab.h \ + ../src/processrunner.h \ + ../src/profilesjsonparser.h \ + ../src/profilestab.h \ + ../src/shepherd.h \ + ../src/signalhandler.h \ + ../src/statustab.h \ + ../src/stdiologger.h \ + ../src/strings.h \ + ../src/svgrenderer.h \ + ../src/systemtab.h \ + ../src/tabbase.h \ + ../src/timinglogger.h \ + ../src/upgradekitunpacker.h \ + ../src/upgrademanager.h \ + ../src/upgradeselector.h \ + ../src/usbmountmanager.h \ + ../src/utils.h \ + ../src/version.h \ + ../src/vertex.h \ ../src/window.h CONFIG += c++1z precompile_header @@ -111,3 +128,14 @@ static { debug { QMAKE_CXXFLAGS_WARN_ON += -Wno-class-memaccess } + +dlp4710 { + DEFINES += DLP4710 +} + +TARGET = lf +TEMPLATE = app + +QMAKE_CXXFLAGS_RELEASE -= -O2 +QMAKE_CXXFLAGS_RELEASE += -O3 -DNDEBUG -Wall -Wextra -Winvalid-pch -Wno-unused-result +QMAKE_CXXFLAGS_DEBUG += -Og -D_DEBUG -Wall -Wextra -Winvalid-pch -Wno-unused-result diff --git a/rebuild b/rebuild index 283505a1..ea764e95 100755 --- a/rebuild +++ b/rebuild @@ -1,18 +1,20 @@ -#!/usr/bin/env bash +#!/bin/bash -if [ -z "${BUILDDIR}" ] -then - export BUILDDIR="/home/lumen/Volumetric/LightField/build" -fi +LIGHTFIELD_ROOT="${PWD}" -rebuild () { - local BUILD=debug - local CLEAN= - local NUKE= - local QMAKE= +######################################################### +## ## +## No user-serviceable parts below this point. ## +## ## +######################################################### - if ! getopt -Q -q -n 'rebuild' -o 'cnqrx' -l 'clean,nuke-first,qmake-anyway,release' -- "$@"; then - cat < ${BUILDDIR}/.lastbuildmode - NUKE=yes - fi - - local LASTBUILDMODE="$(<${BUILDDIR}/.lastbuildmode)" - if [ -n "${LASTBUILDMODE}" -a "${BUILD}" != "${LASTBUILDMODE}" ] - then - echo Switching from ${LASTBUILDMODE} to ${BUILD}. - NUKE=yes - fi - - if [ -n "${NUKE}" ] - then - unset CLEAN - QMAKE=yes - rm -dr ${BUILDDIR} && mkdir -p ${BUILDDIR} - fi + if [ ! -f "${BUILDDIR}/.lastbuildmode" ] + then + echo "${BUILD}:${RELEASE_TRAIN}" > "${BUILDDIR}/.lastbuildmode" + NUKE=yes + fi + + LASTBUILDMODE=$(<"${BUILDDIR}/.lastbuildmode") + if [ -n "${LASTBUILDMODE}" ] && [ "${LASTBUILDMODE}" != "${BUILD}:${RELEASE_TRAIN}" ] + then + echo Switching from "${LASTBUILDMODE}" to "${BUILD}:${RELEASE_TRAIN}". + NUKE=yes + fi + + if [ -n "${NUKE}" ] + then + unset CLEAN + QMAKE=yes + rm -dr "${BUILDDIR}" && mkdir -p "${BUILDDIR}" + fi else - mkdir -p ${BUILDDIR} + mkdir -p "${BUILDDIR}" fi - cd ${BUILDDIR} + if [ ! -f "${LIGHTFIELD_ROOT}/src/version.h" ] + then + if [ -n "${RELEASE_TRAIN}" ] && [ -n "${VERSION}" ] + then + if ! "${LIGHTFIELD_ROOT}/change-version-number.sh" -t "${RELEASE_TRAIN}" "${VERSION}" + then + red-bar "Unable to generate missing src/version.h." + red-bar "Run change-version-number.sh manually." + exit 1 + fi + else + red-bar "src/version.h does not exist, and the version number is unconfigured." + red-bar "Run change-version-number.sh manually." + exit 1 + fi + fi + + # shellcheck disable=SC2164 + cd "${BUILDDIR}" if [ -n "${CLEAN}" ] then - QMAKE=yes - make distclean + QMAKE=yes + make distclean + fi + + if [ -n "${QMAKE}" ] || [ ! -f Makefile ] || [ ../qt/lf.pro -nt Makefile ] + then + qmake CONFIG+="${BUILD}" ${ADDTOCONFIG} ../qt/lf.pro || return + echo "${BUILD}:${RELEASE_TRAIN}" > "${BUILDDIR}/.lastbuildmode" fi - if [ -n "${QMAKE}" -o ! -f Makefile -o ../qt/lf.pro -nt Makefile ] + if [ "${RELEASE_TRAIN}" = "base" ] + then + cp -a ../images/dlpc350-focus-image.png ../images/focus-image.png + cp -a ../images/dlpc350-white-field.png ../images/white-field.png + elif [ "${RELEASE_TRAIN}" = "dlp4710" ] then - qmake CONFIG+=${BUILD} ../qt/lf.pro || return - echo "${BUILD}" > ${BUILDDIR}/.lastbuildmode + cp -a ../images/dlp4710-focus-image.png ../images/focus-image.png + cp -a ../images/dlp4710-white-field.png ../images/white-field.png fi - if ! make -q + if make -q 1>/dev/null 2>&1 then - rm buildinfo.o + echo "make: Nothing to be done for 'first'." + return fi - make -j${QT_BUILD_JOBS-12} + # shellcheck disable=SC2015 + [ -f buildinfo.o ] && rm buildinfo.o 1>/dev/null 2>&1 || true + make -j"${QT_BUILD_JOBS-12}" } -rebuild $* +rebuild "$@" diff --git a/shared-stuff.sh b/shared-stuff.sh new file mode 100644 index 00000000..174d9aaf --- /dev/null +++ b/shared-stuff.sh @@ -0,0 +1,66 @@ +#!/bin/bash +#shellcheck disable=SC2034 + +function clear () { + echo -ne "\x1B[0m\x1B[H\x1B[J\x1B[3J" +} + +function blue-bar () { + echo -e "\r\e[1;37;44m$*\e[K\e[0m" 1>&2 +} + +function red-bar () { + echo -e "\r\e[1;33;41m$*\e[K\e[0m" 1>&2 +} + +function error-trap () { + red-bar 'Failed!' + exit 1 +} + +function apply-atsign-substitution () { + local CODE='\e[0;30;48;2;146;208;80m' + local RST='\e[0m' + # shellcheck disable=SC2145 + echo -e "Substituting value ${CODE}${2}${RST} for token ${CODE}@@${1}@@${RST} in files ${CODE}${@:3}${RST}" + sed -i "s/@@${1}@@/${2}/g" "${@:3}" +} + +function apply-assignment-substitution () { + local CODE='\e[0;30;48;2;0;146;208m' + local RST='\e[0m' + # shellcheck disable=SC2145 + echo -e "Substituting value ${CODE}${2}${RST} into variable assignment ${CODE}${1}${RST} in files ${CODE}${@:3}${RST}" + sed -i 's/^'"${1}"'=.*$/'"${1}"'='"${2}"'/g' "${@:3}" +} + +function generate-suffix () { + local RELEASE_TRAIN="${1}" + local BUILDTYPE="${2}" + + if [ -z "${RELEASE_TRAIN}" ] + then + RELEASE_TRAIN=base + fi + + if [ "${RELEASE_TRAIN}" = "base" ] + then + echo "${BUILDTYPE}" + else + echo "${RELEASE_TRAIN}-${BUILDTYPE}" + fi +} + +DEFAULT_RELEASE_TRAIN=base +DEFAULT_ARCHITECTURE=$(uname -m) +if [ "${DEFAULT_ARCHITECTURE}" = "x86_64" ] +then + DEFAULT_ARCHITECTURE=amd64 +fi + +ARCHITECTURE=amd64 +RELEASE_TRAIN=dlp4710 +VERSION=1.0.11.0 + +trap error-trap ERR +set -e diff --git a/src/advancedtab.cpp b/src/advancedtab.cpp index edad9822..ba8f7df8 100644 --- a/src/advancedtab.cpp +++ b/src/advancedtab.cpp @@ -6,6 +6,9 @@ #include "printjob.h" #include "printmanager.h" #include "shepherd.h" +#include "advancedtabselectionmodel.h" +#include "paramslider.h" +#include namespace { @@ -18,186 +21,92 @@ AdvancedTab::AdvancedTab( QWidget* parent ): TabBase( parent ) { auto boldFont = ModifyFont( origFont, QFont::Bold ); auto fontAwesome = ModifyFont( origFont, "FontAwesome", LargeFontSize ); - - _currentTemperatureLabel->setText( "Current temperature:" ); - _targetTemperatureLabel ->setText( "Target temperature:" ); - _heatingElementLabel ->setText( "Heating element:" ); - _zPositionLabel ->setText( "Z position:" ); - - - _currentTemperature->setAlignment( Qt::AlignRight ); - _currentTemperature->setFont( boldFont ); - _currentTemperature->setText( EmDash ); - - _targetTemperature ->setAlignment( Qt::AlignRight ); - _targetTemperature ->setFont( boldFont ); - _targetTemperature ->setText( EmDash ); - - _heatingElement ->setAlignment( Qt::AlignRight ); - _heatingElement ->setFont( boldFont ); - _heatingElement ->setText( EmDash ); - - _zPosition ->setAlignment( Qt::AlignRight ); - _zPosition ->setFont( boldFont ); - _zPosition ->setText( EmDash ); - - - _leftColumn->setContentsMargins( { } ); - _leftColumn->setFixedWidth( MainButtonSize.width( ) ); - _leftColumn->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding ); - _leftColumn->setLayout( WrapWidgetsInVBox( - WrapWidgetsInHBox( _currentTemperatureLabel, nullptr, _currentTemperature ), - WrapWidgetsInHBox( _targetTemperatureLabel, nullptr, _targetTemperature ), - WrapWidgetsInHBox( _heatingElementLabel, nullptr, _heatingElement ), - WrapWidgetsInHBox( _zPositionLabel, nullptr, _zPosition ), - nullptr - ) ); - - - _offsetLabel->setText( "Build platform offset:" ); - - _offsetValue->setAlignment( Qt::AlignRight ); - _offsetValue->setFont( boldFont ); - _offsetValue->setText( QString { "%1 µm" }.arg( g_settings.buildPlatformOffset ) ); - - _offsetSlider->setMinimum( 0 ); - _offsetSlider->setMaximum( 40 ); - _offsetSlider->setOrientation( Qt::Horizontal ); - _offsetSlider->setPageStep( 4 ); - _offsetSlider->setSingleStep( 1 ); - _offsetSlider->setTickInterval( 4 ); - _offsetSlider->setTickPosition( QSlider::TicksBothSides ); - _offsetSlider->setValue( g_settings.buildPlatformOffset / 25 ); - QObject::connect( _offsetSlider, &QSlider::sliderReleased, this, &AdvancedTab::offsetSlider_sliderReleased ); - QObject::connect( _offsetSlider, &QSlider::valueChanged, this, &AdvancedTab::offsetSlider_valueChanged ); - - - _buildPlatformOffsetGroup->setContentsMargins( { } ); - _buildPlatformOffsetGroup->setLayout( WrapWidgetsInVBoxDM( - WrapWidgetsInHBox( _offsetLabel, nullptr, _offsetValue ), - _offsetSlider - ) ); - - - _bedHeatingButton->setCheckable( true ); - _bedHeatingButton->setChecked( false ); - _bedHeatingButton->setFont( fontAwesome ); - _bedHeatingButton->setFixedSize( 37, 38 ); - _bedHeatingButton->setText( FA_Times ); - QObject::connect( _bedHeatingButton, &QPushButton::clicked, this, &AdvancedTab::printBedHeatingButton_clicked ); - - _bedHeatingButtonLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); - _bedHeatingButtonLabel->setText( "Print bed heating" ); - -#if defined ENABLE_TEMPERATURE_SETTING - _bedTemperatureLabel->setEnabled( false ); - _bedTemperatureLabel->setText( "Print bed temperature:" ); - - _bedTemperatureValue->setAlignment( Qt::AlignRight ); - _bedTemperatureValue->setEnabled( false ); - _bedTemperatureValue->setFont( boldFont ); - _bedTemperatureValue->setText( QString { "%1 °C" }.arg( DefaultPrintBedTemperature ) ); - - _bedTemperatureValueLayout = WrapWidgetsInHBox( _bedTemperatureLabel, nullptr, _bedTemperatureValue ); - _bedTemperatureValueLayout->setEnabled( false ); - - _bedTemperatureSlider->setEnabled( false ); - _bedTemperatureSlider->setMinimum( 30 ); - _bedTemperatureSlider->setMaximum( 50 ); - _bedTemperatureSlider->setOrientation( Qt::Horizontal ); - _bedTemperatureSlider->setPageStep( 1 ); - _bedTemperatureSlider->setSingleStep( 1 ); - _bedTemperatureSlider->setTickInterval( 5 ); - _bedTemperatureSlider->setTickPosition( QSlider::TicksBothSides ); - _bedTemperatureSlider->setValue( DefaultPrintBedTemperature ); - QObject::connect( _bedTemperatureSlider, &QSlider::sliderReleased, this, &AdvancedTab::printBedTemperatureSlider_sliderReleased ); - QObject::connect( _bedTemperatureSlider, &QSlider::valueChanged, this, &AdvancedTab::printBedTemperatureSlider_valueChanged ); -#endif - - auto bedTemperatureLayout = WrapWidgetsInVBoxDM( - WrapWidgetsInHBox( _bedHeatingButton, _bedHeatingButtonLabel, nullptr ) + _forms[0] = _generalForm; + _forms[1] = _temperatureForm; + _forms[2] = _basePumpForm; + _forms[3] = _baseLayerForm; + _forms[4] = _bodyLayersForm; + _forms[5] = _bodyPumpForm; + + QWidget::connect(_distanceSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_upTimeSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_upPauseSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_downTimeSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_downPauseSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_upVelocitySlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_numberOfBaseLayersSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_baseThicknessSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_baseExposureTimeSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_bodyThicknessSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_bodyExposureTimeSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_bodyPumpEveryNthLayer, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_bodyDistanceSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_bodyUpTimeSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_bodyUpPauseSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_bodyDownTimeSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_bodyDownPauseSlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + QWidget::connect(_bodyUpVelocitySlider, &ParamSlider::valuechanged, this, &AdvancedTab::updatePrintProfile); + + //menu + this->_setupLeftMenu(fontAwesome); + + // General form + this->_setupGeneralForm(boldFont, fontAwesome); + + // Temperature form + this->_setupTemperaturelForm(boldFont); + + //Base Pump Form + this->_setupBasePumpForm(boldFont); + + //Base Layer Form + this->_setupBaseLayerForm(); + + //Body Layers Form + this->_setupBodyLayersForm(); + + //Body Pump Form + this->_setupBodyPumpForm(boldFont); + + for(int i=1; isetVisible(false); + + + _rightColumn->setLayout(WrapWidgetsInVBox(_generalForm, _temperatureForm, _basePumpForm, _baseLayerForm, + _bodyLayersForm, _bodyPumpForm, nullptr)); + + setLayout( WrapWidgetsInHBox( + WrapWidgetsInVBox( _leftMenu ), + _rightColumn, nullptr + ) ); -#if defined ENABLE_TEMPERATURE_SETTING - bedTemperatureLayout->addLayout( _bedTemperatureValueLayout ); - bedTemperatureLayout->addWidget( _bedTemperatureSlider ); -#endif - - _bedHeatingGroup->setContentsMargins( { } ); - _bedHeatingGroup->setLayout( bedTemperatureLayout ); - - - _projectBlankImageButton->setCheckable( true ); - _projectBlankImageButton->setChecked( false ); - _projectBlankImageButton->setFont( fontAwesome ); - _projectBlankImageButton->setFixedSize( 37, 38 ); - _projectBlankImageButton->setText( FA_Times ); - QObject::connect( _projectBlankImageButton, &QPushButton::clicked, this, &AdvancedTab::projectBlankImageButton_clicked ); - - _projectBlankImageButtonLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); - _projectBlankImageButtonLabel->setText( "Project blank image" ); - - _projectFocusImageButton->setCheckable( true ); - _projectFocusImageButton->setChecked( false ); - _projectFocusImageButton->setFont( fontAwesome ); - _projectFocusImageButton->setFixedSize( 37, 38 ); - _projectFocusImageButton->setText( FA_Times ); - QObject::connect( _projectFocusImageButton, &QPushButton::clicked, this, &AdvancedTab::projectFocusImageButton_clicked ); - - _projectFocusImageButtonLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); - _projectFocusImageButtonLabel->setText( "Project focus image" ); - - _powerLevelLabel->setText( "Projector power level:" ); - - _powerLevelValue->setAlignment( Qt::AlignRight ); - _powerLevelValue->setFont( boldFont ); - _powerLevelValue->setText( "50%" ); - - _powerLevelValueLayout = WrapWidgetsInHBox( _powerLevelLabel, nullptr, _powerLevelValue ); - - _powerLevelSlider->setEnabled( false ); - _powerLevelSlider->setMinimum( 20 ); - _powerLevelSlider->setMaximum( 100 ); - _powerLevelSlider->setOrientation( Qt::Horizontal ); - _powerLevelSlider->setPageStep( 5 ); - _powerLevelSlider->setSingleStep( 1 ); - _powerLevelSlider->setTickInterval( 5 ); - _powerLevelSlider->setTickPosition( QSlider::TicksBothSides ); - _powerLevelSlider->setValue( 50 ); - QObject::connect( _powerLevelSlider, &QSlider::sliderReleased, this, &AdvancedTab::powerLevelSlider_sliderReleased ); - QObject::connect( _powerLevelSlider, &QSlider::valueChanged, this, &AdvancedTab::powerLevelSlider_valueChanged ); - - _powerLevelLabel->setEnabled( false ); - _powerLevelSlider->setEnabled( false ); - _powerLevelValue->setEnabled( false ); - _powerLevelValueLayout->setEnabled( false ); - - - _projectImageButtonsGroup->setContentsMargins( { } ); - _projectImageButtonsGroup->setLayout( WrapWidgetsInVBoxDM( - WrapWidgetsInHBox( _projectBlankImageButton, _projectBlankImageButtonLabel, nullptr, _projectFocusImageButton, _projectFocusImageButtonLabel, nullptr ), - _powerLevelValueLayout, - _powerLevelSlider - ) ); - - - _rightColumn->setContentsMargins( { } ); - _rightColumn->setMinimumSize( MaximalRightHandPaneSize ); - _rightColumn->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); - _rightColumn->setLayout( WrapWidgetsInVBoxDM( - _buildPlatformOffsetGroup, - _bedHeatingGroup, - _projectImageButtonsGroup, - nullptr - ) ); - - - setLayout( WrapWidgetsInHBox( _leftColumn, _rightColumn ) ); } AdvancedTab::~AdvancedTab( ) { /*empty*/ } +void AdvancedTab::chbox_addBodyPumpChanged(int state) +{ + _bodyPumpEveryNthLayer->setEnabled(state); + _bodyDistanceSlider->setEnabled(state); + _bodyUpTimeSlider->setEnabled(state); + _bodyUpPauseSlider->setEnabled(state); + _bodyDownTimeSlider->setEnabled(state); + _bodyDownPauseSlider->setEnabled(state); + _bodyUpVelocitySlider->setEnabled(state); +} + +void AdvancedTab::chbox_addBasePumpCheckChanged(int state) +{ + _distanceSlider->setEnabled(state); + _upTimeSlider->setEnabled(state); + _upPauseSlider->setEnabled(state); + _downTimeSlider->setEnabled(state); + _downPauseSlider->setEnabled(state); + _upVelocitySlider->setEnabled(state); +} + void AdvancedTab::_connectShepherd( ) { if ( _shepherd ) { QObject::connect( _shepherd, &Shepherd::printer_online, this, &AdvancedTab::printer_online ); @@ -390,3 +299,424 @@ void AdvancedTab::setPrinterAvailable( bool const value ) { _updateControlGroups( ); } + +void AdvancedTab::_setupLeftMenu(QFont fontAwesome) { + AdvancedTabSelectionModel* model = new AdvancedTabSelectionModel(5, 1, _forms, FORMS_COUNT); + + QStandardItem* item = new QStandardItem(QString("General")); + QStandardItem* generalItem = item; + model->setItem(0, 0, item); + + item = new QStandardItem(QString("Temperature")); + model->setItem(1, 0, item); + + item = new QStandardItem(QString("Base Pump")); + model->setItem(2, 0, item); + + item = new QStandardItem(QString("Base Layer")); + model->setItem(3, 0, item); + + item = new QStandardItem(QString("Body Layers")); + model->setItem(4, 0, item); + + item = new QStandardItem(QString("Body Pump")); + model->setItem(5, 0, item); + + QItemSelectionModel* selectionModel = new QItemSelectionModel(model); + QObject::connect( + _leftMenu, &QTreeView::pressed, model, &AdvancedTabSelectionModel::onclick + ); + + _leftMenu->setModel( model ); + _leftMenu->setSelectionModel( selectionModel ); + _leftMenu->setFont( fontAwesome ); + _leftMenu->setVisible( true ); + _leftMenu->setSelectionBehavior(QAbstractItemView::SelectRows); + _leftMenu->setCurrentIndex(model->indexFromItem(generalItem)); +} + +void AdvancedTab::_setupGeneralForm(QFont boldFont, QFont fontAwesome) { + _offsetLabel->setText( "Build platform offset:" ); + + _offsetValue->setAlignment( Qt::AlignRight ); + _offsetValue->setFont( boldFont ); + _offsetValue->setText( QString { "%1 µm" }.arg( g_settings.buildPlatformOffset ) ); + + _offsetSlider->setMinimum( 0 ); + _offsetSlider->setMaximum( 40 ); + _offsetSlider->setOrientation( Qt::Horizontal ); + _offsetSlider->setPageStep( 4 ); + _offsetSlider->setSingleStep( 1 ); + _offsetSlider->setTickInterval( 4 ); + _offsetSlider->setTickPosition( QSlider::TicksBothSides ); + _offsetSlider->setValue( g_settings.buildPlatformOffset / 25 ); + QObject::connect( _offsetSlider, &QSlider::sliderReleased, this, &AdvancedTab::offsetSlider_sliderReleased ); + QObject::connect( _offsetSlider, &QSlider::valueChanged, this, &AdvancedTab::offsetSlider_valueChanged ); + + + _buildPlatformOffsetGroup->setContentsMargins( { } ); + _buildPlatformOffsetGroup->setLayout( WrapWidgetsInVBoxDM( + WrapWidgetsInHBox( _offsetLabel, nullptr, _offsetValue ), + _offsetSlider + ) ); + + + _bedHeatingButton->setCheckable( true ); + _bedHeatingButton->setChecked( false ); + _bedHeatingButton->setFont( fontAwesome ); + _bedHeatingButton->setFixedSize( 37, 38 ); + _bedHeatingButton->setText( FA_Times ); + QObject::connect( _bedHeatingButton, &QPushButton::clicked, this, &AdvancedTab::printBedHeatingButton_clicked ); + + _bedHeatingButtonLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); + _bedHeatingButtonLabel->setText( "Print bed heating" ); + +#if defined ENABLE_TEMPERATURE_SETTING + _bedTemperatureLabel->setEnabled( false ); + _bedTemperatureLabel->setText( "Print bed temperature:" ); + + _bedTemperatureValue->setAlignment( Qt::AlignRight ); + _bedTemperatureValue->setEnabled( false ); + _bedTemperatureValue->setFont( boldFont ); + _bedTemperatureValue->setText( QString { "%1 °C" }.arg( DefaultPrintBedTemperature ) ); + + _bedTemperatureValueLayout = WrapWidgetsInHBox( _bedTemperatureLabel, nullptr, _bedTemperatureValue ); + _bedTemperatureValueLayout->setEnabled( false ); + + _bedTemperatureSlider->setEnabled( false ); + _bedTemperatureSlider->setMinimum( 30 ); + _bedTemperatureSlider->setMaximum( 50 ); + _bedTemperatureSlider->setOrientation( Qt::Horizontal ); + _bedTemperatureSlider->setPageStep( 1 ); + _bedTemperatureSlider->setSingleStep( 1 ); + _bedTemperatureSlider->setTickInterval( 5 ); + _bedTemperatureSlider->setTickPosition( QSlider::TicksBothSides ); + _bedTemperatureSlider->setValue( DefaultPrintBedTemperature ); + QObject::connect( _bedTemperatureSlider, &QSlider::sliderReleased, this, &AdvancedTab::printBedTemperatureSlider_sliderReleased ); + QObject::connect( _bedTemperatureSlider, &QSlider::valueChanged, this, &AdvancedTab::printBedTemperatureSlider_valueChanged ); +#endif + + auto bedTemperatureLayout = WrapWidgetsInVBoxDM( + WrapWidgetsInHBox( _bedHeatingButton, _bedHeatingButtonLabel, nullptr ) + ); +#if defined ENABLE_TEMPERATURE_SETTING + bedTemperatureLayout->addLayout( _bedTemperatureValueLayout ); + bedTemperatureLayout->addWidget( _bedTemperatureSlider ); +#endif + + _bedHeatingGroup->setContentsMargins( { } ); + _bedHeatingGroup->setLayout( bedTemperatureLayout ); + + + _projectBlankImageButton->setCheckable( true ); + _projectBlankImageButton->setChecked( false ); + _projectBlankImageButton->setFont( fontAwesome ); + _projectBlankImageButton->setFixedSize( 37, 38 ); + _projectBlankImageButton->setText( FA_Times ); + QObject::connect( _projectBlankImageButton, &QPushButton::clicked, this, &AdvancedTab::projectBlankImageButton_clicked ); + + _projectBlankImageButtonLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); + _projectBlankImageButtonLabel->setText( "Project blank image" ); + + _projectFocusImageButton->setCheckable( true ); + _projectFocusImageButton->setChecked( false ); + _projectFocusImageButton->setFont( fontAwesome ); + _projectFocusImageButton->setFixedSize( 37, 38 ); + _projectFocusImageButton->setText( FA_Times ); + QObject::connect( _projectFocusImageButton, &QPushButton::clicked, this, &AdvancedTab::projectFocusImageButton_clicked ); + + _projectFocusImageButtonLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); + _projectFocusImageButtonLabel->setText( "Project focus image" ); + + _powerLevelLabel->setText( "Projector power level:" ); + + _powerLevelValue->setAlignment( Qt::AlignRight ); + _powerLevelValue->setFont( boldFont ); + _powerLevelValue->setText( "50%" ); + + _powerLevelValueLayout = WrapWidgetsInHBox( _powerLevelLabel, nullptr, _powerLevelValue ); + + _powerLevelSlider->setEnabled( false ); + _powerLevelSlider->setMinimum( ProjectorMinPercent ); + _powerLevelSlider->setMaximum( ProjectorMaxPercent ); + _powerLevelSlider->setOrientation( Qt::Horizontal ); + _powerLevelSlider->setPageStep( 5 ); + _powerLevelSlider->setSingleStep( 1 ); + _powerLevelSlider->setTickInterval( 5 ); + _powerLevelSlider->setTickPosition( QSlider::TicksBothSides ); + _powerLevelSlider->setValue( 50 ); + QObject::connect( _powerLevelSlider, &QSlider::sliderReleased, this, &AdvancedTab::powerLevelSlider_sliderReleased ); + QObject::connect( _powerLevelSlider, &QSlider::valueChanged, this, &AdvancedTab::powerLevelSlider_valueChanged ); + + _powerLevelLabel->setEnabled( false ); + _powerLevelSlider->setEnabled( false ); + _powerLevelValue->setEnabled( false ); + _powerLevelValueLayout->setEnabled( false ); + + + _projectImageButtonsGroup->setContentsMargins( { } ); + _projectImageButtonsGroup->setLayout( WrapWidgetsInVBoxDM( + WrapWidgetsInHBox( _projectBlankImageButton, _projectBlankImageButtonLabel, nullptr, _projectFocusImageButton, _projectFocusImageButtonLabel, nullptr ), + _powerLevelValueLayout, + _powerLevelSlider + ) ); + + + _generalForm->setContentsMargins( { } ); + _generalForm->setMinimumSize( MaximalRightHandPaneSize ); + _generalForm->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + _generalForm->setLayout( WrapWidgetsInVBoxDM( + _buildPlatformOffsetGroup, + _bedHeatingGroup, + _projectImageButtonsGroup, + nullptr + ) ); +} + +void AdvancedTab::_setupTemperaturelForm(QFont boldFont) { + _currentTemperatureLabel->setText( "Current temperature:" ); + _targetTemperatureLabel ->setText( "Target temperature:" ); + _heatingElementLabel ->setText( "Heating element:" ); + _zPositionLabel ->setText( "Z position:" ); + + + _currentTemperature->setAlignment( Qt::AlignRight ); + _currentTemperature->setFont( boldFont ); + _currentTemperature->setText( EmDash ); + + _targetTemperature ->setAlignment( Qt::AlignRight ); + _targetTemperature ->setFont( boldFont ); + _targetTemperature ->setText( EmDash ); + + _heatingElement ->setAlignment( Qt::AlignRight ); + _heatingElement ->setFont( boldFont ); + _heatingElement ->setText( EmDash ); + + _zPosition ->setAlignment( Qt::AlignRight ); + _zPosition ->setFont( boldFont ); + _zPosition ->setText( EmDash ); + + _temperatureForm->setContentsMargins( { } ); + _temperatureForm->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding ); + _temperatureForm->setMinimumSize(MaximalRightHandPaneSize); + _temperatureForm->setLayout( WrapWidgetsInVBoxDM( + WrapWidgetsInHBox( _currentTemperatureLabel, nullptr, _currentTemperature ), + WrapWidgetsInHBox( _targetTemperatureLabel, nullptr, _targetTemperature ), + WrapWidgetsInHBox( _heatingElementLabel, nullptr, _heatingElement ), + WrapWidgetsInHBox( _zPositionLabel, nullptr, _zPosition ), + WrapWidgetsInHBox( _leftMenu ), + nullptr + ) ); +} + +void AdvancedTab::_setupBasePumpForm(QFont boldFont) +{ + _basePumpForm->setMinimumSize(QSize(MaximalRightHandPaneSize.width() + 35, MaximalRightHandPaneSize.height() + 25)); + _basePumpForm->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + + QWidget* container = new QWidget(); + container->setMinimumSize(MaximalRightHandPaneSize); + container->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + + QObject::connect( _addBasePumpCheckbox, &QCheckBox::stateChanged, this, &AdvancedTab::chbox_addBasePumpCheckChanged ); + + _addBasePumpCheckbox->setFont(boldFont); + _addBasePumpCheckbox->setChecked(true); + + QObject::connect( _addBasePumpCheckbox, &QCheckBox::stateChanged, this, &AdvancedTab::chbox_addBodyPumpChanged ); + + QGroupBox* addBasePumpGroup = new QGroupBox(); + addBasePumpGroup->setLayout(WrapWidgetsInVBox(_addBasePumpCheckbox, nullptr)); + addBasePumpGroup->setContentsMargins( { } ); + + + container->setLayout( + WrapWidgetsInVBox( + addBasePumpGroup, + _distanceSlider, + _upTimeSlider, + _upPauseSlider, + _downTimeSlider, + _downPauseSlider, + _upVelocitySlider, + nullptr + )); + + _basePumpForm->setWidget(container); +} + +void AdvancedTab::_setupBaseLayerForm() +{ + _baseLayerForm->setContentsMargins( { } ); + _baseLayerForm->setMinimumSize( MaximalRightHandPaneSize ); + _baseLayerForm->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + _baseLayerForm->setLayout( + WrapWidgetsInVBoxDM( + _numberOfBaseLayersSlider, + _baseThicknessSlider, + _baseExposureTimeSlider, + nullptr + ) + ); +} +void AdvancedTab::_setupBodyLayersForm() +{ + _bodyLayersForm->setContentsMargins( { } ); + _bodyLayersForm->setMinimumSize( MaximalRightHandPaneSize ); + _bodyLayersForm->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + _bodyLayersForm->setLayout( + WrapWidgetsInVBoxDM( + _bodyThicknessSlider, + _bodyExposureTimeSlider, + nullptr + ) + ); +} +void AdvancedTab::_setupBodyPumpForm(QFont boldFont) +{ + QWidget* container = new QWidget(); + + _bodyPumpForm->setMinimumSize(QSize(MaximalRightHandPaneSize.width() + 35, MaximalRightHandPaneSize.height() + 25)); + _bodyPumpForm->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + + container = new QWidget(); + container->setMinimumSize(MaximalRightHandPaneSize); + container->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + + _addBodyPumpCheckbox->setFont(boldFont); + _addBodyPumpCheckbox->setChecked(true); + + QObject::connect( _addBodyPumpCheckbox, &QCheckBox::stateChanged, this, &AdvancedTab::chbox_addBodyPumpChanged ); + + QGroupBox* addBodyPumpGroup = new QGroupBox(); + addBodyPumpGroup->setLayout(WrapWidgetsInVBox(_addBodyPumpCheckbox, nullptr)); + addBodyPumpGroup->setContentsMargins( { } ); + + container->setLayout( + WrapWidgetsInVBox( + addBodyPumpGroup, + _bodyPumpEveryNthLayer, + _bodyDistanceSlider, + _bodyUpTimeSlider, + _bodyUpPauseSlider, + _bodyDownTimeSlider, + _bodyDownPauseSlider, + _bodyUpVelocitySlider, + nullptr + ) + ); + + _bodyPumpForm->setWidget(container); +} + +void AdvancedTab::updatePrintProfile() { + + if(_lockUpdate) + return; + + PrintProfile* profile = (PrintProfile*)_printProfileManager->activeProfile(); + QString tempProfileName = "temp"; + bool setActive = false; + if(profile->profileName() != tempProfileName) + { + QVector* c = (QVector*)_printProfileManager->profiles(); + auto iter = std::find_if( c->begin( ), c->end( ), [&tempProfileName] ( PrintProfile* p ) { return tempProfileName == p->profileName( ); } ); + profile = ( iter != c->end( ) ) ? *iter : nullptr; + + if(!profile) + { + profile = new PrintProfile(); + profile->setProfileName(tempProfileName); + _printProfileManager->addProfile(profile); + } + + setActive=true; + } + + + profile->setBaseLayerCount(_numberOfBaseLayersSlider->getValue()); + + profile->setBaseLayersPumpingEnabled(_addBasePumpCheckbox->isChecked()); + if(_addBasePumpCheckbox->isChecked()) + { + PrintPumpingParameters baseParams; + + baseParams.setPumpUpDistance( ((double)_distanceSlider->getValue()) / 1000 ); + baseParams.setPumpUpTime(_upTimeSlider->getValue()); + baseParams.setPumpUpPause(_upPauseSlider->getValue()); + baseParams.setPumpDownPause(_downPauseSlider->getValue()); + baseParams.setNoPumpUpVelocity( ((double)_upVelocitySlider->getValue()) / (1000/60)); + baseParams.setPumpEveryNthLayer(0); + baseParams.setLayerThickness(_baseThicknessSlider->getValue()); + baseParams.setLayerExposureTime(_baseExposureTimeSlider->getValue()); + baseParams.setPowerLevel(_powerLevelSlider->value()); + + profile->setBaseLayersPumpingParameters(baseParams); + } + + profile->setBaseLayersPumpingEnabled(_addBodyPumpCheckbox->isChecked()); + if(_addBodyPumpCheckbox->isChecked()) + { + PrintPumpingParameters bodyParams; + + bodyParams.setPumpUpDistance( ((double)_bodyDistanceSlider->getValue()) / 1000 ); + bodyParams.setPumpUpTime(_bodyUpTimeSlider->getValue()); + bodyParams.setPumpUpPause(_bodyUpPauseSlider->getValue()); + bodyParams.setPumpDownPause(_bodyDownPauseSlider->getValue()); + bodyParams.setNoPumpUpVelocity( ((double)_bodyUpVelocitySlider->getValue()) / (1000/60)); + bodyParams.setPumpEveryNthLayer(_bodyPumpEveryNthLayer->getValue()); + bodyParams.setLayerThickness(_bodyThicknessSlider->getValue()); + bodyParams.setLayerExposureTime(_bodyExposureTimeSlider->getValue()); + bodyParams.setPowerLevel(_powerLevelSlider->value()); + + profile->setBodyLayersPumpingParameters(bodyParams); + } + + if(setActive) + { + _printProfileManager->setActiveProfile(tempProfileName); + } +} + +void AdvancedTab::loadPrintProfile(PrintProfile const* profilePtr) { + PrintProfile* profile = (PrintProfile*)profilePtr; + _lockUpdate=true; + + _numberOfBaseLayersSlider->setValue(profile->baseLayerCount()); + + if(profile->baseLayersPumpingEnabled()) + { + PrintPumpingParameters baseParams = profile->baseLayersPumpingParameters(); + + _distanceSlider->setValue(baseParams.pumpUpDistance() * 1000 ); + _upTimeSlider->setValue(baseParams.pumpUpTime()); + _upPauseSlider->setValue(baseParams.pumpUpPause()); + _downPauseSlider->setValue(baseParams.pumpDownPause()); + _upVelocitySlider->setValue(baseParams.noPumpUpVelocity() * (1000/60) ); + _baseThicknessSlider->setValue(baseParams.layerThickness()); + _baseExposureTimeSlider->setValue(baseParams.layerExposureTime()); + _powerLevelSlider->setValue(baseParams.powerLevel()); + } + + if(profile->bodyLayersPumpingEnabled()) + { + PrintPumpingParameters bodyParams = profile->baseLayersPumpingParameters(); + + _bodyDistanceSlider->setValue(bodyParams.pumpUpDistance() * 1000 ); + _bodyUpTimeSlider->setValue(bodyParams.pumpUpTime()); + _bodyUpPauseSlider->setValue(bodyParams.pumpUpPause()); + _bodyDownPauseSlider->setValue(bodyParams.pumpDownPause()); + _bodyUpVelocitySlider->setValue(bodyParams.noPumpUpVelocity() * (1000/60) ); + _bodyThicknessSlider->setValue(bodyParams.layerThickness()); + _bodyExposureTimeSlider->setValue(bodyParams.layerExposureTime()); + _powerLevelSlider->setValue(bodyParams.powerLevel()); + _bodyPumpEveryNthLayer->setValue(bodyParams.pumpEveryNthLayer()); + } + + _lockUpdate=false; +} + +void AdvancedTab::setPrintProfileManager(PrintProfileManager* profileManager) +{ + _printProfileManager = profileManager; +} diff --git a/src/advancedtab.h b/src/advancedtab.h index 70c92a84..daad5eb2 100644 --- a/src/advancedtab.h +++ b/src/advancedtab.h @@ -1,10 +1,12 @@ #ifndef __ADVANCEDTAB_H__ #define __ADVANCEDTAB_H__ -#undef ENABLE_TEMPERATURE_SETTING +#define ENABLE_TEMPERATURE_SETTING #include "tabbase.h" - +#include "paramslider.h" +#include "printprofile.h" +#include "printprofilemanager.h" class PngDisplayer; class AdvancedTab: public TabBase { @@ -16,24 +18,14 @@ class AdvancedTab: public TabBase { AdvancedTab( QWidget* parent = nullptr ); virtual ~AdvancedTab( ) override; - virtual TabIndex tabIndex( ) const override { return TabIndex::Advanced; } - + virtual TabIndex tabIndex( ) const override { return TabIndex::Advanced; } + void setPrintProfileManager(PrintProfileManager* profileManager); protected: virtual void _connectShepherd( ) override; private: - - QLabel* _currentTemperatureLabel { new QLabel }; - QLabel* _targetTemperatureLabel { new QLabel }; - QLabel* _heatingElementLabel { new QLabel }; - QLabel* _zPositionLabel { new QLabel }; - - QLabel* _currentTemperature { new QLabel }; - QLabel* _targetTemperature { new QLabel }; - QLabel* _heatingElement { new QLabel }; - QLabel* _zPosition { new QLabel }; - + PrintProfileManager* _printProfileManager; QLabel* _offsetLabel { new QLabel }; QLabel* _offsetValue { new QLabel }; QSlider* _offsetSlider { new QSlider }; @@ -43,15 +35,6 @@ class AdvancedTab: public TabBase { QPushButton* _bedHeatingButton { new QPushButton }; QLabel* _bedHeatingButtonLabel { new QLabel }; -#if defined ENABLE_TEMPERATURE_SETTING - QLabel* _bedTemperatureLabel { new QLabel }; - QLabel* _bedTemperatureValue { new QLabel }; - QHBoxLayout* _bedTemperatureValueLayout { }; - QSlider* _bedTemperatureSlider { new QSlider }; -#endif - - QGroupBox* _bedHeatingGroup { new QGroupBox }; - QPushButton* _projectBlankImageButton { new QPushButton }; QLabel* _projectBlankImageButtonLabel { new QLabel }; @@ -66,17 +49,93 @@ class AdvancedTab: public TabBase { QGroupBox* _projectImageButtonsGroup { new QGroupBox }; QWidget* _leftColumn { new QWidget }; - QGroupBox* _rightColumn { new QGroupBox }; + QWidget* _rightColumn { new QWidget }; + + //Left panel + QListView* _leftMenu { new QListView }; + + //General form + QGroupBox* _generalForm { new QGroupBox }; + + QGroupBox* _bedHeatingGroup { new QGroupBox }; + + //Temperature form + QWidget* _temperatureForm { new QWidget }; + + QLabel* _currentTemperatureLabel { new QLabel }; + QLabel* _targetTemperatureLabel { new QLabel }; + QLabel* _heatingElementLabel { new QLabel }; + QLabel* _zPositionLabel { new QLabel }; + + QLabel* _currentTemperature { new QLabel }; + QLabel* _targetTemperature { new QLabel }; + QLabel* _heatingElement { new QLabel }; + QLabel* _zPosition { new QLabel }; + +#if defined ENABLE_TEMPERATURE_SETTING + QLabel* _bedTemperatureLabel { new QLabel }; + QLabel* _bedTemperatureValue { new QLabel }; + QHBoxLayout* _bedTemperatureValueLayout { }; + QSlider* _bedTemperatureSlider { new QSlider }; +#endif + + //Base Pump Form + QScrollArea* _basePumpForm { new QScrollArea }; + QCheckBox* _addBasePumpCheckbox { new QCheckBox("add base pump") }; + + ParamSlider* _distanceSlider { new ParamSlider("Base Pump Distance", "µm", 1000, 8000, 250) }; + ParamSlider* _upTimeSlider { new ParamSlider("Base Pump Up Time", "ms", 1000, 8000, 1) }; + ParamSlider* _upPauseSlider { new ParamSlider("Base Pump Up Pause", "ms", 1000, 8000, 1) }; + ParamSlider* _downTimeSlider { new ParamSlider("Base Pump Down Time", "ms", 1000, 8000, 1) }; + ParamSlider* _downPauseSlider { new ParamSlider("Base Pump Down Pause", "ms", 1000, 8000, 1) }; + ParamSlider* _upVelocitySlider { new ParamSlider("Base Pump Up Velocity", "µm/ms", 1000, 8000, 1) }; + + + //Base Layer Form + QWidget* _baseLayerForm { new QWidget }; + + ParamSlider* _numberOfBaseLayersSlider { new ParamSlider("Number of Base Layer", "", 1, 20, 1) }; + ParamSlider* _baseThicknessSlider { new ParamSlider("Base Layer Thickness", "µm", 100, 8000, 1) }; + ParamSlider* _baseExposureTimeSlider { new ParamSlider("Base Pump Up Pause", "ms", 2000, 8000, 1) }; + + //Body Layers Form + QWidget* _bodyLayersForm { new QWidget }; + + ParamSlider* _bodyThicknessSlider { new ParamSlider("Body Layer Thickness", "µm", 20, 8000, 1) }; + ParamSlider* _bodyExposureTimeSlider { new ParamSlider("Base Pump Up Pause", "ms", 2000, 8000, 1) }; + + //Body Pump Form + QScrollArea* _bodyPumpForm { new QScrollArea }; + QCheckBox* _addBodyPumpCheckbox { new QCheckBox("add body pump") }; + + ParamSlider* _bodyPumpEveryNthLayer { new ParamSlider("Body Pump Every Nth Layer:", "", 5, 20, 1) }; + ParamSlider* _bodyDistanceSlider { new ParamSlider("Body Pump Distance", "µm", 1000, 8000, 1) }; + ParamSlider* _bodyUpTimeSlider { new ParamSlider("Body Pump Up Time", "ms", 1000, 8000, 1) }; + ParamSlider* _bodyUpPauseSlider { new ParamSlider("Body Pump Up Pause", "ms", 1000, 8000, 1) }; + ParamSlider* _bodyDownTimeSlider { new ParamSlider("Body Pump Down Time", "ms", 1000, 8000, 1) }; + ParamSlider* _bodyDownPauseSlider { new ParamSlider("Body Pump Down Pause", "ms", 1000, 8000, 1) }; + ParamSlider* _bodyUpVelocitySlider { new ParamSlider("Body Pump Up Velocity", "µm/ms", 1000, 8000, 1) }; + + + static const int FORMS_COUNT { 6 }; + QWidget* _forms[FORMS_COUNT]; PngDisplayer* _pngDisplayer { }; bool _isPrinterOnline { false }; bool _isPrinterAvailable { true }; bool _isProjectorOn { false }; + bool _lockUpdate { false }; void _updateControlGroups( ); void _projectImage( char const* fileName ); - + void _setupLeftMenu(QFont fontAwesome); + void _setupGeneralForm(QFont fontBold, QFont fontAwesome); + void _setupTemperaturelForm(QFont fontBold); + void _setupBasePumpForm(QFont fontBold); + void _setupBaseLayerForm(); + void _setupBodyLayersForm(); + void _setupBodyPumpForm(QFont fontBold); signals: ; @@ -92,7 +151,8 @@ public slots: void setPrinterAvailable( bool const value ); void projectorPowerLevel_changed( int const percentage ); - + void loadPrintProfile (PrintProfile const* profile); + void updatePrintProfile(); protected slots: ; @@ -122,6 +182,10 @@ private slots: void shepherd_sendComplete( bool const success ); + void chbox_addBodyPumpChanged(int); + + void chbox_addBasePumpCheckChanged(int state); + }; #endif // __ADVANCEDTAB_H__ diff --git a/src/advancedtabselectionmodel.cpp b/src/advancedtabselectionmodel.cpp new file mode 100644 index 00000000..0059d0da --- /dev/null +++ b/src/advancedtabselectionmodel.cpp @@ -0,0 +1,20 @@ +#include "advancedtabselectionmodel.h" + +void AdvancedTabSelectionModel::onclick(const QModelIndex &index) +{ + int row = index.row(); + + for(int i=0; i<_panelsCount; i++) + { + this->_relatedPanel[i]->setVisible(i==row); + } +} + +AdvancedTabSelectionModel::AdvancedTabSelectionModel(int r,int c, QWidget** relatedPanels, int panelsCount): QStandardItemModel::QStandardItemModel(r,c) +{ + this->_relatedPanel = relatedPanels; + this->_panelsCount = panelsCount; +} + +AdvancedTabSelectionModel::~AdvancedTabSelectionModel() +{ } diff --git a/src/advancedtabselectionmodel.h b/src/advancedtabselectionmodel.h new file mode 100644 index 00000000..e2e0b27e --- /dev/null +++ b/src/advancedtabselectionmodel.h @@ -0,0 +1,21 @@ +#ifndef __ADVANCEDTABSELECTIONMODEL_H__ +#define __ADVANCEDTABSELECTIONMODEL_H__ + +#include "tabbase.h" + +class AdvancedTabSelectionModel: public QStandardItemModel +{ + Q_OBJECT + private: + QWidget** _relatedPanel; + int _panelsCount; + + public: + AdvancedTabSelectionModel(int r,int c, QWidget** relatedPanel, int panelsCount); + ~AdvancedTabSelectionModel(); + + public slots: + void onclick(const QModelIndex &index); +}; + +#endif // __ADVANCEDTABSELECTIONMODEL_H__ diff --git a/src/app.cpp b/src/app.cpp index 4f822f2a..0da1ba67 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -109,6 +109,8 @@ void App::_parseCommandLine( ) { if ( MoveMainWindow ) { g_settings.mainWindowPosition.setY( 0 ); g_settings.projectorWindowPosition.setY( MainWindowSize.height( ) ); + } else { + g_settings.mainWindowPosition.setY( ProjectorWindowSize.height( ) ); } } diff --git a/src/app.h b/src/app.h index 09664627..5261a92a 100644 --- a/src/app.h +++ b/src/app.h @@ -12,9 +12,9 @@ class AppSettings { public: - QPoint mainWindowPosition { 0, 800 }; - QPoint projectorWindowPosition { 0, 0 }; - QPoint projectorOffset { 0, 0 }; + QPoint mainWindowPosition { 0, 0 }; + QPoint projectorWindowPosition { 0, 0 }; + QPoint projectorOffset { 0, 0 }; Theme theme { }; bool frameless { false }; diff --git a/src/constants.cpp b/src/constants.cpp index 5cb756af..fee26d53 100644 --- a/src/constants.cpp +++ b/src/constants.cpp @@ -1,19 +1,19 @@ #include "pch.h" #include "constants.h" -QRegularExpression const EndsWithWhitespaceRegex { "\\s+$" }; -QRegularExpression const NewLineRegex { "\\r?\\n" }; +QRegularExpression const EndsWithWhitespaceRegex { "\\s+$" }; +QRegularExpression const NewLineRegex { "\\r?\\n" }; -QSize const SmallMainWindowSize { 800, 480 }; -QSize const SmallMainButtonSize { 218, 74 }; -QSize const SmallMaximalRightHandPaneSize { 564, 424 }; +QSize const SmallMainWindowSize { 800, 480 }; +QSize const SmallMainButtonSize { 218, 74 }; +QSize const SmallMaximalRightHandPaneSize { 564, 424 }; -QSize MainWindowSize { 1024, 600 }; -QSize MainButtonSize { 279, 93 }; -QSize MaximalRightHandPaneSize { 722, 530 }; +QSize MainWindowSize { 1024, 600 }; +QSize MainButtonSize { 279, 93 }; +QSize MaximalRightHandPaneSize { 722, 530 }; -QSize const ButtonPadding { 20, 4 }; -QSize const ProjectorWindowSize { 1280, 800 }; +QSize const ButtonPadding { 20, 4 }; +QSize const ProjectorWindowSize { 1920, 1080 }; QString const AptSourcesFilePath { "/etc/apt/sources.list.d/volumetric-lightfield.list" }; QString const JobWorkingDirectoryPath { "/var/cache/lightfield/print-jobs" }; @@ -24,6 +24,8 @@ QString const ShepherdPath { "/usr/share/lig QString const SlicedSvgFileName { "sliced.svg" }; QString const StlModelLibraryPath { "/var/lib/lightfield/model-library" }; QString const UpdatesRootPath { "/var/lib/lightfield/software-updates" }; +QString const PrintProfilesPath { "/var/lib/lightfield/print-profiles.json" }; + QChar const LineFeed { L'\u000A' }; QChar const CarriageReturn { L'\u000D' }; diff --git a/src/constants.h b/src/constants.h index f2ec1d68..04839ab7 100644 --- a/src/constants.h +++ b/src/constants.h @@ -24,6 +24,7 @@ QString extern const ShepherdPath; QString extern const SlicedSvgFileName; QString extern const StlModelLibraryPath; QString extern const UpdatesRootPath; +QString extern const PrintProfilesPath; QChar extern const LineFeed; QChar extern const CarriageReturn; @@ -41,22 +42,38 @@ QChar extern const FA_Backward; QChar extern const FA_Forward; QChar extern const FA_FastForward; -int const DebugLogPathCount = 6; +int const DebugLogPathCount = 6; char extern const* DebugLogPaths[DebugLogPathCount]; -double const PrinterMaximumX = 64.00; // mm -double const PrinterMaximumY = 40.00; // mm -double const PrinterMaximumZ = 50.00; // mm -double const PrinterRaiseToMaximumZ = 60.00; // mm -double const PrinterHighSpeedThresholdZ = 10.00; // mm +double constexpr const PrinterMaximumX = 64.00; // mm +double constexpr const PrinterMaximumY = 40.00; // mm +double constexpr const PrinterMaximumZ = 50.00; // mm +double constexpr const PrinterRaiseToMaximumZ = 60.00; // mm +double constexpr const PrinterHighSpeedThresholdZ = 10.00; // mm -double const PrinterDefaultHighSpeed = 600.00; // mm/min -double const PrinterDefaultLowSpeed = 50.00; // mm/min +double constexpr const PrinterDefaultHighSpeed = 200.00; // mm/min +double constexpr const PrinterDefaultLowSpeed = 50.00; // mm/min -double const AspectRatio5to3 = 5.0 / 3.0; -double const AspectRatio16to10 = 16.0 / 10.0; +double constexpr const AspectRatio5to3 = 5.0 / 3.0; +double constexpr const AspectRatio16to10 = 16.0 / 10.0; -double const LargeFontSize = 22.0; // pt -double const NormalFontSize = 12.0; // pt +double constexpr const LargeFontSize = 22.0; // pt +double constexpr const NormalFontSize = 12.0; // pt + +# if defined DLP4710 + +double constexpr const ProjectorMaxPowerLevel = 1023.0; + +int constexpr const ProjectorMinPercent = 5; +int constexpr const ProjectorMaxPercent = 80; + +# else + +double constexpr const ProjectorMaxPowerLevel = 255.0; + +int constexpr const ProjectorMinPercent = 20; +int constexpr const ProjectorMaxPercent = 80; + +# endif #endif // __CONSTANTS_H__ diff --git a/src/inputdialog.h b/src/inputdialog.h new file mode 100644 index 00000000..120b80b2 --- /dev/null +++ b/src/inputdialog.h @@ -0,0 +1,119 @@ +#ifndef __INPUTDIALOG_H__ +#define __INPUTDIALOG_H__ + +#include "keyboard.h" +#include "window.h" + +#include +#include + + +class InputDialog: public QDialog { + Q_OBJECT + private: + Keyboard* _keyboard { new Keyboard(this) }; + QLabel* _message { new QLabel }; + QLineEdit* _input { new QLineEdit }; + QPushButton* _okButton { new QPushButton("Ok") }; + QPushButton* _cancelButton { new QPushButton("Cancel")}; + QWidget* _widget { new QWidget }; + public: + InputDialog() { } + InputDialog(QString text) { + auto origFont = font( ); + auto fontAwesome = ModifyFont( origFont, "FontAwesome", LargeFontSize ); + + Window* win = App::mainWindow(); + QRect r = win->geometry(); + + move(r.x()+100, r.y()+100); + resize(824, 400); + + _message ->setText(text); + _keyboard->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + _message->setFont(fontAwesome); + _okButton->setFont(fontAwesome); + _cancelButton->setFont(fontAwesome); + _input->setFont(fontAwesome); + + _okButton->setMinimumSize(QSize(245, 70)); + _cancelButton->setMinimumSize(QSize(245, 70)); + setContentsMargins( { } ); + setMinimumSize(QSize(580, 355)); + + setLayout( + WrapWidgetsInVBox( + _message, + _input, + _keyboard, + WrapWidgetsInHBox(_okButton, _cancelButton) + ) + ); + + setModal(true); + + // Window backgorund + // TODO: make it transparent + _widget->setStyleSheet("background-color: rgba(255, 255, 255, 10%);"); + _widget->setFixedSize(QSize(1024,600)); + _widget->setWindowOpacity(0.5); + _widget->show(); + + QWidget::connect(_keyboard, &Keyboard::keyPressed, this, &InputDialog::keyPressed); + QWidget::connect(_keyboard, &Keyboard::backspacePressed, this, &InputDialog::backspacePressed); + QWidget::connect(_okButton, &QPushButton::clicked, this, &InputDialog::oklCLicked_clicked); + QWidget::connect(_cancelButton, &QPushButton::clicked, this, &InputDialog::cancelCLicked_clicked); + } + + ~InputDialog() { + delete _keyboard; + delete _message; + delete _input; + delete _okButton; + delete _cancelButton; + delete _widget; + } + + QString getValue() { + return _input->text(); + } + + public slots: + void keyPressed( QString t) { + int cursorPos = _input->cursorPosition(); + _input->setText(_input->text().insert(cursorPos, t)); + _input->setCursorPosition(cursorPos+1); + } + + void backspacePressed( ) { + int cursorPos = _input->cursorPosition(); + int length = _input->text().length(); + QString text = _input->text(); + if(cursorPos == 0) + return; + + _input->setText(text.left(cursorPos-1) + (cursorPos < length ? text.right(cursorPos) : "")); + _input->setCursorPosition(cursorPos-1); + } + + void cancelCLicked_clicked(bool) { + _widget->hide(); + this->setResult(QDialog::Rejected); + this->reject(); + this->close(); + } + + void oklCLicked_clicked(bool) { + _widget->hide(); + this->setResult(QDialog::Accepted); + this->accept(); + this->close(); + } + + + + signals: + void okclicked(); +}; + +#endif // __INPUTDIALOG_H__ diff --git a/src/key.cpp b/src/key.cpp new file mode 100644 index 00000000..44cc9340 --- /dev/null +++ b/src/key.cpp @@ -0,0 +1,77 @@ +#include +#include +#include "key.h" + + +key::key(QString t,QObject *parent) : QObject(parent) +{ + text = t; + X =10; + Y =10; + W =82;//t.length()*4 + 78; + H =62; + pressed = false; +} + +QRect key::getRect() +{ + return QRect(X,Y,W,H); +} + +void key::setX(int x ) +{ + // qDebug() << "setX " << x << " " << text; + X = x; +} + + +void key::setY(int y ) +{ + // qDebug() << "setY " << y; + Y = y; +} + + +void key::setIconFile(QString i ) +{ + iconFilename = i; + W = 25; +} + +void key::setPressed( bool b) +{ +// qDebug() << "setPessed " << b; + pressed = b; +} + +void key::draw(QPainter *p,QStyle *style) +{ + QStyleOptionButton opt; + QFont font; + auto fontAwesome = ModifyFont( font, "FontAwesome", 20.0 ); + + opt.palette = QPalette(QColor(0,51,102,127)); + p->setFont(fontAwesome); + + /* + if ( pressed ) + { + opt.state = QStyle::State_Active; + } else { + opt.state = QStyle::State_Enabled; + } + */ + opt.rect = QRect(X, Y, W, H); + + if ( iconFilename !="" ) + { + opt.icon = QIcon(iconFilename); + opt.iconSize = QSize(16,16); + } + else + { + if (text =="&") opt.text = "&&"; + else opt.text = text; + } + style->drawControl(QStyle::CE_PushButton, &opt, p); +} diff --git a/src/key.h b/src/key.h new file mode 100644 index 00000000..86a4de7e --- /dev/null +++ b/src/key.h @@ -0,0 +1,48 @@ +#ifndef KEY_H +#define KEY_H + +#include +#include +#include +#include +#include +#include + + +#define KEYS_TYPE 4 + +#define LOWERCASE 0 +#define NUMBER 1 +#define UPPERCASE 2 +#define PUNCTUATION 3 + + +class key : public QObject +{ + Q_OBJECT +public: + explicit key(QString t, QObject *parent = 0); + + void setX(int ); + void setY(int ); + void setIconFile(QString ); + void setPressed( bool b); + + void draw(QPainter *painter,QStyle *s); + QRect getRect(); + +signals: + +public slots: + +public : + int X; + int Y; + int W; + int H; + QString text; + QString iconFilename; + bool pressed; +}; + +#endif // KEY_H diff --git a/src/keyboard.cpp b/src/keyboard.cpp new file mode 100644 index 00000000..2041eac7 --- /dev/null +++ b/src/keyboard.cpp @@ -0,0 +1,244 @@ +#include +#include +#include +#include "key.h" +#include "keyboard.h" + + +// Declaration off the differente keys... +const char *en_lower_keymap[] = { + "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", + "a", "s", "d", "f", "g", "h", "j", "k", "l",";", + "caps", "z", "x", "c", "v", "b", "n", "m",",", "back\nspace", + "123", ".", "space", "@" +}; + +const char *en_upper_keymap[] = { + "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", + "A", "S", "D", "F", "G", "H", "J", "K", "L",";", + "caps", "Z", "X", "C", "V", "B", "N", "M",",", "back\nspace", + "123", ".", "space", "@" +}; + +const char *en_number_keymap[] = { + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", + "-", "/", ":", ";", "(", ")", "€", "&", "@", "\"", + "#+=", ".", ",", "?", "!", "'", "+","\\","%","back\nspace", + "ABC", ",", "space", "." +}; + +const char *en_punctuation_keymap[] = { + "[", "]", "{", "}", "#", "%", "^", "*", "+", "=", + "_", "\\", "|", "~", "<", ">", "=","$", "@", "\"", + "123", ".", ",", "?", "!", "'","/",":",";", "back\nspace", + "ABC", ",", "space", "." +}; + +// In witch row are the key... (there's 4 rows ) +const int row_keymap[] = { + 0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3 +}; + + +const int nbkey = sizeof(en_lower_keymap)/sizeof(char *); + +Keyboard::Keyboard(QWidget *p) : QWidget(p) +{ + currentKey = 0x0; + currentindexkeyboard = LOWERCASE; + uppercase = false; + + initTooltip(); + + keys = QVector >(KEYS_TYPE); + for (int n=0;n < KEYS_TYPE ; n++) + { + keys[n] = QVector< key * >(nbkey); + } + + initKeys(LOWERCASE, en_lower_keymap); + initKeys(NUMBER, en_number_keymap); + initKeys(UPPERCASE, en_upper_keymap); + initKeys(PUNCTUATION, en_punctuation_keymap); +} + +void Keyboard::initKeys( int indexArraykeys, const char *keymap[]) +{ + int xCoor = 0; + int yCoor = 0; + + for(int n=0; nW=574; + + // Calculat e new ccooridinate of button + if (row_keymap[n-1]!=row_keymap[n]) + { + xCoor = 2; + } + else + { + xCoor = keys[indexArraykeys][n-1]->X + keys[indexArraykeys][n-1]->W; + } + yCoor = row_keymap[n] * DEFAULT_YSIZE_BUTTON; + } + else + { + xCoor = 2; + yCoor = 0; + } + + keys[indexArraykeys][n]->setX(xCoor); + keys[indexArraykeys][n]->setY(yCoor); + + //qDebug() <<"N: " << n << "\t\t" <text << "\t\t W= " << keys[indexArraykeys][n]->W; + } +} + +void Keyboard::initTooltip() +{ + tooltip = new QLabel(""); + tooltip->setWindowFlags( Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint ); + + QFont serifFont("Times", 18, QFont::Bold); + tooltip->setFont(serifFont); + tooltip->setAlignment(Qt::AlignCenter); + + // Bug fix of first pres button + tooltip->show(); + tooltip->hide(); +} + +void Keyboard::mousePressEvent(QMouseEvent * e) +{ + //qDebug() << "Mouse press event"; + QWidget::mousePressEvent(e); + + QPoint pos = e->pos(); + setKeyPressed( findKey(pos), pos ); +} + +void Keyboard::mouseMoveEvent(QMouseEvent * e) +{ + //qDebug() << "Mouse move event"; + QPoint pos = e->pos(); + + if (currentKey != 0x0 && !currentKey->getRect().contains(pos)) + { + tooltip->hide(); + currentKey->setPressed(false); + this->repaint(); + } + setKeyPressed( findKey(pos), pos ); +} + +void Keyboard::mouseReleaseEvent(QMouseEvent *e) +{ + //qDebug() << "Mouse release event"; + QPoint pos = e->pos(); + tooltip->hide(); + + key *k= findKey( pos ); + if (k != 0x0 ) + { + if ( k->text == "ABC") + { + currentindexkeyboard = LOWERCASE; + repaint(); + return; + } + if (k->text== "#+=" ) + { + currentindexkeyboard = PUNCTUATION; + repaint(); + return; + } + + if (k->text=="caps") + { + if ( uppercase ==false) + { + currentindexkeyboard = UPPERCASE; + uppercase = true; + } + else + { + currentindexkeyboard = LOWERCASE; + uppercase = false; + } + repaint(); + return; + } + + if (k->text=="123") + { + currentindexkeyboard = NUMBER; + repaint(); + } + else + { + if ( k->text =="back\nspace" ) + { + emit backspacePressed(); + return; + } + else if (k->text=="enter") + { + emit returnPressed(); + return; + } + else if ( k->text == "space") + { + emit keyPressed(" "); + } + else + { + emit keyPressed(k->text); + } + } + } +} + +key *Keyboard::findKey(QPoint p) +{ + foreach (key *k, keys[currentindexkeyboard]) + { + if (k->getRect().contains(p)) + { + return k; + } + } + return 0x0; +} + +void Keyboard::setKeyPressed( key *k, QPoint /*pos*/) +{ + currentKey = k; + if (k == 0x0) return; + + k->setPressed(true); + this->repaint(); + + QPoint p = QWidget::mapToGlobal(this->pos() +QPoint( k->X, k->Y)); + tooltip->setGeometry(p.x(),p.y()-50,50, 50); + tooltip->setText(k->text); + tooltip->show(); // this line makes bug with first relase event +} + +void Keyboard::paintEvent(QPaintEvent*) +{ + QPainter painter(this); + foreach (key *k, keys[currentindexkeyboard]) + { + k->draw(&painter,style()); + } +} diff --git a/src/keyboard.h b/src/keyboard.h new file mode 100644 index 00000000..4eb0d062 --- /dev/null +++ b/src/keyboard.h @@ -0,0 +1,43 @@ +#ifndef KEYBOARD_H +#define KEYBOARD_H + +#include +#include +#include +#include + +#define DEFAULT_YSIZE_BUTTON 62 + +class key; + +class Keyboard : public QWidget +{ + Q_OBJECT + +public: + Keyboard(QWidget *p); + + signals: + void keyPressed( QString t); + void backspacePressed( ); + void returnPressed( ); + +private : + void paintEvent(QPaintEvent*); + void mousePressEvent(QMouseEvent * E); + void mouseMoveEvent(QMouseEvent * e); + void mouseReleaseEvent(QMouseEvent *); + + void initTooltip(); + void initKeys( int indexArraykeys,const char *keymap[]); + key *findKey(QPoint p); + void setKeyPressed( key *k,QPoint ); + + QVector > keys; + QLabel *tooltip; + key *currentKey; + int currentindexkeyboard; + bool uppercase ; +}; + +#endif // KEYBOARD_H diff --git a/src/paramslider.cpp b/src/paramslider.cpp new file mode 100644 index 00000000..97495539 --- /dev/null +++ b/src/paramslider.cpp @@ -0,0 +1,58 @@ +#include "paramslider.h" + + +void ParamSlider::init(QString name, QString unit, int startValue, int maxValue, int step) +{ + QString valueLabel = QString::number(startValue) + QString(" ") + unit; + auto origFont = font( ); + auto boldFont = ModifyFont( origFont, QFont::Bold ); + + this->_nameLabel->setText(name); + this->_valueLabel->setText(valueLabel); + this->_valueLabel->setFont(boldFont); + this->_slider->setValue(startValue); + this->_slider->setMaximum(maxValue); + this->_slider->setSingleStep(step); + this->_slider->setOrientation(Qt::Orientation::Horizontal); + + QWidget::connect(this->_slider, &QSlider::valueChanged, this, &ParamSlider::onvaluechanged); + + this->setLayout( + WrapWidgetsInVBoxDM( + WrapWidgetsInHBox(_nameLabel, nullptr, _valueLabel), + _slider + ) + ); + + _unit = unit; +} + +int ParamSlider::getValue() +{ + return _slider->value(); +} + +void ParamSlider::setValue(int value) +{ + _slider->setValue(value); +} + +void ParamSlider::onvaluechanged(int) +{ + this->_valueLabel->setText(QString::number(_slider->value()) + " " + QString(_unit)); + emit valuechanged(); +} + +ParamSlider::ParamSlider(QString name, QString unit, int startValue, int maxValue, int step) +{ + this->init(name, unit, startValue, maxValue, step); +} + +ParamSlider::ParamSlider(QString name, int maxValue) +{ + this->init(name, "", 0, maxValue, 1); +} + +ParamSlider::~ParamSlider() +{ } + diff --git a/src/paramslider.h b/src/paramslider.h new file mode 100644 index 00000000..d6189b4f --- /dev/null +++ b/src/paramslider.h @@ -0,0 +1,29 @@ +#ifndef __PARAMSLIDER_H__ +#define __PARAMSLIDER_H__ + + +class ParamSlider: public QGroupBox { + Q_OBJECT + private: + QSlider* _slider { new QSlider }; + QLabel* _nameLabel { new QLabel }; + QLabel* _valueLabel { new QLabel }; + QString _unit; + + void init(QString name, QString unit, int startValue, int maxValue, int step); + + public: + ParamSlider(QString name, QString unit, int startValue, int maxValue, int step); + ParamSlider(QString name, int maxValue); + ~ParamSlider(); + + int getValue(); + void setValue(int value); + + signals: + void valuechanged(); + public slots: + void onvaluechanged(int value); +}; + +#endif // __PARAMSLIDER_H__ diff --git a/src/printjob.h b/src/printjob.h index 18a58acf..14295389 100644 --- a/src/printjob.h +++ b/src/printjob.h @@ -2,6 +2,7 @@ #define __PRINTJOB_H__ #include "coordinate.h" +#include "printprofile.h" class PrintJob { @@ -28,28 +29,30 @@ class PrintJob { exposureTimeScaleFactor = value->exposureTimeScaleFactor; powerLevel = value->powerLevel; printSpeed = value->printSpeed; + printProfile = value->printProfile; } ~PrintJob( ) { /*empty*/ } - size_t vertexCount { }; - Coordinate x { }; - Coordinate y { }; - Coordinate z { }; - double estimatedVolume { }; // unit: µL - - QString modelFileName { }; - QString modelHash { }; - QString jobWorkingDirectory { }; - - int layerCount { }; - int layerThickness { 100 }; // unit: µm - double exposureTime { 1.0 }; // unit: s - double exposureTimeScaleFactor { 1.0 }; // for first two layers - int powerLevel { 128 }; // range: 0..255 - double printSpeed { PrinterDefaultLowSpeed }; // unit: mm/min; range: 50-200 + size_t vertexCount { }; + Coordinate x { }; + Coordinate y { }; + Coordinate z { }; + double estimatedVolume { }; // unit: µL + + QString modelFileName { }; + QString modelHash { }; + QString jobWorkingDirectory { }; + + int layerCount { }; + int layerThickness { 100 }; // unit: µm + double exposureTime { 1.0 }; // unit: s + double exposureTimeScaleFactor { 1.0 }; // for first two layers + int powerLevel { static_cast( ProjectorMaxPowerLevel / 2.0 + 0.5 ) }; // range: 0..ProjectorMaxPowerLevel + double printSpeed { PrinterDefaultLowSpeed }; // unit: mm/min; range: 50-200 + PrintProfile* printProfile { }; }; diff --git a/src/printprofile.cpp b/src/printprofile.cpp new file mode 100644 index 00000000..82547d4e --- /dev/null +++ b/src/printprofile.cpp @@ -0,0 +1,3 @@ +#include "pch.h" + +#include "printprofile.h" diff --git a/src/printprofile.h b/src/printprofile.h new file mode 100644 index 00000000..17f43e95 --- /dev/null +++ b/src/printprofile.h @@ -0,0 +1,118 @@ +#ifndef __PRINTPROFILE_H__ +#define __PRINTPROFILE_H__ + +#include "printpumpingparameters.h" + +class PrintProfile: public QObject { + + Q_OBJECT; + +public: + + PrintProfile( QObject* parent = nullptr ): QObject( parent ) { + + } + + virtual ~PrintProfile( ) override { + /*empty*/ + } + + PrintProfile* copy() { + PrintProfile* printProfile = new PrintProfile(); + + printProfile->_name = this->_name; + printProfile->_baseLayerCount = this->_baseLayerCount; + printProfile->_baseLayersPumpingEnabled = this->_baseLayersPumpingEnabled; + printProfile->_bodyLayersPumpingEnabled = this->_bodyLayersPumpingEnabled; + + printProfile->_baseLayersPumpingParameters = this->_baseLayersPumpingParameters; + printProfile->_bodyLayersPumpingParameters = this->_bodyLayersPumpingParameters; + + return printProfile; + } + + // + // Accessors + // + + QString const& profileName( ) const { + return _name; + } + + int baseLayerCount( ) const { + return _baseLayerCount; + } + + PrintPumpingParameters& baseLayersPumpingParameters( ) { + return _baseLayersPumpingParameters; + } + + PrintPumpingParameters& bodyLayersPumpingParameters( ) { + return _bodyLayersPumpingParameters; + } + + bool baseLayersPumpingEnabled() { + return _baseLayersPumpingEnabled; + } + + bool bodyLayersPumpingEnabled() { + return _bodyLayersPumpingEnabled; + } + + // + // Mutators + // + + void setProfileName( QString const& newName ) { + emit profileNameChanged( newName ); + _name = newName; + } + + void setBaseLayerCount( int const newCount ) { + _baseLayerCount = newCount; + } + + void setBaseLayersPumpingParameters( PrintPumpingParameters const& newParameters ) { + _baseLayersPumpingParameters = newParameters; + } + + void setBodyLayersPumpingParameters( PrintPumpingParameters const& newParameters ) { + _bodyLayersPumpingParameters = newParameters; + } + + void setBaseLayersPumpingEnabled(bool value) { + _baseLayersPumpingEnabled = value; + } + + void setBodyLayersPumpingEnabled(bool value) { + _bodyLayersPumpingEnabled = value; + } +protected: + +private: + + QString _name; + int _baseLayerCount; + bool _baseLayersPumpingEnabled; + PrintPumpingParameters _baseLayersPumpingParameters; + bool _bodyLayersPumpingEnabled; + PrintPumpingParameters _bodyLayersPumpingParameters; + bool _defaultProfile; + +signals: + ; + + void profileNameChanged( QString const& newName ); + +public slots: + ; + +protected slots: + ; + +private slots: + ; + +}; + +#endif // !__PRINTPROFILE_H__ diff --git a/src/printprofilemanager.cpp b/src/printprofilemanager.cpp new file mode 100644 index 00000000..2e13f2eb --- /dev/null +++ b/src/printprofilemanager.cpp @@ -0,0 +1,49 @@ +#include "pch.h" + +#include "printprofilemanager.h" +PrintProfile* PrintProfileManager::_findProfile( QString const& profileName ) { + auto iter = std::find_if( _profiles->begin( ), _profiles->end( ), [&profileName] ( PrintProfile* p ) { return profileName == p->profileName( ); } ); + return ( iter != _profiles->end( ) ) ? *iter : nullptr; +} + +bool PrintProfileManager::addProfile( PrintProfile* newProfile ) { + auto profile = _findProfile( newProfile->profileName( ) ); + if ( !profile ) { + _profiles->append( newProfile ); + return true; + } else { + debug( "PrintProfileManager::addProfile: can't add profile %p: already have a profile named '%s'\n", newProfile, newProfile->profileName( ).toUtf8( ).data( ) ); + return false; + } +} + +bool PrintProfileManager::removeProfile( QString const& name ) { + auto profile = _findProfile( name ); + if ( profile ) { + _profiles->removeOne( profile ); + return true; + } else { + debug( "PrintProfileManager::removeProfile: can't remove profile named '%s': not in collection\n", name.toUtf8( ).data( ) ); + return false; + } +} + +bool PrintProfileManager::setActiveProfile( QString const& profileName ) { + auto newProfile = _findProfile( profileName ); + if ( newProfile ) { + emit activeProfileChanged( newProfile ); + _activeProfile = newProfile; + return true; + } else { + debug( "PrintProfileManager::setActiveProfile: couldn't find profile named '%s' in collection\n", profileName.toUtf8( ).data( ) ); + return false; + } +} + +bool PrintProfileManager::importProfiles( QString const& /*fileName*/ ) { + return false; +} + +bool PrintProfileManager::exportProfiles( QString const& /*fileName*/ ) { + return false; +} diff --git a/src/printprofilemanager.h b/src/printprofilemanager.h new file mode 100644 index 00000000..1e46792f --- /dev/null +++ b/src/printprofilemanager.h @@ -0,0 +1,63 @@ +#ifndef __PRINTPROFILEMANAGER_H__ +#define __PRINTPROFILEMANAGER_H__ + +#include "printprofile.h" + +using PrintProfileCollection = QVector; + +class PrintProfileManager: public QObject { + + Q_OBJECT; + +public: + + PrintProfileManager( QObject* parent = nullptr ): QObject( parent ) { + /*empty*/ + } + + virtual ~PrintProfileManager( ) override { + /*empty*/ + } + + PrintProfileCollection const* profiles( ) { + return _profiles; + } + + PrintProfile const* activeProfile( ) { + return _activeProfile; + } + + bool addProfile( PrintProfile* newProfile ); + bool removeProfile( QString const& name ); + + bool setActiveProfile( QString const& profileName ); + + bool importProfiles( QString const& fileName ); + bool exportProfiles( QString const& fileName ); + +protected: + +private: + + PrintProfileCollection* _profiles { new PrintProfileCollection }; + PrintProfile* _activeProfile { }; + + PrintProfile* _findProfile( QString const& name ); + +signals: + ; + + void activeProfileChanged( PrintProfile const* newProfile ); + +public slots: + ; + +protected slots: + ; + +private slots: + ; + +}; + +#endif //!__PRINTPROFILEMANAGER_H__ diff --git a/src/printpumpingparameters.h b/src/printpumpingparameters.h new file mode 100644 index 00000000..18695281 --- /dev/null +++ b/src/printpumpingparameters.h @@ -0,0 +1,146 @@ +#ifndef __PRINTPUMPINGPARAMETERS_H__ +#define __PRINTPUMPINGPARAMETERS_H__ + +class PrintPumpingParameters { + +public: + + PrintPumpingParameters( ) = default; + PrintPumpingParameters( PrintPumpingParameters const& ) = default; + PrintPumpingParameters( PrintPumpingParameters&& ) = default; + PrintPumpingParameters& operator=( PrintPumpingParameters const& ) = default; + PrintPumpingParameters& operator=( PrintPumpingParameters&& ) = default; + + // + // Accessors + // + + // unit: mm, multiples of 0.01 + double pumpUpDistance( ) const { + return _pumpUpDistance; + } + + // unit: ms + int pumpUpTime( ) const { + return _pumpUpTime; + } + + // unit: mm/min + double pumpUpVelocity_Effective( ) const { + return _pumpUpDistance / ( _pumpUpTime / 1000.0 / 60.0 ); + } + + // unit: ms + int pumpUpPause( ) const { + return _pumpUpPause; + } + + // unit: mm, multiples of 0.01 + double pumpDownDistance_Effective( ) const { + return _pumpUpDistance - ( _layerThickness / 1000.0 ); + } + + // unit: ms + int pumpDownTime_Effective( ) const { + return ( pumpDownDistance_Effective( ) / pumpDownVelocity_Effective( ) ) / ( 60.0 / 1000.0 ) + 0.5; + } + + // unit: mm/min + double pumpDownVelocity_Effective( ) const { + return pumpDownDistance_Effective( ) / ( pumpDownTime_Effective( ) / 1000.0 / 60.0 ); + } + + // unit: ms + int pumpDownPause( ) const { + return _pumpDownPause; + } + + // unit: mm/min + double noPumpUpVelocity( ) const { + return _noPumpUpVelocity; + } + + // unit: none + int pumpEveryNthLayer( ) const { + return _pumpEveryNthLayer; + } + + // unit: µm + int layerThickness( ) const { + return _layerThickness; + } + + // unit: ms + int layerExposureTime( ) const { + return _layerExposureTime; + } + + // unit: percent + double powerLevel( ) const { + return _powerLevel; + } + + // + // Mutators + // + + // unit: mm, multiples of 0.01 + void setPumpUpDistance( double const value ) { + _pumpUpDistance = value; + } + + // unit: ms + void setPumpUpTime( int const value ) { + _pumpUpTime = value; + } + + // unit: ms + void setPumpUpPause( int const value ) { + _pumpUpPause = value; + } + + // unit: ms + void setPumpDownPause( int const value ) { + _pumpDownPause = value; + } + + // unit: mm/min + void setNoPumpUpVelocity( double const value ) { + _noPumpUpVelocity = value; + } + + // unit: none + void setPumpEveryNthLayer( int const value ) { + _pumpEveryNthLayer = value; + } + + // unit: µm + void setLayerThickness( int const value ) { + _layerThickness = value; + } + + // unit: ms + void setLayerExposureTime( int const value ) { + _layerExposureTime = value; + } + + // unit: percent + void setPowerLevel( double const value ) { + _powerLevel = value; + } + +private: + + double _pumpUpDistance { 2.00 }; // mm + int _pumpUpTime { 600 }; // ms + int _pumpUpPause { 2000 }; // ms + int _pumpDownPause { 4000 }; // ms + int _noPumpUpVelocity { 200 }; // mm/min + int _pumpEveryNthLayer { 1 }; + int _layerThickness { 100 }; // µm + int _layerExposureTime { 1000 }; // ms + double _powerLevel { 50.0 }; // percent + +}; + +#endif //!__PRINTPUMPINGPARAMETERS_H__ diff --git a/src/printtab.cpp b/src/printtab.cpp index 5f1147d0..7aaf0fc1 100644 --- a/src/printtab.cpp +++ b/src/printtab.cpp @@ -70,8 +70,8 @@ PrintTab::PrintTab( QWidget* parent ): InitialShowEventMixin( _powerLevelValue->setAlignment( Qt::AlignRight ); _powerLevelValue->setFont( boldFont ); - _powerLevelSlider->setMinimum( 20 ); - _powerLevelSlider->setMaximum( 100 ); + _powerLevelSlider->setMinimum( ProjectorMinPercent ); + _powerLevelSlider->setMaximum( ProjectorMaxPercent ); _powerLevelSlider->setOrientation( Qt::Horizontal ); _powerLevelSlider->setPageStep( 5 ); _powerLevelSlider->setSingleStep( 1 ); diff --git a/src/profilesjsonparser.h b/src/profilesjsonparser.h new file mode 100644 index 00000000..2fb2733c --- /dev/null +++ b/src/profilesjsonparser.h @@ -0,0 +1,220 @@ +#ifndef PROFILESJSONPARSER_H +#define PROFILESJSONPARSER_H + +#include "printprofile.h" + +#define DEBUG_LOGS + +class ProfilesJsonParser +{ +public: + static QVector* loadProfiles() { + QVector* profilesList = new QVector(); + debug( "ProfilesJsonParser::loadProfiles: opening file\n" ); + QFile jsonFile(PrintProfilesPath); + if(!jsonFile.exists()) + { + // Show message when not found a profile in path + // TODO: Create file with default profile + QMessageBox msgBox; + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText("File print profile does not exist\n" ); + msgBox.open(); + msgBox.exec(); + + debug( "ProfilesJsonParser::loadProfiles: File %s does not exist\n", PrintProfilesPath.toUtf8( ).data( ) ); + return profilesList; + } + jsonFile.open(QIODevice::ReadOnly); + + debug( "ProfilesJsonParser::loadProfiles: building document\n" ); + QJsonDocument jsonDocument=QJsonDocument().fromJson(jsonFile.readAll()); + + debug( "ProfilesJsonParser::loadProfiles: get root array\n" ); + QJsonArray array = jsonDocument.array(); + + debug( "ProfilesJsonParser::loadProfiles: iter over array: %d elements\n", array.count() ); + for(int i=0; isetProfileName(obj["name"].toString()); + } + else + { + debug( "ProfilesJsonParser::loadProfiles: Error while parsing name field" ); + throw new QException(); + } + + debug( " + get baseLayerCount\n" ); + auto blc = obj["baseLayerCount"]; + + if(blc.isDouble()) + printProfile->setBaseLayerCount(blc.toInt()); + else + { + debug( "ProfilesJsonParser::loadProfiles: Error while parsing baseLayerCount field" ); + throw new QException(); + } + + debug( " + get baseLayersPumpingParameters\n" ); + auto baseLayersPumpingParameters = obj["baseLayersPumpingParameters"]; + + if(!baseLayersPumpingParameters.isUndefined() && !baseLayersPumpingParameters.isNull()) + { + PrintPumpingParameters params = _parsePrintPumpingParameters(baseLayersPumpingParameters.toObject()); + printProfile->setBaseLayersPumpingParameters(params); + printProfile->setBaseLayersPumpingEnabled(true); + } + else + printProfile->setBaseLayersPumpingEnabled(false); + + debug( " + get bodyLayersPumpingParameters\n" ); + auto bodyLayersPumpingParameters = obj["bodyLayersPumpingParameters"]; + + if(!bodyLayersPumpingParameters.isUndefined() && !bodyLayersPumpingParameters.isNull()) + { + PrintPumpingParameters params = _parsePrintPumpingParameters(bodyLayersPumpingParameters.toObject()); + printProfile->setBodyLayersPumpingParameters(params); + printProfile->setBodyLayersPumpingEnabled(true); + } + else + printProfile->setBodyLayersPumpingEnabled(false); + + debug( " + push back to list\n" ); + profilesList->push_back(printProfile); + } + catch (QException*) + { + delete printProfile; + } + catch (...) + { + debug( "ProfilesJsonParser::loadProfiles: Unknown error while parsing print profile\n" ); + delete printProfile; + } + } + + debug( "ProfilesJsonParser::loadProfiles: end parsing\n" ); + return profilesList; + } + + static void saveProfiles(const QVector* profiles) + { + debug( "ProfilesJsonParser::saveProfiles:\n" ); + QFile jsonFile(PrintProfilesPath); + + QJsonDocument jsonDocument=QJsonDocument(); + + QJsonArray jsonArray; + + debug( " + loop start: %d profiles\n", profiles->count( ) ); + for(int i=0; icount(); ++i) + { + auto profile = (*profiles)[i]; + + debug( " + serializing profile %s\n", profile->profileName( ).toUtf8( ).data( ) ); + if(profile->profileName() == "temp") + continue; + + QJsonObject json; + + json["name"] = profile->profileName(); + json["baseLayerCount"] = profile->baseLayerCount(); + + if(profile->baseLayersPumpingEnabled()) + { + QJsonObject baseParameters = _serializePrintPumpingParameters(profile->baseLayersPumpingParameters()); + json["baseLayersPumpingParameters"]= baseParameters; + } + + if(profile->bodyLayersPumpingEnabled()) + { + QJsonObject bodyParameters = _serializePrintPumpingParameters(profile->bodyLayersPumpingParameters()); + json["bodyLayersPumpingParameters"]= bodyParameters; + } + + jsonArray.append(json); + } + + jsonDocument.setArray(jsonArray); + + jsonFile.open(QFile::WriteOnly); + jsonFile.write(jsonDocument.toJson()); + } + +private: + static PrintPumpingParameters _parsePrintPumpingParameters(QJsonObject obj) + { + PrintPumpingParameters params; + + params.setPumpUpDistance( _parseIntValue(obj, QString("pumpUpDistance")) ); + params.setPumpUpTime( _parseDoubleValue(obj, QString("pumpUpTime")) ); + params.setPumpUpPause( _parseDoubleValue(obj, QString("pumpUpPause")) ); + params.setPumpDownPause( _parseDoubleValue(obj, QString("pumpDownPause")) ); + params.setNoPumpUpVelocity( _parseDoubleValue(obj, QString("noPumpUpVelocity")) ); + params.setPumpEveryNthLayer( _parseDoubleValue(obj, QString("pumpEveryNthLayer")) ); + params.setLayerThickness( _parseDoubleValue(obj, QString("layerThickness")) ); + params.setLayerExposureTime( _parseDoubleValue(obj, QString("layerExposureTime")) ); + params.setPowerLevel( _parseIntValue(obj, QString("powerLevel")) ); + + return params; + } + + static int _parseIntValue(QJsonObject obj, QString propertyName) + { + QJsonValue value; + + value = obj[propertyName]; + + if(value.isDouble()) + return value.toInt(); + else + { + debug( "ProfilesJsonParser::_parseIntValue: Error while parsing field %s\n", propertyName.toUtf8( ).data( ) ); + throw new QException(); + } + } + + static double _parseDoubleValue(QJsonObject obj, QString propertyName) + { + QJsonValue value; + + value = obj[propertyName]; + + if(value.isDouble()) + return value.toDouble(); + else + { + debug( "ProfilesJsonParser::_parseDoubleValue: Error while parsing field %s\n", propertyName.toUtf8( ).data( ) ); + throw new QException(); + } + } + + static QJsonObject _serializePrintPumpingParameters(PrintPumpingParameters params) + { + QJsonObject result; + + result["pumpUpDistance"]=params.pumpUpDistance(); + result["pumpUpTime"]=params.pumpUpTime(); + result["pumpUpPause"]=params.pumpUpPause(); + result["pumpDownPause"]=params.pumpDownPause(); + result["noPumpUpVelocity"]=params.noPumpUpVelocity(); + result["pumpEveryNthLayer"]=params.pumpEveryNthLayer(); + result["layerThickness"]=params.layerThickness(); + result["layerExposureTime"]=params.layerExposureTime(); + result["powerLevel"]=params.powerLevel(); + + return result; + } + +}; + +#endif // PROFILESJSONPARSER_H diff --git a/src/profilestab.cpp b/src/profilestab.cpp new file mode 100644 index 00000000..8d7b63ef --- /dev/null +++ b/src/profilestab.cpp @@ -0,0 +1,503 @@ +#include "pch.h" + +#include "inputdialog.h" +#include "profilestab.h" +#include "profilesjsonparser.h" +#include "window.h" + +#include +#include + +ProfilesTab::ProfilesTab( QWidget* parent ): TabBase( parent ) { + auto origFont = font( ); + auto boldFont = ModifyFont( origFont, QFont::Bold ); + auto fontAwesome = ModifyFont( origFont, "FontAwesome", LargeFontSize ); + _fontAwesome = new QFont(fontAwesome); + + + QGroupBox* cpyProfilesUsbBox = new QGroupBox(); + cpyProfilesUsbBox->setLayout(WrapWidgetsInVBox(_cpyProfilesUsb, nullptr)); + cpyProfilesUsbBox->setContentsMargins( { } ); + + QGroupBox* cpyStlFilesUsbBox = new QGroupBox(); + cpyStlFilesUsbBox->setLayout(WrapWidgetsInVBox(_cpyStlFilesUsb, nullptr)); + cpyStlFilesUsbBox->setContentsMargins( { } ); + + + _cpyProfilesUsb->setFont(fontAwesome); + _cpyStlFilesUsb->setFont(fontAwesome); + + _importParams->setFont(fontAwesome); + _importParams->setFixedSize( MainButtonSize ); + _importParams->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + + _exportParams->setFont(fontAwesome); + _exportParams->setFixedSize( MainButtonSize ); + _exportParams->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + + _newProfile->setFont(fontAwesome); + _newProfile->setFixedSize( MainButtonSize ); + _newProfile->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + + _renameProfile->setFont(fontAwesome); + _renameProfile->setFixedSize( MainButtonSize ); + _renameProfile->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + + _overwriteProfile->setFont(fontAwesome); + _overwriteProfile->setFixedSize( MainButtonSize ); + _overwriteProfile->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + + _deleteProfile->setFont(fontAwesome); + _deleteProfile->setFixedSize( MainButtonSize ); + _deleteProfile->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + + _loadProfile->setFont(fontAwesome); + _loadProfile->setFixedSize( MainButtonSize ); + _loadProfile->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + + // Default disabled all button no profile is selected + _enableButtonProfile(false); + _setupProfilesList(fontAwesome); + + QObject::connect( _importParams, &QPushButton::clicked, this, &ProfilesTab::importParams_clicked ); + QObject::connect( _exportParams, &QPushButton::clicked, this, &ProfilesTab::exportParams_clicked ); + QObject::connect( _newProfile, &QPushButton::clicked, this, &ProfilesTab::newProfile_clicked ); + QObject::connect( _renameProfile, &QPushButton::clicked, this, &ProfilesTab::renamePProfile_clicked ); + QObject::connect( _overwriteProfile, &QPushButton::clicked, this, &ProfilesTab::updateProfile_clicked ); + QObject::connect( _deleteProfile, &QPushButton::clicked, this, &ProfilesTab::deleteProfile_clicked ); + QObject::connect( _loadProfile, &QPushButton::clicked, this, &ProfilesTab::loadProfile_clicked ); + QObject::connect( _profilesList, &QListView::clicked, this, &ProfilesTab::itemClicked ); + + setLayout( + WrapWidgetsInHBox( + WrapWidgetsInVBox( + _exportParams, + cpyProfilesUsbBox, + cpyStlFilesUsbBox, + nullptr, + WrapWidgetsInHBox( + WrapWidgetsInVBox( + _importParams, + _loadProfile, + _deleteProfile + ), + WrapWidgetsInVBox( + _newProfile, + _renameProfile, + _overwriteProfile + ) + ) + ), + _profilesList + ) + ); +} + +ProfilesTab::~ProfilesTab( ) { + /*empty*/ +} + + +void ProfilesTab::itemClicked(QModelIndex const& index) +{ + _enableButtonProfile(true); +} + + +void ProfilesTab::_enableButtonProfile( bool enabled ) { + _overwriteProfile->setEnabled(enabled); + _deleteProfile->setEnabled(enabled); + _loadProfile->setEnabled(enabled); + _renameProfile->setEnabled(enabled); +} + +void ProfilesTab::tab_uiStateChanged( TabIndex const sender, UiState const state ) { + debug( "+ ProfilesTab::tab_uiStateChanged: from %sTab: %s => %s\n", ToString( sender ), ToString( _uiState ), ToString( state ) ); + _uiState = state; + + switch ( _uiState ) { + case UiState::SelectStarted: + case UiState::SelectCompleted: + case UiState::SliceStarted: + case UiState::SliceCompleted: + case UiState::PrintStarted: + case UiState::PrintCompleted: + break; + } +} + +void ProfilesTab::_setupProfilesList(QFont font) { + + QItemSelectionModel* selectionModel = new QItemSelectionModel( _model ); + _profilesList->setModel( _model ); + _profilesList->setSelectionModel( selectionModel ); + _profilesList->setFont( font ); + _profilesList->setVisible( true ); + _profilesList->setSelectionBehavior( QAbstractItemView::SelectRows ); + _profilesList->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + +} + +void ProfilesTab::setPrintProfileManager( PrintProfileManager* printProfileManager ) { + _printProfileManager = printProfileManager; + + QStandardItem* item = nullptr; + QStandardItem* firstItem = nullptr; + QVector* profiles = ProfilesJsonParser::loadProfiles(); + bool findDefaultProfile = false; + int listItemIndex; + + for(int i=0; icount(); ++i) + { + PrintProfile* profile = (*profiles)[i]; + _printProfileManager->addProfile(profile); + + item = new QStandardItem(profile->profileName()); + item->setEditable( false ); + + findDefaultProfile = false; + if ( profile->profileName() == "default" ) + { + findDefaultProfile = true; + } + + if( !i ) + { + firstItem=item; + _printProfileManager->setActiveProfile(profile->profileName()); + _enableButtonProfile(true); + } + + if ( !findDefaultProfile ) + { + _model->setItem( listItemIndex, 0, item ); + listItemIndex++; + } + } + + if ( findDefaultProfile ) + { + qDebug() << "Find default profile"; + } + else + { + // TODO: create default profile ? + qDebug() << "Not find default profile"; + } + + + if( firstItem ) + _profilesList->setCurrentIndex( _model->indexFromItem(firstItem) ); + + delete profiles; +} + +void ProfilesTab::importParams_clicked(bool) +{ + Window* w = App::mainWindow(); + + QMessageBox msgBox; + // because when two line text causes wrong value of sizeHint().width() and sizeHint().height() + msgBox.setText("
Are You sure to import all profiles
from USB memory stick?
"); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + msgBox.setFont(*_fontAwesome); + msgBox.move( w->x() + (w->width() - msgBox.sizeHint().width())/2, w->y() + (w->height() - msgBox.sizeHint().height())/2 ); + int ret = msgBox.exec(); + + switch (ret) { + case QMessageBox::Yes: + + // @todo how to pass checkboxes values? what filename means? + if(!_printProfileManager->importProfiles(nullptr)) + { + msgBox.setText("
Something went wrong. Make sure memory
stick is inserted into USB drive.
"); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.move( (w->width() - msgBox.sizeHint().width())/2, (w->height() - msgBox.sizeHint().height())/2 ); + msgBox.exec(); + } + else + { + msgBox.setText("Import successed."); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.move( (w->width() - msgBox.sizeHint().width())/2, (w->height() - msgBox.sizeHint().height())/2 ); + msgBox.exec(); + } + break; + default: + break; + } +} + +void ProfilesTab::exportParams_clicked(bool) +{ + Window* w = App::mainWindow(); + + QMessageBox msgBox; + msgBox.setText("
Are You sure to export all profiles
to USB memory stick?
"); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + msgBox.setFont(*_fontAwesome); + msgBox.move( (w->width() - msgBox.sizeHint().width())/2, (w->height() - msgBox.sizeHint().height())/2 ); + int ret = msgBox.exec(); + + switch (ret) { + case QMessageBox::Yes: + // @todo how to pass checkboxes values? what filename means? + if(!_printProfileManager->exportProfiles(nullptr)) + { + msgBox.setText("Something went wrong. Make sure memory stick is inserted into USB drive."); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.move( (w->width() - msgBox.sizeHint().width())/2, (w->height() - msgBox.sizeHint().height())/2 ); + msgBox.exec(); + } + else + { + msgBox.setText("Import successed."); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.move( (w->width() - msgBox.sizeHint().width())/2, (w->height() - msgBox.sizeHint().height())/2 ); + msgBox.exec(); + } + break; + default: + break; + } +} + +void ProfilesTab::newProfile_clicked(bool) +{ + Window* w = App::mainWindow(); + + QMessageBox msgBox; + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setFont(*_fontAwesome); + + InputDialog* inputDialog = new InputDialog(QString("Entry profile name: ")); + int ret = inputDialog->exec(); + + QString filename = inputDialog->getValue(); + + if (ret && !filename.isEmpty()) + { + if(!_createNewProfile(filename)) + { + msgBox.setText("Something went wrong."); + msgBox.move( (w->width() - msgBox.sizeHint().width())/2, (w->height() - msgBox.sizeHint().height())/2 ); + msgBox.exec(); + } + else + { + msgBox.setText("Profile successfuly added."); + msgBox.move( (w->width() - msgBox.sizeHint().width())/2, (w->height() - msgBox.sizeHint().height())/2 ); + msgBox.exec(); + } + } +} + +void ProfilesTab::renamePProfile_clicked(bool) +{ + Window* w = App::mainWindow(); + + QMessageBox msgBox; + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setFont(*_fontAwesome); + InputDialog* inputDialog = new InputDialog(QString("Entry profile name: ")); + int ret = inputDialog->exec(); + + QString filename = inputDialog->getValue(); + if (ret && !filename.isEmpty()) + { + if(!_renamePProfile(filename)) + { + msgBox.setText("Something went wrong."); + msgBox.move( (w->width() - msgBox.sizeHint().width())/2, (w->height() - msgBox.sizeHint().height())/2 ); + msgBox.exec(); + } + else + { + msgBox.setText("Profile successfuly renamed."); + msgBox.move( (w->width() - msgBox.sizeHint().width())/2, (w->height() - msgBox.sizeHint().height())/2 ); + msgBox.exec(); + } + } +} + +void ProfilesTab::updateProfile_clicked(bool) +{ + Window* w = App::mainWindow(); + + QMessageBox msgBox; + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setFont(*_fontAwesome); + msgBox.setText("Are You sure to update selected profile?"); + msgBox.move( (w->width() - msgBox.sizeHint().width())/2, (w->height() - msgBox.sizeHint().height())/2 ); + int ret = msgBox.exec(); + + switch (ret) { + case QMessageBox::Yes: + if(!_updateProfile()) + { + msgBox.setText("Something went wrong."); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); + } + break; + default: + break; + } +} + +void ProfilesTab::deleteProfile_clicked(bool) +{ + Window* w = App::mainWindow(); + + QMessageBox msgBox; + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setFont(*_fontAwesome); + msgBox.setText("Are You sure to delete selected profile?"); + msgBox.move( (w->width() - msgBox.sizeHint().width())/2, (w->height() - msgBox.sizeHint().height())/2 ); + int ret = msgBox.exec(); + + switch (ret) { + case QMessageBox::Yes: + if(!_deletePrintProfile()) + { + msgBox.setText("Something went wrong."); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); + } + break; + default: + break; + } +} + +void ProfilesTab::loadProfile_clicked(bool) +{ + Window* w = App::mainWindow(); + + QMessageBox msgBox; + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setFont(*_fontAwesome); + msgBox.setText("Are You sure to load selected profile?"); + //qDebug() << w->width() << " " << msgBox.sizeHint().width() << " " << w->height() << " " << msgBox.sizeHint().height(); + msgBox.move( (w->width() - msgBox.sizeHint().width())/2, (w->height() - msgBox.sizeHint().height())/2 ); + int ret = msgBox.exec(); + + switch (ret) { + case QMessageBox::Yes: + if(!_loadPrintProfile()) + { + msgBox.setText("Something went wrong."); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.move( (w->width() - msgBox.sizeHint().width())/2, (w->height() - msgBox.sizeHint().height())/2 ); + msgBox.exec(); + } + break; + default: + break; + } +} + +bool ProfilesTab::_createNewProfile(QString profileName) +{ + PrintProfile* printProfile = (PrintProfile*)_printProfileManager->activeProfile(); + PrintProfile* profileCopy = printProfile->copy(); + + profileCopy->setProfileName(profileName); + _printProfileManager->addProfile(profileCopy); + QStandardItem* item = new QStandardItem(profileName); + item->setEditable(false); + _model->appendRow(item); + ProfilesJsonParser::saveProfiles(_printProfileManager->profiles()); + return true; +} + +bool ProfilesTab::_renamePProfile(QString profileName) +{ + QModelIndex index = _profilesList->currentIndex(); + + QString oldName = index.data(Qt::DisplayRole).toString(); + _model->setData(index, QVariant(profileName)); + + QVector* c = (QVector*)_printProfileManager->profiles(); + auto iter = std::find_if( c->begin( ), c->end( ), [&oldName] ( PrintProfile* p ) { return oldName == p->profileName( ); } ); + PrintProfile* profile = ( iter != c->end( ) ) ? *iter : nullptr; + + profile->setProfileName(profileName); + + ProfilesJsonParser::saveProfiles(_printProfileManager->profiles()); + + return true; +} + +bool ProfilesTab::_updateProfile() +{ + QModelIndex index = _profilesList->currentIndex(); + QString profileName = index.data(Qt::DisplayRole).toString(); + + QVector* c = (QVector*)_printProfileManager->profiles(); + auto iter = std::find_if( c->begin( ), c->end( ), [&profileName] ( PrintProfile* p ) { return profileName == p->profileName( ); } ); + PrintProfile* profile = ( iter != c->end( ) ) ? *iter : nullptr; + PrintProfile* activeProfile = (PrintProfile*)_printProfileManager->activeProfile(); + + profile->setBaseLayerCount(activeProfile->baseLayerCount()); + profile->setBaseLayersPumpingEnabled(activeProfile->baseLayersPumpingEnabled()); + profile->setBodyLayersPumpingEnabled(activeProfile->bodyLayersPumpingEnabled()); + + PrintPumpingParameters baseParams = activeProfile->baseLayersPumpingParameters(); + PrintPumpingParameters newBaseParams; + + newBaseParams.setPumpUpDistance( baseParams.pumpUpDistance() ); + newBaseParams.setPumpUpTime( baseParams.pumpUpTime() ); + newBaseParams.setPumpUpPause( baseParams.pumpUpPause() ); + newBaseParams.setPumpDownPause( baseParams.pumpDownPause() ); + newBaseParams.setNoPumpUpVelocity( baseParams.noPumpUpVelocity() ); + newBaseParams.setPumpEveryNthLayer( baseParams.pumpEveryNthLayer() ); + newBaseParams.setLayerThickness( baseParams.layerThickness() ); + newBaseParams.setLayerExposureTime( baseParams.layerExposureTime() ); + newBaseParams.setPowerLevel( baseParams.powerLevel() ); + + profile->setBaseLayersPumpingParameters(newBaseParams); + + PrintPumpingParameters bodyParams = activeProfile->bodyLayersPumpingParameters(); + PrintPumpingParameters newBodyParams; + + newBodyParams.setPumpUpDistance( bodyParams.pumpUpDistance() ); + newBodyParams.setPumpUpTime( bodyParams.pumpUpTime() ); + newBodyParams.setPumpUpPause( bodyParams.pumpUpPause() ); + newBodyParams.setPumpDownPause( bodyParams.pumpDownPause() ); + newBodyParams.setNoPumpUpVelocity( bodyParams.noPumpUpVelocity() ); + newBodyParams.setPumpEveryNthLayer( bodyParams.pumpEveryNthLayer() ); + newBodyParams.setLayerThickness( bodyParams.layerThickness() ); + newBodyParams.setLayerExposureTime( bodyParams.layerExposureTime() ); + newBodyParams.setPowerLevel( bodyParams.powerLevel() ); + + profile->setBaseLayersPumpingParameters(bodyParams); + + ProfilesJsonParser::saveProfiles(_printProfileManager->profiles()); + + return true; +} + +bool ProfilesTab::_deletePrintProfile() +{ + QModelIndex index = _profilesList->currentIndex(); + QString itemText = index.data(Qt::DisplayRole).toString(); + _printProfileManager->removeProfile(itemText); + + _model->removeRows(index.row(), 1); + ProfilesJsonParser::saveProfiles(_printProfileManager->profiles()); + + ProfilesJsonParser::loadProfiles(); + _enableButtonProfile(false); // Because no item is selected after deleted + + return true; +} + +bool ProfilesTab::_loadPrintProfile() +{ + QModelIndex index = _profilesList->currentIndex(); + QString itemText = index.data(Qt::DisplayRole).toString(); + return _printProfileManager->setActiveProfile(itemText); +} diff --git a/src/profilestab.h b/src/profilestab.h new file mode 100644 index 00000000..0dff0f88 --- /dev/null +++ b/src/profilestab.h @@ -0,0 +1,72 @@ +#ifndef __PROFILESTAB_H__ +#define __PROFILESTAB_H__ + +#include "tabbase.h" +#include "printprofilemanager.h" + +class ProfilesTab: public TabBase { + + Q_OBJECT + +public: + + ProfilesTab( QWidget* parent = nullptr ); + virtual ~ProfilesTab( ) override; + + virtual TabIndex tabIndex( ) const override { return TabIndex::Profiles; } + + void setPrintProfileManager( PrintProfileManager* printProfileManager ); + +protected: + +private: + + PrintProfileManager* _printProfileManager; + + + QPushButton* _importParams { new QPushButton("Import") }; + QPushButton* _exportParams { new QPushButton("Export") }; + QPushButton* _newProfile { new QPushButton("Create profile") }; + QPushButton* _renameProfile { new QPushButton("Rename profile") }; + QPushButton* _overwriteProfile { new QPushButton("Update profile") }; + QPushButton* _deleteProfile { new QPushButton("Delete selected") }; + QPushButton* _loadProfile { new QPushButton("Load selected") }; + QCheckBox* _cpyProfilesUsb { new QCheckBox("Copy profiles to USB") }; + QCheckBox* _cpyStlFilesUsb { new QCheckBox("Copy STL files to USB") }; + QListView* _profilesList { new QListView }; + QStandardItemModel* _model { new QStandardItemModel }; + QFont* _fontAwesome; + + void _setupProfilesList(QFont font); + bool _createNewProfile(QString profileName); + bool _renamePProfile(QString profileName); + bool _updateProfile(); + bool _deletePrintProfile(); + bool _loadPrintProfile(); + void _enableButtonProfile( bool enabled ); +signals: + ; + +public slots: + ; + + virtual void tab_uiStateChanged( TabIndex const sender, UiState const state ) override; + +protected slots: + ; + +private slots: + ; + + void importParams_clicked(bool); + void exportParams_clicked(bool); + void newProfile_clicked(bool); + void renamePProfile_clicked(bool); + void updateProfile_clicked(bool); + void deleteProfile_clicked(bool); + void loadProfile_clicked(bool); + void itemClicked(const QModelIndex &index); + +}; + +#endif //!__PROFILESTAB_H__ diff --git a/src/strings.cpp b/src/strings.cpp index fb49db34..31761190 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -47,6 +47,7 @@ namespace { "Print", "Status", "Advanced", + "Profiles", "System", }; diff --git a/src/tabbase.h b/src/tabbase.h index 1ba8ce68..655a37af 100644 --- a/src/tabbase.h +++ b/src/tabbase.h @@ -26,6 +26,7 @@ class TabBase: public QWidget { Print, Status, Advanced, + Profiles, System, }; Q_ENUM( TabIndex ); diff --git a/src/upgrademanager.cpp b/src/upgrademanager.cpp index 9e4d08db..5c34ee84 100644 --- a/src/upgrademanager.cpp +++ b/src/upgrademanager.cpp @@ -1,5 +1,7 @@ #include "pch.h" +#include + #include "upgrademanager.h" #include "gpgsignaturechecker.h" @@ -12,32 +14,31 @@ namespace { - QStringList UpgradeKitFileGlobs { - "lightfield-debug_*_amd64.kit", - "lightfield-release_*_amd64.kit" + QStringList const UpgradeKitFileGlobs { + "lightfield-*.kit", }; - QStringList UpgradeKitDirGlobs { - "lightfield-debug_*_amd64", - "lightfield-release_*_amd64" + QStringList const UpgradeKitDirGlobs { + "lightfield-*", }; - QMap BuildTypeToString { + QMap const BuildTypeToString { { BuildType::Release, "release" }, { BuildType::Debug, "debug" }, }; - QMap StringToBuildType { + QMap const StringToBuildType { { "release", BuildType::Release }, { "debug", BuildType::Debug }, }; - QRegularExpression const MetadataFieldMatcherRegex { "^([-0-9A-Za-z]+):\\s*" }; - QRegularExpression const WhitespaceRegex { "\\s+" }; - QRegularExpression const CommentMatcherRegex { "\\s+#.*$" }; + QRegularExpression const MetadataFieldMatcherRegex { "^([-0-9A-Za-z]+):\\s*" }; + QRegularExpression const WhitespaceRegex { "\\s+" }; + QRegularExpression const CommentMatcherRegex { "\\s+#.*$" }; + QRegularExpression const KitFileMatcherRegex { "^lightfield(?:-(.*?))?-(debug|release)_(.*?)_(.*?)\\.kit$" }; + QRegularExpression const KitDirMatcherRegex { "^lightfield(?:-(.*?))?-(debug|release)_(.*?)_(.*?)$" }; - QStringList ExpectedMetadataFields { - "Metadata-Version", + QStringList const ExpectedMetadataV1Fields { "Version", "Build-Type", "Release-Date", @@ -45,6 +46,21 @@ namespace { "Checksums-SHA256" }; + QStringList const ExpectedMetadataV2Fields { + "Architecture", + "Release-Train" + }; + + QStringList _EnsureMapContainsKeys( QMap map, QStringList keyList ) { + QStringList result; + for ( auto const& key : keyList ) { + if ( !map.contains( key ) ) { + result += key; + } + } + return result; + } + } UpgradeManager::UpgradeManager( QObject* parent ): QObject( parent ) { @@ -52,6 +68,13 @@ UpgradeManager::UpgradeManager( QObject* parent ): QObject( parent ) { _stdoutLogger = new StdioLogger { "apt-get/stdout", this }; _processRunner = new ProcessRunner { this }; + { + utsname u; + + uname( &u ); + _architecture = u.machine; + } + QObject::connect( _processRunner, &ProcessRunner::readyReadStandardError, _stderrLogger, &StdioLogger::read ); QObject::connect( _processRunner, &ProcessRunner::readyReadStandardOutput, _stdoutLogger, &StdioLogger::read ); @@ -106,33 +129,80 @@ void UpgradeManager::_checkForUpgrades( QString const& upgradesPath ) { for ( auto kitDirInfo : QDir { UpdatesRootPath }.entryInfoList( UpgradeKitDirGlobs, QDir::Dirs | QDir::Readable | QDir::Executable, QDir::Name ) ) { QString kitPath { kitDirInfo.absoluteFilePath( ) }; QDir kitDir { kitPath }; - debug( " + found unpacked kit in '%s'\n", kitPath.toUtf8( ).data( ) ); + + auto match { KitDirMatcherRegex.match( kitDirInfo.fileName( ) ) }; + if ( !match.hasMatch( ) ) { + debug( " + ignoring unpacked kit '%s': folder name doesn't match schema\n", kitPath.toUtf8( ).data( ) ); + continue; + } + if ( match.captured( 4 ) != _architecture ) { + debug( " + ignoring unpacked kit '%s': wrong architecture\n", kitPath.toUtf8( ).data( ) ); + continue; + } if ( !kitDir.exists( "version.inf" ) ) { - debug( " + deleting bad unpacked kit: version.inf file is missing\n" ); + debug( " + deleting bad unpacked kit '%s': version.inf file is missing\n", kitPath.toUtf8( ).data( ) ); kitDir.removeRecursively( ); continue; } if ( !kitDir.exists( "version.inf.sig" ) ) { - debug( " + deleting bad unpacked kit: version.inf.sig file is missing\n" ); + debug( " + deleting bad unpacked kit '%s': version.inf.sig file is missing\n", kitPath.toUtf8( ).data( ) ); kitDir.removeRecursively( ); continue; } + debug( + "+ UpgradeManager::_checkForUpgrades: found unpacked kit in '%s'\n" + " + Version: %s\n" + " + Build type: %s\n" + " + Release train: %s\n" + " + Architecture: %s\n" + "", + kitPath.toUtf8( ).data( ), + match.captured( 3 ).toUtf8( ).data( ), + match.captured( 2 ).toUtf8( ).data( ), + match.captured( 1 ).toUtf8( ).data( ), + match.captured( 4 ).toUtf8( ).data( ) + ); + _unprocessedUpgradeKits.append( UpgradeKitInfo { kitPath } ); } if ( !upgradesPath.isEmpty( ) ) { debug( "+ UpgradeManager::_checkForUpgrades: looking for upgrade kits in path '%s'\n", upgradesPath.toUtf8( ).data( ) ); for ( auto kitFile : QDir { upgradesPath }.entryInfoList( UpgradeKitFileGlobs, QDir::Files | QDir::Readable, QDir::Name ) ) { - debug( "+ UpgradeManager::_checkForUpgrades: found kit file '%s'\n", kitFile.absoluteFilePath( ).toUtf8( ).data( ) ); + auto kitFilePath { kitFile.absoluteFilePath( ) }; - QFileInfo sigFile { kitFile.absoluteFilePath( ) % ".sig" }; + auto match { KitFileMatcherRegex.match( kitFile.fileName( ) ) }; + if ( !match.hasMatch( ) ) { + debug( " + ignoring kit '%s': file name doesn't match schema\n", kitFilePath.toUtf8( ).data( ) ); + continue; + } + if ( match.captured( 4 ) != _architecture ) { + debug( " + ignoring kit '%s': wrong architecture\n", kitFilePath.toUtf8( ).data( ) ); + continue; + } + + QFileInfo sigFile { kitFilePath % ".sig" }; if ( !sigFile.exists( ) ) { - debug( " + ignoring kit: signature file is missing\n" ); + debug( " + ignoring kit '%s': signature file is missing\n", kitFilePath.toUtf8( ).data( ) ); continue; } + debug( + "+ UpgradeManager::_checkForUpgrades: found kit file '%s'\n" + " + Version: '%s'\n" + " + Build type: '%s'\n" + " + Release train: '%s'\n" + " + Architecture: '%s'\n" + "", + kitFilePath.toUtf8( ).data( ), + match.captured( 3 ).toUtf8( ).data( ), + match.captured( 2 ).toUtf8( ).data( ), + match.captured( 1 ).toUtf8( ).data( ), + match.captured( 4 ).toUtf8( ).data( ) + ); + _unprocessedUpgradeKits.append( UpgradeKitInfo { kitFile, sigFile } ); } } @@ -378,33 +448,38 @@ bool UpgradeManager::_parseVersionInfo( QString const& versionInfoFileName, Upgr ++index; } - bool missingMetadata = false; - for ( auto const& field : ExpectedMetadataFields ) { - if ( !fields.contains( field ) ) { - debug( " + metadata is missing field \"%s\"\n", field.toUtf8( ).data( ) ); - missingMetadata = true; - } - } - if ( missingMetadata ) { - return false; - } - { - update.metadataVersionString = fields["Metadata-Version"]; + update.metadataVersionString = fields.value( "Metadata-Version" ); bool ok = false; - update.metadataVersion = update.metadataVersionString.toInt( &ok ); + update.metadataVersion = update.metadataVersionString.isEmpty( ) ? 0 : update.metadataVersionString.toInt( &ok ); if ( !ok ) { debug( " + bad metadata version \"%s\"\n", update.metadataVersionString.toUtf8( ).data( ) ); return false; } - if ( update.metadataVersion != 1 ) { + if ( ( update.metadataVersion < 1 ) || ( update.metadataVersion > 2 ) ) { debug( " + unknown metadata version \"%s\"\n", update.metadataVersionString.toUtf8( ).data( ) ); return false; } } + QStringList missingMetadataFields; + if ( update.metadataVersion >= 1 ) { + if ( auto missingFields = _EnsureMapContainsKeys( fields, ExpectedMetadataV1Fields ); !missingFields.isEmpty( ) ) { + missingMetadataFields += missingFields; + } + } + if ( update.metadataVersion >= 2 ) { + if ( auto missingFields = _EnsureMapContainsKeys( fields, ExpectedMetadataV2Fields ); !missingFields.isEmpty( ) ) { + missingMetadataFields += missingFields; + } + } + if ( !missingMetadataFields.isEmpty( ) ) { + debug( " + metadata is missing field%s %s\n", missingMetadataFields.count( ) != 1 ? "s" : "", missingMetadataFields.join( ", " ) ); + return false; + } + { update.versionString = fields["Version"]; @@ -465,6 +540,15 @@ bool UpgradeManager::_parseVersionInfo( QString const& versionInfoFileName, Upgr debug( " + file '%s': checksum %s\n", ( path + pieces[1] ).toUtf8( ).data( ), pieces[0].toUtf8( ).data( ) ); } + if ( update.metadataVersion > 1 ) { + update.architecture = fields["Architecture"]; + if ( _architecture != update.architecture ) { + debug( " + wrong architecture '%s'\n", update.architecture.toUtf8( ).data( ) ); + return false; + } + update.releaseTrain = fields["Release-Train"]; + } + return true; } diff --git a/src/upgrademanager.h b/src/upgrademanager.h index c0128776..2f62719f 100644 --- a/src/upgrademanager.h +++ b/src/upgrademanager.h @@ -50,8 +50,12 @@ class UpgradeKitInfo { BuildType buildType { }; + QString architecture; + QDate releaseDate; + QString releaseTrain; + QString description; QMap checksums; @@ -99,6 +103,8 @@ class UpgradeManager: public QObject { QString _stderrJournal; QString _stdoutJournal; + QString _architecture; + void _flushLoggers( ); void _clearJournals( ); void _checkForUpgrades( QString const& upgradesPath ); diff --git a/src/utils.h b/src/utils.h index b68fc614..805c1cb4 100644 --- a/src/utils.h +++ b/src/utils.h @@ -30,11 +30,11 @@ inline QString RemoveFileExtension( QString const& fileName ) { } inline constexpr int PercentagePowerLevelToRawLevel( int percentage ) { - return static_cast( static_cast( percentage ) / 100.0 * 255.0 + 0.5 ); + return static_cast( static_cast( percentage ) / 100.0 * ProjectorMaxPowerLevel + 0.5 ); } inline constexpr int RawPowerLevelToPercentage( int raw ) { - return static_cast( static_cast( raw ) / 255.0 * 100.0 + 0.5 ); + return static_cast( static_cast( raw ) / ProjectorMaxPowerLevel * 100.0 + 0.5 ); } template diff --git a/src/version.h b/src/version.h deleted file mode 100644 index f6e269f1..00000000 --- a/src/version.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __VERSION_H__ -#define __VERSION_H__ - -enum class BuildType { - unknown, - Release, - Debug, -}; - -inline constexpr unsigned MakeVersionCode( unsigned const major, unsigned const minor, unsigned const teeny, unsigned const build = 0 ) { - return ( ( major & 0xFFu ) << 24u ) | ( ( minor & 0xFFu ) << 16u ) | ( ( teeny & 0xFFu ) << 8u ) | ( build & 0xFFu ); -} - -inline constexpr void DecodeVersionCode( unsigned const versionCode, int& major, int& minor, int& teeny, int& build ) { - major = static_cast( ( versionCode >> 24u ) & 0xFFu ); - minor = static_cast( ( versionCode >> 16u ) & 0xFFu ); - teeny = static_cast( ( versionCode >> 8u ) & 0xFFu ); - build = static_cast( versionCode & 0xFFu ); -} - -char const* LIGHTFIELD_VERSION_STRING __attribute__(( weak )) = "1.0.10.0"; -unsigned const LIGHTFIELD_VERSION_MAJOR = 1; -unsigned const LIGHTFIELD_VERSION_MINOR = 0; -unsigned const LIGHTFIELD_VERSION_TEENY = 10; -unsigned const LIGHTFIELD_VERSION_BUILD = 0; -unsigned const LIGHTFIELD_VERSION_CODE = MakeVersionCode( LIGHTFIELD_VERSION_MAJOR, LIGHTFIELD_VERSION_MINOR, LIGHTFIELD_VERSION_TEENY, LIGHTFIELD_VERSION_BUILD ); - -#if defined _DEBUG -BuildType const LIGHTFIELD_VERSION_BUILD_TYPE = BuildType::Debug; -#elif defined NDEBUG -BuildType const LIGHTFIELD_VERSION_BUILD_TYPE = BuildType::Release; -#else -# error Unknown build type: Neither _DEBUG nor NDEBUG are #define:d. -#endif - -#endif // __VERSION_H__ diff --git a/src/version.h.in b/src/version.h.in index ef3d79a0..66e0ca11 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -18,19 +18,21 @@ inline constexpr void DecodeVersionCode( unsigned const versionCode, int& major, build = static_cast( versionCode & 0xFFu ); } -char const* LIGHTFIELD_VERSION_STRING __attribute__(( weak )) = "@@LIGHTFIELD_VERSION_STRING@@"; -unsigned const LIGHTFIELD_VERSION_MAJOR = @@LIGHTFIELD_VERSION_MAJOR@@; -unsigned const LIGHTFIELD_VERSION_MINOR = @@LIGHTFIELD_VERSION_MINOR@@; -unsigned const LIGHTFIELD_VERSION_TEENY = @@LIGHTFIELD_VERSION_TEENY@@; -unsigned const LIGHTFIELD_VERSION_BUILD = @@LIGHTFIELD_VERSION_BUILD@@; -unsigned const LIGHTFIELD_VERSION_CODE = MakeVersionCode( LIGHTFIELD_VERSION_MAJOR, LIGHTFIELD_VERSION_MINOR, LIGHTFIELD_VERSION_TEENY, LIGHTFIELD_VERSION_BUILD ); +char const* LIGHTFIELD_VERSION_STRING __attribute__(( weak )) = "@@VERSION_STRING@@"; +unsigned const LIGHTFIELD_VERSION_MAJOR = @@VERSION_MAJOR@@; +unsigned const LIGHTFIELD_VERSION_MINOR = @@VERSION_MINOR@@; +unsigned const LIGHTFIELD_VERSION_TEENY = @@VERSION_TEENY@@; +unsigned const LIGHTFIELD_VERSION_BUILD = @@VERSION_BUILD@@; +unsigned const LIGHTFIELD_VERSION_CODE = MakeVersionCode( LIGHTFIELD_VERSION_MAJOR, LIGHTFIELD_VERSION_MINOR, LIGHTFIELD_VERSION_TEENY, LIGHTFIELD_VERSION_BUILD ); #if defined _DEBUG -BuildType const LIGHTFIELD_VERSION_BUILD_TYPE = BuildType::Debug; -#elif defined NDEBUG -BuildType const LIGHTFIELD_VERSION_BUILD_TYPE = BuildType::Release; +BuildType const LIGHTFIELD_VERSION_BUILD_TYPE = BuildType::Debug; +#elif defined NDEBUG +BuildType const LIGHTFIELD_VERSION_BUILD_TYPE = BuildType::Release; #else # error Unknown build type: Neither _DEBUG nor NDEBUG are #define:d. #endif +char const* LIGHTFIELD_VERSION_RELEASE_TRAIN __attribute__(( weak )) = "@@RELEASE_TRAIN@@"; + #endif // __VERSION_H__ diff --git a/src/win32junk.h b/src/win32junk.h index 603751ff..dd1e37a0 100644 --- a/src/win32junk.h +++ b/src/win32junk.h @@ -100,6 +100,10 @@ struct statvfs { unsigned long f_bavail; }; +struct utsname { + char machine[]; +}; + //================================================ // POSIX function prototypes //================================================ @@ -126,6 +130,7 @@ extern int sigtimedwait( sigset_t const* set, siginfo_t* info, timespec cons extern int socketpair( int domain, int type, int protocol, int sv[2] ); extern int statvfs( char const* path, struct statvfs* buf ); extern char* strsignal( int sig ); +extern int uname( utsname* buf ) //================================================ // GNU C Library function prototypes diff --git a/src/window.cpp b/src/window.cpp index af100c2b..47ade5ea 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -5,6 +5,7 @@ #include "pngdisplayer.h" #include "printjob.h" #include "printmanager.h" +#include "printprofilemanager.h" #include "shepherd.h" #include "signalhandler.h" #include "upgrademanager.h" @@ -15,6 +16,7 @@ #include "printtab.h" #include "statustab.h" #include "advancedtab.h" +#include "profilestab.h" #include "systemtab.h" namespace { @@ -36,7 +38,6 @@ Window::Window( QWidget* parent ): QMainWindow( parent ) { #if defined _DEBUG _isPrinterPrepared = g_settings.pretendPrinterIsPrepared; #endif // _DEBUG - setWindowFlags( windowFlags( ) | ( g_settings.frameless ? Qt::FramelessWindowHint : Qt::BypassWindowManagerHint ) ); setFixedSize( MainWindowSize ); move( g_settings.mainWindowPosition ); @@ -56,8 +57,9 @@ Window::Window( QWidget* parent ): QMainWindow( parent ) { _printJob = new PrintJob; - _upgradeManager = new UpgradeManager; - _usbMountManager = new UsbMountManager; + _printProfileManager = new PrintProfileManager; + _upgradeManager = new UpgradeManager; + _usbMountManager = new UsbMountManager; QObject::connect( _usbMountManager, &UsbMountManager::ready, _upgradeManager, [this] ( ) { QObject::connect( _usbMountManager, &UsbMountManager::filesystemMounted, _upgradeManager, &UpgradeManager::checkForUpgrades ); @@ -70,6 +72,7 @@ Window::Window( QWidget* parent ): QMainWindow( parent ) { _printTab = new PrintTab, _statusTab = new StatusTab, _advancedTab = new AdvancedTab, + _profilesTab = new ProfilesTab, _systemTab = new SystemTab, }; @@ -89,10 +92,11 @@ Window::Window( QWidget* parent ): QMainWindow( parent ) { emit shepherdChanged( _shepherd ); emit printJobChanged( _printJob ); - _fileTab ->setUsbMountManager( _usbMountManager ); - _advancedTab->setPngDisplayer ( _pngDisplayer ); - _systemTab ->setUpgradeManager ( _upgradeManager ); - _systemTab ->setUsbMountManager( _usbMountManager ); + _fileTab ->setUsbMountManager ( _usbMountManager ); + _advancedTab->setPngDisplayer ( _pngDisplayer ); + _profilesTab->setPrintProfileManager( _printProfileManager ); + _systemTab ->setUpgradeManager ( _upgradeManager ); + _systemTab ->setUsbMountManager ( _usbMountManager ); _shepherd->start( ); @@ -154,6 +158,15 @@ Window::Window( QWidget* parent ): QMainWindow( parent ) { QObject::connect( _advancedTab, &AdvancedTab::projectorPowerLevelChanged, _printTab, &PrintTab::projectorPowerLevel_changed ); QObject::connect( _advancedTab, &AdvancedTab::printerAvailabilityChanged, _statusTab, &StatusTab::setPrinterAvailable ); QObject::connect( _advancedTab, &AdvancedTab::printerAvailabilityChanged, _systemTab, &SystemTab::setPrinterAvailable ); + QObject::connect( _printProfileManager, &PrintProfileManager::activeProfileChanged, _advancedTab, &AdvancedTab::loadPrintProfile ); + + _advancedTab->setPrintProfileManager( _printProfileManager ); + // + // "Profiles" tab + // + + _profilesTab->setContentsMargins( { } ); + _profilesTab->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); // // "System" tab @@ -476,3 +489,9 @@ void Window::signalHandler_signalReceived( siginfo_t const& info ) { close( ); } + +void Window::showEvent( QShowEvent* aShowEvent ) +{ + QMainWindow::showEvent(aShowEvent); + activateWindow(); +} diff --git a/src/window.h b/src/window.h index 22616348..cee7e174 100644 --- a/src/window.h +++ b/src/window.h @@ -6,8 +6,9 @@ class ModelSelectionInfo; class PngDisplayer; -class PrintManager; class PrintJob; +class PrintManager; +class PrintProfileManager; class Shepherd; class SignalHandler; class UpgradeManager; @@ -18,6 +19,7 @@ class PrepareTab; class PrintTab; class StatusTab; class AdvancedTab; +class ProfilesTab; class SystemTab; class Window: public QMainWindow { @@ -34,35 +36,38 @@ class Window: public QMainWindow { protected: virtual void closeEvent( QCloseEvent* event ) override; - + void showEvent( QShowEvent* aShowEvent ) override; private: - SignalHandler* _signalHandler { }; - ModelSelectionInfo* _modelSelection { }; - PngDisplayer* _pngDisplayer { }; - PrintJob* _printJob { }; - PrintManager* _printManager { }; - Shepherd* _shepherd { }; - UiState _uiState { }; - UpgradeManager* _upgradeManager { }; - UsbMountManager* _usbMountManager { }; - - QTabWidget* _tabWidget { new QTabWidget }; - FileTab* _fileTab; - PrepareTab* _prepareTab; - PrintTab* _printTab; - StatusTab* _statusTab; - AdvancedTab* _advancedTab; - SystemTab* _systemTab; - QPushButton* _helpButton { new QPushButton }; - - bool _isPrinterPrepared { }; - bool _isModelRendered { }; + SignalHandler* _signalHandler { }; + ModelSelectionInfo* _modelSelection { }; + PngDisplayer* _pngDisplayer { }; + PrintJob* _printJob { }; + PrintManager* _printManager { }; + PrintProfileManager* _printProfileManager { }; + Shepherd* _shepherd { }; + UiState _uiState { }; + UpgradeManager* _upgradeManager { }; + UsbMountManager* _usbMountManager { }; + + QTabWidget* _tabWidget { new QTabWidget }; + FileTab* _fileTab; + PrepareTab* _prepareTab; + PrintTab* _printTab; + StatusTab* _statusTab; + AdvancedTab* _advancedTab; + ProfilesTab* _profilesTab; + SystemTab* _systemTab; + QPushButton* _helpButton { new QPushButton }; + + bool _isPrinterPrepared { }; + bool _isModelRendered { }; void _setPrinterPrepared( bool const value ); void _setModelRendered( bool const value ); signals: + ; void printJobChanged( PrintJob* printJob ); void printManagerChanged( PrintManager* printManager ); @@ -72,12 +77,14 @@ class Window: public QMainWindow { void printerPrepared( bool const value ); void terminationRequested( ); - public slots: + ; protected slots: + ; private slots: + ; void startPrinting( ); diff --git a/stdio-shepherd/printer.py b/stdio-shepherd/printer.py index b1b6aa56..345ebad2 100644 --- a/stdio-shepherd/printer.py +++ b/stdio-shepherd/printer.py @@ -111,7 +111,7 @@ def on_online(self): if(self.onlinecb): self.onlinecb() - def connect(self,port=None,baud=250000): + def connect(self,port='/dev/lumen-arduino',baud=250000): baselist=[] for g in ['/dev/ttyUSB*', '/dev/ttyACM*']: baselist += glob.glob(g) diff --git a/system-stuff/99-waveshare.conf b/system-stuff/99-waveshare-dlp4710.conf similarity index 76% rename from system-stuff/99-waveshare.conf rename to system-stuff/99-waveshare-dlp4710.conf index abbe72cf..91a67d83 100644 --- a/system-stuff/99-waveshare.conf +++ b/system-stuff/99-waveshare-dlp4710.conf @@ -3,7 +3,7 @@ Section "InputClass" MatchIsTouchscreen "on" MatchUSBID "0eef:0005" Driver "libinput" - Option "TransformationMatrix" "0.8 0 0 0 0.428571 0.571429 0 0 1" + Option "TransformationMatrix" "0.5333333 0 0 0 0.3571429 0.6428571 0 0 1" EndSection Section "Monitor" @@ -11,7 +11,7 @@ Section "Monitor" Identifier "DP-1" Modeline "1024x600_60.0" 49.00 1024 1029 1042 1312 600 602 605 622 -hsync -vsync Option "PreferredMode" "1024x600_60.0" - Option "Position" "0 800" + Option "Position" "0 1080" Option "DPMS" "false" Option "Primary" "true" EndSection @@ -19,8 +19,8 @@ EndSection Section "Monitor" # Projector Identifier "DP-2" - Modeline "1280x800_60.0" 83.50 1280 1352 1480 1680 800 810 816 831 +hsync +vsync - Option "PreferredMode" "1280x800_60.0" + Modeline "1920x1080_60.0" 148.50 1920 2008 2096 2200 1080 1084 1089 1125 -hsync -vsync + Option "PreferredMode" "1920x1080_60.0" Option "Position" "0 0" Option "DPMS" "false" Option "Primary" "false" @@ -33,7 +33,7 @@ Section "Screen" DefaultDepth 24 SubSection "Display" Depth 24 - Virtual 1280 1400 # ( max(1280,1024), (800+600) ) + Virtual 1920 1680 # ( max(1920,1024), (1080+600) ) EndSubSection EndSection diff --git a/system-stuff/99-waveshare-dlpc350.conf b/system-stuff/99-waveshare-dlpc350.conf new file mode 100644 index 00000000..91a67d83 --- /dev/null +++ b/system-stuff/99-waveshare-dlpc350.conf @@ -0,0 +1,48 @@ +Section "InputClass" + Identifier "WaveShare WS170120 configuration override" + MatchIsTouchscreen "on" + MatchUSBID "0eef:0005" + Driver "libinput" + Option "TransformationMatrix" "0.5333333 0 0 0 0.3571429 0.6428571 0 0 1" +EndSection + +Section "Monitor" + # Touchscreen + Identifier "DP-1" + Modeline "1024x600_60.0" 49.00 1024 1029 1042 1312 600 602 605 622 -hsync -vsync + Option "PreferredMode" "1024x600_60.0" + Option "Position" "0 1080" + Option "DPMS" "false" + Option "Primary" "true" +EndSection + +Section "Monitor" + # Projector + Identifier "DP-2" + Modeline "1920x1080_60.0" 148.50 1920 2008 2096 2200 1080 1084 1089 1125 -hsync -vsync + Option "PreferredMode" "1920x1080_60.0" + Option "Position" "0 0" + Option "DPMS" "false" + Option "Primary" "false" +EndSection + +Section "Screen" + Identifier "Screen0" + Device "Intel" + Monitor "DP-1" + DefaultDepth 24 + SubSection "Display" + Depth 24 + Virtual 1920 1680 # ( max(1920,1024), (1080+600) ) + EndSubSection +EndSection + +Section "Device" + Identifier "Intel" + Driver "intel" + BusID "PCI:0:2:0" + Option "Monitor-DP1" "DP-1" + Option "Monitor-DP2" "DP-2" + Option "ModeDebug" "true" +EndSection + diff --git a/system-stuff/dlp4710-reset-lumen-projector-port b/system-stuff/dlp4710-reset-lumen-projector-port new file mode 100755 index 00000000..c6b3dec8 --- /dev/null +++ b/system-stuff/dlp4710-reset-lumen-projector-port @@ -0,0 +1,4 @@ +#!/bin/bash + +stty -F /dev/lumen-projector -a 1>/dev/null 2>&1 +sleep 1 diff --git a/system-stuff/set-projector-power.service b/system-stuff/dlp4710-set-projector-power.service similarity index 82% rename from system-stuff/set-projector-power.service rename to system-stuff/dlp4710-set-projector-power.service index a5ecdcb4..9e0c8307 100644 --- a/system-stuff/set-projector-power.service +++ b/system-stuff/dlp4710-set-projector-power.service @@ -11,7 +11,7 @@ RequiresMountsFor=/usr Type=oneshot RemainAfterExit=yes User=root -ExecStart=/usr/bin/set-projector-power 0 +ExecStart=/usr/share/lightfield/libexec/reset-lumen-projector-port ExecStop=/usr/bin/set-projector-power 0 Restart=no diff --git a/system-stuff/dlpc350-set-projector-power.service b/system-stuff/dlpc350-set-projector-power.service new file mode 100644 index 00000000..9e0c8307 --- /dev/null +++ b/system-stuff/dlpc350-set-projector-power.service @@ -0,0 +1,19 @@ +# lightfield.service +# +# lightfield systemd unit file: +# Makes sure the projector is off on startup and shutdown. + +[Unit] +Description=Reset Lumen X projector +RequiresMountsFor=/usr + +[Service] +Type=oneshot +RemainAfterExit=yes +User=root +ExecStart=/usr/share/lightfield/libexec/reset-lumen-projector-port +ExecStop=/usr/bin/set-projector-power 0 +Restart=no + +[Install] +WantedBy=basic.target diff --git a/system-stuff/reset-lumen-projector-port b/system-stuff/reset-lumen-projector-port new file mode 100755 index 00000000..c6b3dec8 --- /dev/null +++ b/system-stuff/reset-lumen-projector-port @@ -0,0 +1,4 @@ +#!/bin/bash + +stty -F /dev/lumen-projector -a 1>/dev/null 2>&1 +sleep 1 diff --git a/text/defaultProfle.txt b/text/defaultProfle.txt new file mode 100644 index 00000000..e487f477 --- /dev/null +++ b/text/defaultProfle.txt @@ -0,0 +1,28 @@ +[ + { + "baseLayerCount": 1, + "baseLayersPumpingParameters": { + "layerExposureTime": 1000, + "layerThickness": 100, + "noPumpUpVelocity": 200, + "powerLevel": 10, + "pumpDownPause": 4000, + "pumpEveryNthLayer": 1, + "pumpUpDistance": 1, + "pumpUpPause": 2000, + "pumpUpTime": 600 + }, + "bodyLayersPumpingParameters": { + "layerExposureTime": 1000, + "layerThickness": 100, + "noPumpUpVelocity": 200, + "powerLevel": 10, + "pumpDownPause": 4000, + "pumpEveryNthLayer": 1, + "pumpUpDistance": 1, + "pumpUpPause": 2000, + "pumpUpTime": 600 + }, + "name": "default" + } +] diff --git a/text/text.qrc b/text/text.qrc index 3f577fe0..6774ce90 100644 --- a/text/text.qrc +++ b/text/text.qrc @@ -1,5 +1,7 @@ - + copyright-message.txt + text.qrc + defaultProfle.txt diff --git a/uninstall-lightfield.sh b/uninstall-lightfield.sh index e6d9734c..890c0b20 100755 --- a/uninstall-lightfield.sh +++ b/uninstall-lightfield.sh @@ -29,7 +29,7 @@ rm -f \ /home/lumen/.gnupg/trustdb.gpg \ /lib/systemd/system/clean-up-mount-points.service \ /lib/systemd/system/set-projector-power.service \ - /lib/udev/rules.d/90-dlpc350.rules \ + /lib/udev/rules.d/90-dlp4710.rules \ /usr/bin/lf \ /usr/bin/mountmon \ /usr/bin/set-projector-power \ diff --git a/unpack-kit-manually.sh b/unpack-kit-manually.sh index 6a87c893..99c9da12 100755 --- a/unpack-kit-manually.sh +++ b/unpack-kit-manually.sh @@ -1,7 +1,7 @@ #!/bin/bash -VERSION=1.0.10.0 -PACKAGE_BUILD_ROOT=/home/lumen/Volumetric/LightField/packaging +VERSION=1.0.11.0 +PACKAGE_BUILD_ROOT="${PWD}/packaging" ######################################################### ## ## diff --git a/usb-driver/Makefile b/usb-driver/Makefile new file mode 100644 index 00000000..672ac657 --- /dev/null +++ b/usb-driver/Makefile @@ -0,0 +1,36 @@ +BUILD = debug + +CXX = g++ +LD = g++ +RM = rm + +TARGET = set-projector-power +SOURCES = dlpc350_usb.cpp dlpc350_api.cpp main.cpp +OBJECTS = $(SOURCES:.cpp=.o) + +CFLAGS = -std=gnu++17 -Wall -Wextra -Werror -pedantic +LFLAGS = +ifeq ($(BUILD),debug) +CFLAGS += -D_DEBUG -g -Og +LFLAGS += -g +else ifeq ($(BUILD),release) +CFLAGS += -DNDEBUG -O3 +LFLAGS += -s +endif + +all: $(TARGET) + +%.o: %.cpp + $(CXX) $(CFLAGS) -c $< + +$(TARGET): $(OBJECTS) + $(LD) $(LFLAGS) -o $@ $^ -lhidapi-libusb + +clean: + -$(RM) $(TARGET) $(OBJECTS) + +## Dependencies + +dlpc350_usb.o: dlpc350_usb.cpp +dlpc350_api.o: dlpc350_api.cpp +main.o: main.cpp