diff --git a/.appveyor.yml b/.appveyor.yml index 65302bd..0bfd924 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,102 +1,104 @@ version: '{branch}-{build}' image: Visual Studio 2015 configuration: release platform: x86 init: - ps: >- $env:commit = $env:appveyor_repo_commit.SubString(0,7) Update-AppveyorBuild -Version ("{0}-{1}-{2}" -f $env:appveyor_repo_branch,$env:appveyor_build_number,$env:commit ) environment: VSVER: 14.0 CMAKE_INSTALL_ROOT: C:\projects\cmake matrix: - MSVC: 15 RUNTIME_LINKAGE: static QT_VERSION: 5.9 QT_LINKAGE: static ICU_VERSION: 57.1 ICU_LINKAGE: static COVERITY_BUILD_CANDIDATE: True QTDIR: C:\Qt\5.8\msvc2015 ATCORE_LIBS: Qt5SerialPort.dll install: - cmd: >- %QTDIR%\bin\qtenv2.bat qmake -v set QTDIR if %QTDIR:_64=%==%QTDIR% ( set ARCH=x86 ) else set ARCH=x64 if %QTDIR:msvc=%==%QTDIR% g++ --version if %QTDIR:msvc=%==%QTDIR% set make=mingw32-make.exe if %QTDIR:msvc=%==%QTDIR% %make% --version if not %QTDIR:msvc=%==%QTDIR% call "%ProgramFiles(x86)%\Microsoft Visual Studio %VSVER%\VC\vcvarsall.bat" %ARCH% if not %QTDIR:msvc=%==%QTDIR% set make=nmake.exe if not %QTDIR:msvc=%==%QTDIR% %make% /? > nul set QTBIN=%QTDIR%\bin build_script: - cmd: >- mkdir %CMAKE_INSTALL_ROOT% mkdir work cinst ninja cd work git clone -q git://anongit.kde.org/extra-cmake-modules.git cd extra-cmake-modules cmake -G "Ninja" . -DCMAKE_INSTALL_PREFIX=%CMAKE_INSTALL_ROOT% ninja install cd %APPVEYOR_BUILD_FOLDER% mkdir %APPVEYOR_BUILD_FOLDER%-build cd %APPVEYOR_BUILD_FOLDER%-build cmake %APPVEYOR_BUILD_FOLDER% -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_INSTALL_PREFIX=%CMAKE_INSTALL_ROOT% -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_INSTALL_PREFIX=%CMAKE_INSTALL_ROOT% -DBUILD_GUI=ON cmake --build . --target ALL_BUILD --config %CONFIGURATION% mkdir AtCore_Test_Client-%commit%-win32 mkdir AtCore_Test_Client-%commit%-win32\plugins move %APPVEYOR_BUILD_FOLDER%-build\bin\%CONFIGURATION%\AtCore.dll AtCore_Test_Client-%commit%-win32\ + move %APPVEYOR_BUILD_FOLDER%-build\bin\%CONFIGURATION%\AtCoreWidgets.dll AtCore_Test_Client-%commit%-win32\ + move %APPVEYOR_BUILD_FOLDER%-build\bin\%CONFIGURATION%\atcore-gui.exe AtCore_Test_Client-%commit%-win32\ move %APPVEYOR_BUILD_FOLDER%-build\bin\%CONFIGURATION%\* AtCore_Test_Client-%commit%-win32\plugins\ windeployqt --compiler-runtime AtCore_Test_Client-%commit%-win32/atcore-gui.exe for %%I in (%ATCORE_LIBS%) do copy %QTBIN%\%%I AtCore_Test_Client-%commit%-win32\ 7z a -tzip AtCore_Test_Client-win.zip AtCore_Test_Client-%commit%-win32 -r copy %APPVEYOR_BUILD_FOLDER%-build\AtCore_Test_Client-win.zip %APPVEYOR_BUILD_FOLDER%\AtCore_Test_Client-win.zip artifacts: - path: AtCore_Test_Client-win.zip name: AtCore deploy: - provider: GitHub tag: continuous description: continuous auth_token: secure: yG66EEKasiTmuCDPStbz0nVsvcETsQlnpDD2ScfNWUwT81kKfALCVFRTPMrp6R6E artifact: AtCore force_update: true diff --git a/CMakeLists.txt b/CMakeLists.txt index cfdff95..29295e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,119 +1,120 @@ project(AtCore) cmake_minimum_required(VERSION 3.8) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(ECM REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH}) include(CMakePackageConfigHelpers) include(ECMGenerateHeaders) include(ECMGeneratePriFile) include(ECMInstallIcons) include(ECMSetupVersion) include(FeatureSummary) include(GenerateExportHeader) include(KDECompilerSettings NO_POLICY_SCOPE) include(KDEInstallDirs) include(KDECMakeSettings) option(BUILD_GUI "Build the Test Gui") option(BUILD_DOCS "Build and Install Documents (Requires Doxygen)") option(BUILD_TESTS "Build and Run Unittests") +option(DEPLOY_PLUGINS_WITH_BINARY "Deploy Plugins to bin/plugins (Use for win/mac)") set_package_properties( ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra modules and scripts for CMake" URL "git://anongit.kde.org/extra-cmake-modules") set(PROJECT_VERSION "1.0.70") set(KF5_DEP_VERSION "5.24.0") # handled by release scripts set(REQUIRED_QT_VERSION 5.4.0) set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/AtCore") # Generate version check file. ecm_setup_version(${PROJECT_VERSION} VARIABLE_PREFIX ATCORE VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/atcore_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/AtCoreConfigVersion.cmake" SOVERSION ${PROJECT_VERSION_MAJOR} ) # Get the version from git if it's a git repository IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) FIND_PACKAGE(Git) IF(GIT_FOUND) EXECUTE_PROCESS( COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" OUTPUT_VARIABLE "GIT_VERSION" ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) MESSAGE( STATUS "Git Commit: ${GIT_VERSION}" ) add_definitions( -DGIT_REVISION="${GIT_VERSION}") ENDIF(GIT_FOUND) ENDIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) add_definitions(-DQT_NO_CAST_FROM_ASCII -DQT_NO_URL_CAST_FROM_STRING) find_package(Qt5 REQUIRED COMPONENTS Core SerialPort Charts Widgets ) include(ECMPoQmTools) if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ecm_install_po_files_as_qm(po) endif() # Set default build type to be release if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX OR CMAKE_COMPILER_IS_CLANG) # Turn warnings on by default set(CMAKE_CXX_FLAGS "-Wall -Wextra") # Set debug mode to use -g set(CMAKE_CXX_FLAGS_DEBUG "-g") # Use optimization set(CMAKE_CXX_FLAGS_RELEASE "-O3") endif() include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(CMAKE_AUTOMOC ON) add_subdirectory(src) #optional Parts. if(BUILD_GUI) add_subdirectory(testclient) endif() if (BUILD_TESTS) add_subdirectory(unittests) endif() if (BUILD_DOCS) add_subdirectory(doc) endif() install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AtCoreConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/atcore_version.h" DESTINATION "${INCLUDE_INSTALL_DIR}/AtCore/" COMPONENT Devel ) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/doc/build.md b/doc/build.md index c9fa714..101d610 100644 --- a/doc/build.md +++ b/doc/build.md @@ -1,92 +1,99 @@ # Building And Deploying %AtCore Building %AtCore is broken up into to main steps Configuration and Building. Deploying %AtCore is also covered here. ## Configuration In order to configure your build you will need [cmake] and [extra-cmake-modules]. %AtCore Build Options Are: - -DBUILD_GUI = ( ON | OFF ) Build the test client (Default is OFF) - -DBUILD_DOCS = (ON | OFF ) Build the Documentation (Default is OFF) - -DBUILD_TESTS = ( ON | OFF ) Build and Run Unittests (Default is OFF) - + - -DDEPLOY_PLUGINS_WITH_BINARY ( ON | OFF ) Deploy the plugins to bin/plugins (Default is OFF, Turn on for win/mac) + Recommended CMake Command Linux ``` cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL+LIBDIR=lib CMakeLists.txt ``` Mac OS/ Windows ``` -cmake CMakeLists.txt +cmake -DDEPLOY_PLUGINS_WITH_BINARY=ON CMakeLists.txt ``` ## Building After Configuring you Should be able to run make to build all targets. ``` make ``` ## Dependencies In addition to a working development enviroment for your system you will need the following to build %AtCore - qt5-base - qt5-serialport - qt5-widgets - qt5-charts Building The Documentation adds the following dependency: - [doxygen] ### Installing Dependencies on Windows and Mac OS #### Mac Os Mac Os users could use [homebrew] to install both cmake and cmake-extra-modules using. ``` brew update brew install cmake brew tap KDE-mac/kde; brew install kf5-extra-cmake-modules ``` Then can download and install [Qt] #### Windows Windows users could install [chocolatey] and do something like ``` choco install cmake choco install ninja git clone -q git://anongit.kde.org/extra-cmake-modules.git cd extra-cmake-modules cmake -G "Ninja" . -DCMAKE_INSTALL_PREFIX= ninja install ``` Then Download and install [Qt] ## Deploying %AtCore After you build you may wish to deploy atcore on your system for use ### Linux From the build dir the command below to install atcore with its plugins to the system (assuming cmake used above) ``` sudo make install ``` -### Windows/Mac OS -On these systems atcore will look in the path of the program using it for firmware plugins +### Finding Plugins +AtCore will look in a few places for plugins these are. + 1. BUILDDIR for plugins. + 2. KDE_PLUGIN_DIR/AtCore + 3. Qt's Plugin Path/AtCore + 4. INSTALL_PREFIX/KDE_PLUGIN_DIR/AtCore + 5. Binary using atcore's path/plugins (see Below) +For the last place bin/plugins atcore will look next to the binary using atcore. On Windows this is in a directory next to the program ``` C:\atcore_test_GUI\atcore-gui.exe C:\atcore_test_GUI\AtCore.dll C:\atcore_test_GUI\plugins\repetier.dll ``` On Mac OS this is in the app bundle ``` atcore-gui.app/Contents/MacOS/atcore-gui atcore-gui.app/Contents/MacOS/AtCore.dylib atcore-gui.app/Contents/MacOS/plugins/repetier.dylib ``` [Qt]:https://www.qt.io [doxygen]:http://www.stack.nl/~dimitri/doxygen/ [cmake]:https://cmake.org/ [extra-cmake-modules]:https://cgit.kde.org/extra-cmake-modules.git/tree [homebrew]:https://brew.sh/ [chocolatey]:https://chocolatey.org/ diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c2472a4..2e73a06 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,101 +1,101 @@ # # Create the Library. # configure_file( atcore_default_folders.h.in ${CMAKE_CURRENT_BINARY_DIR}/atcore_default_folders.h ) set(AtCoreLib_SRCS atcore.cpp seriallayer.cpp gcodecommands.cpp ifirmware.cpp temperature.cpp printthread.cpp ) add_library(AtCore SHARED ${AtCoreLib_SRCS}) target_link_libraries(AtCore Qt5::Core Qt5::SerialPort) # # # Configure the Library # # add_library(AtCore::AtCore ALIAS AtCore) target_include_directories(AtCore INTERFACE "$") set_target_properties(AtCore PROPERTIES VERSION ${ATCORE_VERSION_STRING} SOVERSION ${ATCORE_SOVERSION} EXPORT_NAME AtCore ) ecm_generate_headers(ATCORE_CamelCase_HEADERS HEADER_NAMES AtCore GCodeCommands IFirmware SerialLayer Temperature REQUIRED_HEADERS ATCORE_HEADERS ) ecm_create_qm_loader(AtCoreLib_SRCS atcore_qt) generate_export_header(AtCore BASE_NAME atcore) configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/AtCoreConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/AtCoreConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) # # # Install the Library # # install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AtCoreConfig.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/atcore_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/AtCore COMPONENT Devel ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/atcore_default_folders.h ${ATCORE_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR}/AtCore COMPONENT Devel ) install(FILES ${ATCORE_CamelCase_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR}/AtCore ) install( TARGETS AtCore EXPORT AtCoreTargets - ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} + ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) ecm_generate_pri_file( BASE_NAME AtCore LIB_NAME AtCore DEPS "Qt5Core Qt5SerialPort" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/AtCore ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/core/atcore.cpp b/src/core/atcore.cpp index fe4ea2c..9bcd99f 100644 --- a/src/core/atcore.cpp +++ b/src/core/atcore.cpp @@ -1,778 +1,772 @@ /* AtCore Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello Patrick José Pereira Lays Rodrigues This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include #include #include #include #include #include #include "atcore.h" #include "atcore_version.h" #include "seriallayer.h" #include "gcodecommands.h" #include "printthread.h" #include "atcore_default_folders.h" Q_LOGGING_CATEGORY(ATCORE_PLUGIN, "org.kde.atelier.core.plugin") Q_LOGGING_CATEGORY(ATCORE_CORE, "org.kde.atelier.core") /** * @brief The AtCorePrivate struct * Provides a private data set for atcore. */ struct AtCorePrivate { IFirmware *firmwarePlugin = nullptr;//!< @param firmwarePlugin: pointer to firmware plugin SerialLayer *serial = nullptr; //!< @param serial: pointer to the serial layer QPluginLoader pluginLoader; //!< @param pluginLoader: QPluginLoader QDir pluginsDir; //!< @param pluginsDir: Directory where plugins were found QMap plugins; //!< @param plugins: Map of plugins name / path QByteArray lastMessage; //!< @param lastMessage: lastMessage from the printer int extruderCount = 1; //!< @param extruderCount: extruder count Temperature temperature; //!< @param temperature: Temperature object QStringList commandQueue; //!< @param commandQueue: the list of commands to send to the printer bool ready = false; //!< @param ready: True if printer is ready for a command QTimer *tempTimer = nullptr; //!< @param tempTimer: timer connected to the checkTemperature function float percentage; //!< @param percentage: print job percent QByteArray posString; //!< @param posString: stored string from last M114 return AtCore::STATES printerState; //!< @param printerState: State of the Printer QStringList serialPorts; //!< @param seralPorts: Detected serial Ports QTimer *serialTimer = nullptr; //!< @param serialTimer: Timer connected to locateSerialPorts bool sdCardMounted = false; //!< @param sdCardMounted: True if Sd Card is mounted. bool sdCardReadingFileList = false; //!< @param sdCardReadingFileList: True while getting file names from sd card bool sdCardPrinting = false; //!< @param sdCardPrinting: True if currently printing from sd card. QString sdCardFileName; //!< @param sdCardFileName: name of file being used from sd card. QStringList sdCardFileList; //!< @param sdCardFileList: List of files on sd card. }; AtCore::AtCore(QObject *parent) : QObject(parent), d(new AtCorePrivate) { //Register MetaTypes qRegisterMetaType("AtCore::STATES"); setState(AtCore::DISCONNECTED); //Create and start the timer that checks for temperature. d->tempTimer = new QTimer(this); d->tempTimer->setInterval(5000); d->tempTimer->setSingleShot(false); //Attempt to find our plugins - //For Windows and Mac we always look in plugins folder of the program using atcore. - //On others we use AtCoreDirectories::pluginDir to hold a list of dirs to check -#if defined(Q_OS_WIN) || defined(Q_OS_MAC) - d->pluginsDir = qApp->applicationDirPath() + QStringLiteral("/plugins"); -#else for (const auto &path : AtCoreDirectories::pluginDir) { qCDebug(ATCORE_PLUGIN) << "Lookin for plugins in " << path; if (QDir(path).exists()) { d->pluginsDir = QDir(path); qCDebug(ATCORE_PLUGIN) << "Valid path for plugins found !"; break; } } -#endif if (!d->pluginsDir.exists()) { qCritical() << "No valid path for plugin !"; } qCDebug(ATCORE_PLUGIN) << d->pluginsDir; findFirmwarePlugins(); setState(AtCore::DISCONNECTED); } QString AtCore::version() const { QString versionString = QString::fromLatin1(ATCORE_VERSION_STRING); #if defined GIT_REVISION if (!QStringLiteral(GIT_REVISION).isEmpty()) { versionString.append(QString::fromLatin1("-%1").arg(QStringLiteral(GIT_REVISION))); } #endif return versionString; } SerialLayer *AtCore::serial() const { return d->serial; } IFirmware *AtCore::firmwarePlugin() const { return d->firmwarePlugin; } void AtCore::close() { exit(0); } Temperature &AtCore::temperature() const { return d->temperature; } void AtCore::findFirmware(const QByteArray &message) { if (state() == AtCore::DISCONNECTED) { qWarning() << "Cant find firwmware, serial not connected !"; return; } if (state() == AtCore::CONNECTING) { //Most Firmwares will return "start" on connect, some return their firmware name. if (message.contains("start")) { qCDebug(ATCORE_CORE) << "Waiting requestFirmware."; QTimer::singleShot(500, this, &AtCore::requestFirmware); return; } else if (message.contains("Grbl")) { loadFirmwarePlugin(QString::fromLatin1("grbl")); return; } else if (message.contains("Smoothie")) { loadFirmwarePlugin(QString::fromLatin1("smoothie")); return; } qCDebug(ATCORE_CORE) << "Waiting for printer..."; } qCDebug(ATCORE_CORE) << "Find Firmware Called" << message; if (!message.contains("FIRMWARE_NAME:")) { qCDebug(ATCORE_CORE) << "No firmware yet."; return; } qCDebug(ATCORE_CORE) << "Found firmware string, Looking for Firmware Name."; QString fwName = QString::fromLocal8Bit(message); fwName = fwName.split(QChar::fromLatin1(':')).at(1); if (fwName.indexOf(QChar::fromLatin1(' ')) == 0) { //remove leading space fwName.remove(0, 1); } if (fwName.contains(QChar::fromLatin1(' '))) { //check there is a space or dont' resize fwName.resize(fwName.indexOf(QChar::fromLatin1(' '))); } fwName = fwName.toLower().simplified(); if (fwName.contains(QChar::fromLatin1('_'))) { fwName.resize(fwName.indexOf(QChar::fromLatin1('_'))); } qCDebug(ATCORE_CORE) << "Firmware Name:" << fwName; if (message.contains("EXTRUDER_COUNT:")) { //this code is broken if more then 9 extruders are detected. since only one char is returned d->extruderCount = message.at(message.indexOf("EXTRUDER_COUNT:") + 15) - '0'; } qCDebug(ATCORE_CORE) << "Extruder Count:" << QString::number(extruderCount()); loadFirmwarePlugin(fwName); } void AtCore::loadFirmwarePlugin(const QString &fwName) { qCDebug(ATCORE_PLUGIN) << "Looking for Plugin:" << fwName; if (d->plugins.contains(fwName)) { d->pluginLoader.setFileName(d->plugins[fwName]); if (!d->pluginLoader.load()) { //Plugin was not loaded, Provide some debug info. qCDebug(ATCORE_PLUGIN) << "Plugin Loading: Failed."; qCDebug(ATCORE_PLUGIN) << d->pluginLoader.errorString(); setState(AtCore::CONNECTING); } else { //Plugin was loaded successfully. d->firmwarePlugin = qobject_cast(d->pluginLoader.instance()); firmwarePlugin()->init(this); qCDebug(ATCORE_PLUGIN) << "Plugin Loading: Successful"; disconnect(serial(), &SerialLayer::receivedCommand, this, &AtCore::findFirmware); connect(serial(), &SerialLayer::receivedCommand, this, &AtCore::newMessage); connect(firmwarePlugin(), &IFirmware::readyForCommand, this, &AtCore::processQueue); d->ready = true; // ready on new firmware load if (firmwarePlugin()->name() != QStringLiteral("Grbl")) { connect(d->tempTimer, &QTimer::timeout, this, &AtCore::checkTemperature); d->tempTimer->start(); } setState(IDLE); } } else { qCDebug(ATCORE_CORE) << "Plugin:" << fwName << ": Not found."; } } bool AtCore::initSerial(const QString &port, int baud) { d->serial = new SerialLayer(port, baud); if (serialInitialized() && d->serial->isWritable()) { setState(AtCore::CONNECTING); connect(serial(), &SerialLayer::receivedCommand, this, &AtCore::findFirmware); return true; } else { qCDebug(ATCORE_CORE) << "Failed to open device for Read / Write."; return false; } } bool AtCore::serialInitialized() const { if (!d->serial) { return false; } return d->serial->isOpen(); } QString AtCore::connectedPort() const { return serial()->portName(); } QStringList AtCore::serialPorts() const { QStringList ports; QList serialPortInfoList = QSerialPortInfo::availablePorts(); if (!serialPortInfoList.isEmpty()) { foreach (const QSerialPortInfo &serialPortInfo, serialPortInfoList) { #ifdef Q_OS_MAC //Mac OS has callout serial ports starting with cu these devices are read only. //It is necessary to filter them out to help prevent user error. if (!serialPortInfo.portName().startsWith(QStringLiteral("cu."), Qt::CaseInsensitive)) { ports.append(serialPortInfo.portName()); } #else ports.append(serialPortInfo.portName()); #endif } } return ports; } void AtCore::locateSerialPort() { QStringList ports = serialPorts(); if (d->serialPorts != ports) { d->serialPorts = ports; emit portsChanged(d->serialPorts); } } quint16 AtCore::serialTimerInterval() const { if (d->serialTimer != nullptr) { return d->serialTimer->interval(); } return 0; } void AtCore::setSerialTimerInterval(const quint16 &newTime) { if (!d->serialTimer) { //There is no timer. We need to create one. d->serialTimer = new QTimer(); connect(d->serialTimer, &QTimer::timeout, this, &AtCore::locateSerialPort); } //Start over with the new time. d->serialTimer->start(newTime); } void AtCore::newMessage(const QByteArray &message) { //Evaluate the messages coming from the printer. d->lastMessage = message; //Check if the message has current coordinates. if (message.startsWith(QString::fromLatin1("X:").toLocal8Bit())) { d->posString = message; d->posString.resize(d->posString.indexOf('E')); d->posString.replace(':', ""); } //Check if have temperature info and decode it if (d->lastMessage.contains("T:") || d->lastMessage.contains("B:")) { temperature().decodeTemp(message); } emit(receivedMessage(d->lastMessage)); } void AtCore::setRelativePosition() { pushCommand(GCode::toCommand(GCode::G91)); } void AtCore::setAbsolutePosition() { pushCommand(GCode::toCommand(GCode::G90)); } float AtCore::percentagePrinted() const { return d->percentage; } void AtCore::print(const QString &fileName, bool sdPrint) { if (state() == AtCore::CONNECTING) { qCDebug(ATCORE_CORE) << "Load a firmware plugin to print."; return; } //Start a print job. setState(AtCore::STARTPRINT); if (sdPrint) { //Printing from the sd card requires us to send some M commands. pushCommand(GCode::toCommand(GCode::M23, fileName)); d->sdCardFileName = fileName; pushCommand(GCode::toCommand(GCode::M24)); setState(AtCore::BUSY); d->sdCardPrinting = true; connect(d->tempTimer, &QTimer::timeout, this, &AtCore::sdCardPrintStatus); return; } //Process the gcode with a printThread. //The Thread processes the gcode without freezing the libary. //Only sends a command back when the printer is ready, avoiding buffer overflow in the printer. QThread *thread = new QThread(); PrintThread *printThread = new PrintThread(this, fileName); printThread->moveToThread(thread); connect(printThread, &PrintThread::printProgressChanged, this, &AtCore::printProgressChanged, Qt::QueuedConnection); connect(thread, &QThread::started, printThread, &PrintThread::start); connect(printThread, &PrintThread::finished, thread, &QThread::quit); connect(thread, &QThread::finished, printThread, &PrintThread::deleteLater); if (!thread->isRunning()) { thread->start(); } } void AtCore::pushCommand(const QString &comm) { //Append command to the commandQueue d->commandQueue.append(comm); if (d->ready) { //The printer is ready for a command now so push one. processQueue(); } } void AtCore::closeConnection() { if (serialInitialized()) { if (AtCore::state() == AtCore::BUSY && !d->sdCardPrinting) { //We have to clean up the print job if printing from the host. //However disconnecting while printing from sd card should not affect the print job. setState(AtCore::STOP); } if (firmwarePluginLoaded()) { disconnect(firmwarePlugin(), &IFirmware::readyForCommand, this, &AtCore::processQueue); disconnect(serial(), &SerialLayer::receivedCommand, this, &AtCore::newMessage); if (firmwarePlugin()->name() != QStringLiteral("Grbl")) { disconnect(d->tempTimer, &QTimer::timeout, this, &AtCore::checkTemperature); d->tempTimer->stop(); } //Attempt to unload the firmware plugin. QString name = firmwarePlugin()->name(); QString msg = d->pluginLoader.unload() ? QStringLiteral("success") : QStringLiteral("FAIL"); qCDebug(ATCORE_PLUGIN) << QStringLiteral("Firmware plugin %1 unload: %2").arg(name, msg); } serial()->close(); //Clear our copy of the sdcard filelist clearSdCardFileList(); setState(AtCore::DISCONNECTED); } } AtCore::STATES AtCore::state(void) { return d->printerState; } void AtCore::setState(AtCore::STATES state) { if (state != d->printerState) { qCDebug(ATCORE_CORE) << "Atcore state changed from [" \ << d->printerState << "] to [" << state << "]"; d->printerState = state; if (state == AtCore::FINISHEDPRINT && d->sdCardPrinting) { //Clean up the sd card print d->sdCardPrinting = false; disconnect(d->tempTimer, &QTimer::timeout, this, &AtCore::sdCardPrintStatus); } emit(stateChanged(d->printerState)); } } void AtCore::stop() { //Stop a print job setState(AtCore::STOP); d->commandQueue.clear(); if (d->sdCardPrinting) { stopSdPrint(); } setExtruderTemp(0, 0); setBedTemp(0); home(AtCore::X); } void AtCore::emergencyStop() { //Emergency Stop. Stops the machine //Clear the queue, and any print job //Before sending the command to ensure //Less chance of movement after the restart. d->commandQueue.clear(); if (AtCore::state() == AtCore::BUSY) { if (!d->sdCardPrinting) { //Stop our running print thread setState(AtCore::STOP); } } //push command through serial to bypass atcore's queue. serial()->pushCommand(GCode::toCommand(GCode::M112).toLocal8Bit()); } void AtCore::stopSdPrint() { //Stop an SdCard Print. pushCommand(GCode::toCommand(GCode::M25)); d->sdCardFileName = QString(); pushCommand(GCode::toCommand(GCode::M23, d->sdCardFileName)); AtCore::setState(AtCore::FINISHEDPRINT); AtCore::setState(AtCore::IDLE); } void AtCore::requestFirmware() { if (serialInitialized()) { qCDebug(ATCORE_CORE) << "Sending " << GCode::description(GCode::M115); serial()->pushCommand(GCode::toCommand(GCode::M115).toLocal8Bit()); } else { qCDebug(ATCORE_CORE) << "There is no open device to send commands"; } } bool AtCore::firmwarePluginLoaded() const { if (firmwarePlugin()) { return true; } else { return false; } } void AtCore::findFirmwarePlugins() { d->plugins.clear(); qCDebug(ATCORE_PLUGIN) << "plugin dir:" << d->pluginsDir; QStringList files = d->pluginsDir.entryList(QDir::Files); foreach (const QString &f, files) { QString file = f; #if defined(Q_OS_WIN) if (file.endsWith(QStringLiteral(".dll"))) #elif defined(Q_OS_MAC) if (file.endsWith(QStringLiteral(".dylib"))) #else if (file.endsWith(QStringLiteral(".so"))) #endif file = file.split(QChar::fromLatin1('.')).at(0); else { qCDebug(ATCORE_PLUGIN) << "File" << file << "not plugin."; continue; } qCDebug(ATCORE_CORE) << "Found plugin file" << f; if (file.startsWith(QStringLiteral("lib"))) { file = file.remove(QStringLiteral("lib")); } file = file.toLower().simplified(); QString pluginString; pluginString.append(d->pluginsDir.path()); pluginString.append(QChar::fromLatin1('/')); pluginString.append(f); d->plugins[file] = pluginString; qCDebug(ATCORE_CORE) << tr("plugins[%1]=%2").arg(file, pluginString); } } QStringList AtCore::availableFirmwarePlugins() const { return d->plugins.keys(); } void AtCore::pause(const QString &pauseActions) { if (d->sdCardPrinting) { pushCommand(GCode::toCommand(GCode::M25)); } //Push the command to request current coordinates. //This will be read by AtCore::newMessage and stored for use on resume. pushCommand(GCode::toCommand(GCode::M114)); if (!pauseActions.isEmpty()) { QStringList temp = pauseActions.split(QChar::fromLatin1(',')); for (int i = 0; i < temp.length(); i++) { pushCommand(temp.at(i)); } } setState(AtCore::PAUSE); } void AtCore::resume() { if (d->sdCardPrinting) { pushCommand(GCode::toCommand(GCode::M24)); } else { //Move back to previous coordinates. pushCommand(GCode::toCommand(GCode::G0, QString::fromLatin1(d->posString))); } setState(AtCore::BUSY); } /*~~~~~Control Slots ~~~~~~~~*/ void AtCore::home() { pushCommand(GCode::toCommand(GCode::G28)); } void AtCore::home(uchar axis) { QString args; if (axis & AtCore::X) { args.append(QStringLiteral("X0 ")); } if (axis & AtCore::Y) { args.append(QStringLiteral("Y0 ")); } if (axis & AtCore::Z) { args.append(QStringLiteral("Z0")); } pushCommand(GCode::toCommand(GCode::G28, args)); } void AtCore::setExtruderTemp(uint temp, uint extruder, bool andWait) { if (andWait) { pushCommand(GCode::toCommand(GCode::M109, QString::number(temp), QString::number(extruder))); } else { pushCommand(GCode::toCommand(GCode::M104, QString::number(extruder), QString::number(temp))); } } void AtCore::setBedTemp(uint temp, bool andWait) { if (andWait) { pushCommand(GCode::toCommand(GCode::M190, QString::number(temp))); } else { pushCommand(GCode::toCommand(GCode::M140, QString::number(temp))); } } void AtCore::setFanSpeed(uint speed, uint fanNumber) { pushCommand(GCode::toCommand(GCode::M106, QString::number(fanNumber), QString::number(speed))); } void AtCore::setPrinterSpeed(uint speed) { pushCommand(GCode::toCommand(GCode::M220, QString::number(speed))); } void AtCore::setFlowRate(uint speed) { pushCommand(GCode::toCommand(GCode::M221, QString::number(speed))); } void AtCore::move(AtCore::AXES axis, int arg) { static QLatin1Char a('?'); switch (axis) { case AtCore::X: a = QLatin1Char('X'); break; case AtCore::Y: a = QLatin1Char('Y'); break; case AtCore::Z: a = QLatin1Char('Z'); break; case AtCore::E: a = QLatin1Char('E'); break; default: break; }; move(a, arg); } void AtCore::move(QLatin1Char axis, int arg) { pushCommand(GCode::toCommand(GCode::G1, QStringLiteral("%1 %2").arg(axis).arg(QString::number(arg)))); } int AtCore::extruderCount() const { return d->extruderCount; } void AtCore::processQueue() { d->ready = true; if (d->commandQueue.isEmpty()) { return; } if (!serialInitialized()) { qCDebug(ATCORE_PLUGIN) << "Can't process queue ! Serial not initialized."; return; } QString text = d->commandQueue.takeAt(0); if (firmwarePluginLoaded()) { serial()->pushCommand(firmwarePlugin()->translate(text)); } else { serial()->pushCommand(text.toLocal8Bit()); } d->ready = false; } void AtCore::checkTemperature() { //One request for the temperature in the queue at a time. if (d->commandQueue.contains(GCode::toCommand(GCode::M105))) { return; } pushCommand(GCode::toCommand(GCode::M105)); } void AtCore::showMessage(const QString &message) { if (!message.isEmpty()) { pushCommand(GCode::toCommand((GCode::M117), message)); } } void AtCore::setUnits(AtCore::UNITS units) { switch (units) { case AtCore::METRIC: pushCommand(GCode::toCommand(GCode::G21)); break; case AtCore::IMPERIAL: pushCommand(GCode::toCommand(GCode::G20)); break; } } QStringList AtCore::portSpeeds() const { return serial()->validBaudRates(); } void AtCore::disableMotors(uint delay) { //Disables motors if (delay) { pushCommand(GCode::toCommand(GCode::M84, QString::number(delay))); } else { pushCommand(GCode::toCommand(GCode::M84)); } } //Most firmwares will not report if an sdcard is mounted on boot. bool AtCore::isSdMounted() const { return d->sdCardMounted; } void AtCore::setSdMounted(bool mounted) { if (mounted != isSdMounted()) { d->sdCardMounted = mounted; emit(sdMountChanged(d->sdCardMounted)); } } void AtCore::getSDFileList() { pushCommand(GCode::toCommand(GCode::M20)); } QStringList AtCore::sdFileList() { if (!d->sdCardReadingFileList) { getSDFileList(); } return d->sdCardFileList; } void AtCore::appendSdCardFileList(const QString &fileName) { d->sdCardFileList.append(fileName); emit(sdCardFileListChanged(d->sdCardFileList)); } void AtCore::clearSdCardFileList() { d->sdCardFileList.clear(); emit(sdCardFileListChanged(d->sdCardFileList)); } void AtCore::sdDelete(const QString &fileName) { if (d->sdCardFileList.contains(fileName)) { pushCommand(GCode::toCommand(GCode::M30, fileName)); getSDFileList(); } else { qCDebug(ATCORE_CORE) << "Delete failed file not found:" << fileName; } } void AtCore::mountSd(uint slot) { pushCommand(GCode::toCommand(GCode::M21, QString::number(slot))); } void AtCore::umountSd(uint slot) { pushCommand(GCode::toCommand(GCode::M22, QString::number(slot))); } bool AtCore::isReadingSdCardList() const { return d->sdCardReadingFileList; } void AtCore::setReadingSdCardList(bool readingList) { d->sdCardReadingFileList = readingList; } void AtCore::sdCardPrintStatus() { //One request for the Sd Job status in the queue at a time. if (d->commandQueue.contains(GCode::toCommand(GCode::M27))) { return; } pushCommand(GCode::toCommand(GCode::M27)); } diff --git a/src/core/atcore_default_folders.h.in b/src/core/atcore_default_folders.h.in index eac2a88..ffe9d6b 100644 --- a/src/core/atcore_default_folders.h.in +++ b/src/core/atcore_default_folders.h.in @@ -1,31 +1,32 @@ /* AtCore KDE Libary for 3D Printers Copyright (C) <2016> Authors: Tomaz Canabrava Chris Rizzitello Patrick José Pereira This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma once #include namespace AtCoreDirectories { const QStringList pluginDir = \ - QStringList(QStringLiteral("@CMAKE_CURRENT_BINARY_DIR@/plugins")) \ + QStringList(QStringLiteral("@CMAKE_CURRENT_BINARY_DIR@/../plugins")) \ << QStringList(QStringLiteral("@KDE_INSTALL_PLUGINDIR@/AtCore")) \ << QStringList(QLibraryInfo::location(QLibraryInfo::PluginsPath) + QStringLiteral("/AtCore")) \ + << QStringList(QStringLiteral("@CMAKE_INSTALL_PREFIX@/@KDE_INSTALL_PLUGINDIR@/AtCore")) \ << QStringList(QStringLiteral("plugins")); -}; +} diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index ea215bf..ca38c93 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -1,58 +1,57 @@ set(RepetierPlugin_SRCS repetierplugin.cpp) add_library(repetier SHARED ${RepetierPlugin_SRCS}) target_link_libraries(repetier Qt5::Core AtCore::AtCore) set(GrblPlugin_SRCS grblplugin.cpp) add_library(grbl SHARED ${GrblPlugin_SRCS}) target_link_libraries(grbl Qt5::Core AtCore::AtCore) set(TeacupPlugin_SRCS teacupplugin.cpp) add_library(teacup SHARED ${TeacupPlugin_SRCS}) target_link_libraries(teacup Qt5::Core AtCore::AtCore) set(MarlinPlugin_SRCS marlinplugin.cpp) add_library(marlin SHARED ${MarlinPlugin_SRCS}) target_link_libraries(marlin Qt5::Core AtCore::AtCore) set(SprinterPlugin_SRCS sprinterplugin.cpp) add_library(sprinter SHARED ${SprinterPlugin_SRCS}) target_link_libraries(sprinter Qt5::Core AtCore::AtCore) set(AprinterPlugin_SRCS aprinterplugin.cpp) add_library(aprinter SHARED ${AprinterPlugin_SRCS}) target_link_libraries(aprinter Qt5::Core AtCore::AtCore) set(SmoothiePlugin_SRCS smoothieplugin.cpp) add_library(smoothie SHARED ${SmoothiePlugin_SRCS}) target_link_libraries(smoothie Qt5::Core AtCore::AtCore) -if(WIN32 OR APPLE) +if(DEPLOY_PLUGINS_WITH_BINARY) install( TARGETS repetier grbl teacup marlin sprinter aprinter smoothie DESTINATION bin/plugins ) -endif() -if(UNIX AND NOT APPLE) +else (NOT DEPLOY_PLUGINS_WITH_BINARY) install( TARGETS repetier grbl teacup marlin sprinter aprinter smoothie DESTINATION ${KDE_INSTALL_PLUGINDIR}/AtCore ) endif() diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index 6c6b1ce..c33bc47 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -1,86 +1,86 @@ set(widgetsLIB_SRCS about.cpp axiscontrol.cpp commandwidget.cpp logwidget.cpp movementwidget.cpp plotwidget.cpp printwidget.cpp sdwidget.cpp statuswidget.cpp temperaturewidget.cpp ) add_library(AtCoreWidgets ${widgetsLIB_SRCS}) target_link_libraries(AtCoreWidgets AtCore::AtCore Qt5::Core Qt5::Widgets Qt5::Charts) set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/AtCore") configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/AtCoreWidgetsConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/AtCoreWidgetsConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AtCoreWidgetsConfig.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) generate_export_header(AtCoreWidgets BASE_NAME atcorewidgets) add_library(AtCore::AtCoreWidgets ALIAS AtCoreWidgets) target_include_directories(AtCoreWidgets INTERFACE "$") set_target_properties(AtCoreWidgets PROPERTIES VERSION ${ATCORE_VERSION_STRING} SOVERSION ${ATCORE_SOVERSION} EXPORT_NAME AtCoreWidgets ) ecm_generate_headers(ATCOREWIDGETS_CamelCase_HEADERS HEADER_NAMES About AxisControl CommandWidget LogWidget MovementWidget PlotWidget PrintWidget SdWidget StatusWidget TemperatureWidget REQUIRED_HEADERS ATCOREWIDGETS_HEADERS ) ecm_create_qm_loader(widgetsLib_SRCS atcore_qt) install(FILES ${ATCOREWIDGETS_CamelCase_HEADERS} ${ATCOREWIDGETS_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR}/AtCore ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/atcorewidgets_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/AtCore COMPONENT Devel ) install( TARGETS AtCoreWidgets EXPORT AtCoreTargets - ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} + ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) ecm_generate_pri_file( BASE_NAME AtCoreWidgets LIB_NAME AtCoreWidgets DEPS "Qt5Core Qt5Widgets Qt5Charts" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/AtCore ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/widgets/about.cpp b/src/widgets/about.cpp index 7226ef1..0620429 100644 --- a/src/widgets/about.cpp +++ b/src/widgets/about.cpp @@ -1,72 +1,72 @@ /* AtCore Test Client Copyright (C) <2017> Authors: Chris Rizzitello This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include "about.h" About::About(QWidget *parent) : QDialog(parent) { setWindowTitle(QStringLiteral("About Atcore")); setWindowIcon(QIcon::fromTheme(QStringLiteral("help-about"), style()->standardIcon(QStyle::SP_MessageBoxInformation))); QLabel *lbl_version = new QLabel(QString::fromLatin1("Version: %1").arg(QCoreApplication::applicationVersion())); QLabel *lbl_qt_version = new QLabel(QString::fromLatin1("Using Qt: %1").arg(QString::fromLatin1(qVersion()))); QLabel *lbl_authors = new QLabel(QStringLiteral("Authors:\n" - " Chris Rizzitello \n" - " Patrick José Pereira \n" - " Lays Rodrigues \n" - " Tomaz Canabrava " - "")); + " Chris Rizzitello \n" + " Patrick José Pereira \n" + " Lays Rodrigues \n" + " Tomaz Canabrava " + "")); QLabel *lbl_icon = new QLabel(); lbl_icon->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); lbl_icon->setScaledContents(true); lbl_icon->setPixmap(QPixmap(QStringLiteral(":/icon/atcore"))); QPushButton *btn_close = new QPushButton(QStringLiteral("&Close")); connect(btn_close, &QPushButton::clicked, this, &QDialog::close); QVBoxLayout *versionInfo = new QVBoxLayout; versionInfo->addWidget(lbl_version); versionInfo->addWidget(lbl_qt_version); QVBoxLayout *topLayout = new QVBoxLayout; topLayout->setContentsMargins(0, 0, 0, 0); topLayout->addWidget(lbl_icon); topLayout->addItem(versionInfo); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addItem(topLayout); mainLayout->addWidget(lbl_authors); mainLayout->addWidget(btn_close); setLayout(mainLayout); } About::~About() { } diff --git a/src/widgets/axiscontrol.cpp b/src/widgets/axiscontrol.cpp index 1ed202d..de7e404 100644 --- a/src/widgets/axiscontrol.cpp +++ b/src/widgets/axiscontrol.cpp @@ -1,217 +1,217 @@ /* Atelier KDE Printer Host for 3D Printing Copyright (C) <2016> Author: Lays Rodrigues - lays.rodrigues@kde.org Chris Rizzitello - rizzitello@kde.org This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "axiscontrol.h" #include -PieButton::PieButton(QLatin1Char& axis, int value, int size, int angle) : _axis(axis), _value(value) +PieButton::PieButton(QLatin1Char &axis, int value, int size, int angle) : _axis(axis), _value(value) { const int delta = 16; // Qt Docs: angle is 16th of a degree. setBrush(_palette.button()); setStartAngle(angle * delta); setSpanAngle(90 * delta); setRect(QRect(QPoint(size * -1, size * -1), QPoint(size, size))); setZValue(size * -1); setAcceptHoverEvents(true); setToolTip(QStringLiteral("Move the hotend to the %1 by %2 units").arg(axis).arg(value)); } void PieButton::setPalette(QPalette palette) { _palette = palette; } void PieButton::mousePressEvent(QGraphicsSceneMouseEvent *) { emit clicked(_axis, _value); } void PieButton::hoverEnterEvent(QGraphicsSceneHoverEvent *) { setBrush(_palette.highlight()); } void PieButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *) { setBrush(_palette.button()); } -RectButton::RectButton(QLatin1Char& axis, int value, int size) : _axis(axis), _value(value) +RectButton::RectButton(QLatin1Char &axis, int value, int size) : _axis(axis), _value(value) { setBrush(_palette.button()); setRect(QRect(QPoint(0, 0), QPoint(size, size))); setAcceptHoverEvents(true); setZValue(size * -1); if (axis != QLatin1Char('E')) { setToolTip(QStringLiteral("Move the hotend to the %1 by %2 units").arg(axis).arg(value)); } else { setToolTip(QStringLiteral("Extrude %1 Units").arg(value)); } } void RectButton::setPalette(QPalette palette) { _palette = palette; } void RectButton::mousePressEvent(QGraphicsSceneMouseEvent *) { emit clicked(_axis, _value); } void RectButton::hoverEnterEvent(QGraphicsSceneHoverEvent *) { setBrush(_palette.highlight()); } void RectButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *) { setBrush(_palette.button()); } /* About the Magic Numbers I don't have experience programming with QGraphicsScene, Tomaz is helping me, but until we have a better solution, all the values that are dividing or multiplying the items is based only in tests and errors. Those values was chosen because it fit better on the alignment of the items in the scene. If you have a better solution, please share with us. Lays Rodrigues - Jan/2017 */ -AxisControl::AxisControl(const QList &movementValues, QWidget* parent) : +AxisControl::AxisControl(const QList &movementValues, QWidget *parent) : QGraphicsView(parent) { setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); setScene(new QGraphicsScene()); const int listSize = movementValues.size(); int maxValue = *std::max_element(movementValues.begin(), movementValues.end()); QList lessList = movementValues; std::sort(lessList.begin(), lessList.end(), std::less()); QList greaterList = movementValues; std::sort(greaterList.begin(), greaterList.end(), std::greater()); - auto createPie = [ this, maxValue ](QLatin1Char& axis, int value, int size, int angle) { + auto createPie = [ this, maxValue ](QLatin1Char & axis, int value, int size, int angle) { auto pie = new PieButton(axis, value, size, angle); pie->setPalette(this->palette()); connect(pie, &PieButton::clicked, this, &AxisControl::clicked); if (abs(value) == maxValue) { setLabels(pie, axis, value); } scene()->addItem(pie); }; - auto createRect = [ this, maxValue ](QLatin1Char& axis, int value, int size, int xPos, int yPos) { + auto createRect = [ this, maxValue ](QLatin1Char & axis, int value, int size, int xPos, int yPos) { auto z = new RectButton(axis, value, size); z->setPalette(this->palette()); z->setPos(xPos, yPos); connect(z, &RectButton::clicked, this, &AxisControl::clicked); if (abs(value) == maxValue) { setLabels(z, axis, value); } scene()->addItem(z); }; int currPieSize = 25; auto xchar = QLatin1Char('X'); auto ychar = QLatin1Char('Y'); auto zchar = QLatin1Char('Z'); auto echar = QLatin1Char('E'); - for(const int &value: lessList) { + for (const int &value : lessList) { createPie(xchar, value, currPieSize, -45); // Left createPie(xchar, value * -1, currPieSize, 135); // Right createPie(ychar, value, currPieSize, 45); // Top createPie(ychar, value * -1, currPieSize, 225); // Bottom currPieSize += 25; } int currSize = 25; int xPos = sceneRect().width() - 50; int yPos = -(listSize * 25); //Align with the origin // Z+ - for(const int &value: greaterList) { + for (const int &value : greaterList) { createRect(zchar, value, currSize, xPos, yPos); yPos += currSize; } // Z- - for(const int &value: lessList){ + for (const int &value : lessList) { createRect(zchar, -value, currSize, xPos, yPos); yPos += currSize; } currSize = 25; xPos = sceneRect().width() - 50; yPos = -(listSize * 25); //Align with the origin // E- - for(const int &value: greaterList){ + for (const int &value : greaterList) { createRect(echar, -value, currSize, xPos, yPos); yPos += currSize; } // E+ - for(const int &value: lessList){ + for (const int &value : lessList) { createRect(echar, value, currSize, xPos, yPos); yPos += currSize; } setSceneRect(scene()->itemsBoundingRect()); } void AxisControl::resizeEvent(QResizeEvent *) { fitInView(sceneRect(), Qt::KeepAspectRatio); } -void AxisControl::setLabels(QGraphicsItem *item, QLatin1Char& axis, int value) +void AxisControl::setLabels(QGraphicsItem *item, QLatin1Char &axis, int value) { auto *lb = new QGraphicsSimpleTextItem(); lb->setBrush(palette().buttonText()); if (this->logicalDpiX() <= 96) { lb->setText((value < 0) ? QStringLiteral(" -") + axis : QStringLiteral(" ") + axis); } else { lb->setText((value < 0) ? QStringLiteral("-") + axis : QStringLiteral(" ") + axis); } if (axis.toLatin1() == 'X') { lb->setY(item->y() - lb->boundingRect().width()); if (value < 0) { lb->setX(item->x() - item->boundingRect().width() / 1.2 - lb->boundingRect().width() / 2); } else { lb->setX(item->x() + item->boundingRect().width() / 1.2 - lb->boundingRect().width() / 2); } } else if (axis.toLatin1() == 'Y') { lb->setX(item->x() - lb->boundingRect().width() / 2); if (value < 0) { lb->setY(item->y() + item->boundingRect().height() / 1.5); } else { lb->setY(item->y() - item->boundingRect().height()); } } else { lb->setX(item->x() + lb->boundingRect().width() / fontMetrics().width(lb->text())); #ifndef Q_OS_WIN lb->setY(item->y() - lb->boundingRect().height() / fontMetrics().xHeight()); #else lb->setY(item->y() - lb->boundingRect().height() / fontMetrics().height()); #endif } scene()->addItem(lb); } diff --git a/src/widgets/axiscontrol.h b/src/widgets/axiscontrol.h index 34eba38..14088f2 100644 --- a/src/widgets/axiscontrol.h +++ b/src/widgets/axiscontrol.h @@ -1,86 +1,86 @@ /* Atelier KDE Printer Host for 3D Printing Copyright (C) <2016> Author: Lays Rodrigues - lays.rodrigues@kde.org Chris Rizzitello - rizzitello@kde.org This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma once #include #include #include #include "atcorewidgets_export.h" /* Usage: * * Create a instance of PrinterHotendPositionVisualController and * connect the clicked signal, it will give you the axis and value * that was clicked. */ class ATCOREWIDGETS_EXPORT PieButton : public QObject, public QGraphicsEllipseItem { Q_OBJECT public: - PieButton(QLatin1Char& axis, int value, int size, int angle); + PieButton(QLatin1Char &axis, int value, int size, int angle); void setPalette(QPalette palette); protected: void mousePressEvent(QGraphicsSceneMouseEvent *); void hoverEnterEvent(QGraphicsSceneHoverEvent *); void hoverLeaveEvent(QGraphicsSceneHoverEvent *); signals: void clicked(QLatin1Char axis, int value); private: QLatin1Char _axis; int _value; QPalette _palette; }; class ATCOREWIDGETS_EXPORT RectButton : public QObject, public QGraphicsRectItem { Q_OBJECT public: - RectButton(QLatin1Char& axis, int value, int size); + RectButton(QLatin1Char &axis, int value, int size); void setPalette(QPalette palette); protected: void mousePressEvent(QGraphicsSceneMouseEvent *); void hoverEnterEvent(QGraphicsSceneHoverEvent *); void hoverLeaveEvent(QGraphicsSceneHoverEvent *); signals: void clicked(QLatin1Char axis, int value); private: QLatin1Char _axis; int _value; QPalette _palette; }; class ATCOREWIDGETS_EXPORT AxisControl : public QGraphicsView { Q_OBJECT public: explicit AxisControl(const QList &movementValues = {1, 10, 25}, QWidget *parent = nullptr); private: - void setLabels(QGraphicsItem *item, QLatin1Char& axis, int value); + void setLabels(QGraphicsItem *item, QLatin1Char &axis, int value); protected: void resizeEvent(QResizeEvent *); signals: void clicked(QLatin1Char axis, int value); }; diff --git a/src/widgets/movementwidget.cpp b/src/widgets/movementwidget.cpp index 75a1504..2c723f1 100644 --- a/src/widgets/movementwidget.cpp +++ b/src/widgets/movementwidget.cpp @@ -1,98 +1,98 @@ /* AtCore Test Client Copyright (C) <2018> Author: Chris Rizzitello - rizzitello@kde.org This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "axiscontrol.h" #include "movementwidget.h" MovementWidget::MovementWidget(bool showHomeAndDisableWidgets, QWidget *parent) : QWidget(parent) { auto mainLayout = new QVBoxLayout; auto hBoxLayout = new QHBoxLayout; auto newButton = new QPushButton; - if( showHomeAndDisableWidgets) { + if (showHomeAndDisableWidgets) { newButton = new QPushButton(tr("Home All")); hBoxLayout->addWidget(newButton); connect(newButton, &QPushButton::clicked, [this] { emit(homeAllPressed()); }); newButton = new QPushButton(tr("Home X")); hBoxLayout->addWidget(newButton); connect(newButton, &QPushButton::clicked, [this] { emit(homeXPressed()); }); newButton = new QPushButton(tr("Home Y")); hBoxLayout->addWidget(newButton); connect(newButton, &QPushButton::clicked, [this] { emit(homeYPressed()); }); newButton = new QPushButton(tr("Home Z")); hBoxLayout->addWidget(newButton); connect(newButton, &QPushButton::clicked, [this] { emit(homeZPressed()); }); mainLayout->addLayout(hBoxLayout); newButton = new QPushButton(tr("Disable Motors")); mainLayout->addWidget(newButton); connect(newButton, &QPushButton::clicked, [this] { emit(disableMotorsPressed()); }); } comboMoveAxis = new QComboBox; comboMoveAxis->addItem(tr("Move X Axis to")); comboMoveAxis->addItem(tr("Move Y Axis to")); comboMoveAxis->addItem(tr("Move Z Axis to")); sbMoveAxis = new QDoubleSpinBox; sbMoveAxis->setRange(0, 200); newButton = new QPushButton(tr("Go")); connect(newButton, &QPushButton::clicked, this, [this] { if (comboMoveAxis->currentIndex() == 0) { emit(absoluteMove(QLatin1Char('X'), sbMoveAxis->value())); } else if (comboMoveAxis->currentIndex() == 1) { emit(absoluteMove(QLatin1Char('Y'), sbMoveAxis->value())); } else if (comboMoveAxis->currentIndex() == 2) { emit(absoluteMove(QLatin1Char('Z'), sbMoveAxis->value())); } }); hBoxLayout = new QHBoxLayout; hBoxLayout->addWidget(comboMoveAxis); hBoxLayout->addWidget(sbMoveAxis); hBoxLayout->addWidget(newButton); mainLayout->addLayout(hBoxLayout); auto axisControl = new AxisControl; mainLayout->addWidget(axisControl); connect(axisControl, &AxisControl::clicked, this, &MovementWidget::relativeMove); setLayout(mainLayout); } diff --git a/src/widgets/printwidget.cpp b/src/widgets/printwidget.cpp index 33c5421..7e4b3ed 100644 --- a/src/widgets/printwidget.cpp +++ b/src/widgets/printwidget.cpp @@ -1,125 +1,125 @@ /* AtCore Test Client Copyright (C) <2018> Author: Chris Rizzitello - rizzitello@kde.org This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "printwidget.h" #include #include #include #include PrintWidget::PrintWidget(bool showAllControls, QWidget *parent) : QWidget(parent) { auto mainLayout = new QVBoxLayout; QPushButton *newButton = nullptr; QLabel *newLabel = nullptr; - QHBoxLayout *hBoxLayout =nullptr; - if(showAllControls) { + QHBoxLayout *hBoxLayout = nullptr; + if (showAllControls) { buttonPrint = new QPushButton(tr("Print File")); connect(buttonPrint, &QPushButton::clicked, [this] { emit(printPressed()); }); newButton = new QPushButton(tr("Emergency Stop")); connect(newButton, &QPushButton::clicked, [this] { emit(emergencyStopPressed()); }); hBoxLayout = new QHBoxLayout; hBoxLayout->addWidget(buttonPrint); hBoxLayout->addWidget(newButton); mainLayout->addLayout(hBoxLayout); newLabel = new QLabel(tr("On Pause:")); linePostPause = new QLineEdit; linePostPause->setPlaceholderText(QStringLiteral("G91,G0 Z1,G90,G1 X0 Y195")); hBoxLayout = new QHBoxLayout; hBoxLayout->addWidget(newLabel); hBoxLayout->addWidget(linePostPause); mainLayout->addLayout(hBoxLayout); } newLabel = new QLabel(tr("Printer Speed")); sbPrintSpeed = new QSpinBox; sbPrintSpeed->setRange(1, 300); sbPrintSpeed->setValue(100); sbPrintSpeed->setSuffix(QStringLiteral("%")); newButton = new QPushButton(tr("Set")); connect(newButton, &QPushButton::clicked, [this] { emit(printSpeedChanged(sbPrintSpeed->value())); }); hBoxLayout = new QHBoxLayout; hBoxLayout->addWidget(newLabel, 60); hBoxLayout->addWidget(sbPrintSpeed, 20); hBoxLayout->addWidget(newButton, 20); mainLayout->addLayout(hBoxLayout); newLabel = new QLabel(tr("Flow Rate")); sbFlowRate = new QSpinBox; sbFlowRate->setRange(1, 300); sbFlowRate->setValue(100); sbFlowRate->setSuffix(QStringLiteral("%")); newButton = new QPushButton(tr("Set")); connect(newButton, &QPushButton::clicked, [this] { emit(flowRateChanged(sbFlowRate->value())); }); hBoxLayout = new QHBoxLayout; hBoxLayout->addWidget(newLabel, 60); hBoxLayout->addWidget(sbFlowRate, 20); hBoxLayout->addWidget(newButton, 20); mainLayout->addLayout(hBoxLayout); comboFanSelect = new QComboBox; sbFanSpeed = new QSpinBox; sbFanSpeed->setRange(0, 100); sbFanSpeed->setSuffix(QStringLiteral("%")); newButton = new QPushButton(tr("Set")); connect(newButton, &QPushButton::clicked, [this] { emit(fanSpeedChanged(sbFanSpeed->value(), comboFanSelect->currentIndex())); }); hBoxLayout = new QHBoxLayout; hBoxLayout->addWidget(comboFanSelect, 60); hBoxLayout->addWidget(sbFanSpeed, 20); hBoxLayout->addWidget(newButton, 20); mainLayout->addLayout(hBoxLayout); setLayout(mainLayout); } QString PrintWidget::postPauseCommand(void) const { return linePostPause->text(); } void PrintWidget::setPrintText(const QString &text) { buttonPrint->setText(text); } void PrintWidget::updateFanCount(const int count) { for (int i = 0; i < count; i++) { comboFanSelect->insertItem(i, tr("Fan %1 speed").arg(i)); } } diff --git a/src/widgets/statuswidget.cpp b/src/widgets/statuswidget.cpp index 71b1b35..332beb2 100644 --- a/src/widgets/statuswidget.cpp +++ b/src/widgets/statuswidget.cpp @@ -1,118 +1,118 @@ /* AtCore Test Client Copyright (C) <2018> Author: Chris Rizzitello - rizzitello@kde.org This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "statuswidget.h" StatusWidget::StatusWidget(bool showStop, QWidget *parent) : QWidget(parent) { //first create the item for the print Progress. auto hBoxLayout = new QHBoxLayout; printingProgress = new QProgressBar; printingProgress->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); hBoxLayout->addWidget(printingProgress); - if(showStop) { + if (showStop) { auto newButton = new QPushButton(style()->standardIcon(QStyle::SP_BrowserStop), QString()); connect(newButton, &QPushButton::clicked, [this] { emit(stopPressed()); }); hBoxLayout->addWidget(newButton); } lblTime = new QLabel(QStringLiteral("00:00:00")); lblTime->setAlignment(Qt::AlignHCenter); auto newLabel = new QLabel(QStringLiteral(" / ")); lblTimeLeft = new QLabel(QStringLiteral("??:??:??")); lblTimeLeft->setAlignment(Qt::AlignHCenter); hBoxLayout->addWidget(lblTime); hBoxLayout->addWidget(newLabel); hBoxLayout->addWidget(lblTimeLeft); printProgressWidget = new QWidget(); printProgressWidget->setLayout(hBoxLayout); //Then Create the full bar. newLabel = new QLabel(tr("AtCore State:")); lblState = new QLabel(tr("Not Connected")); lblSd = new QLabel(); - spacer = new QSpacerItem(10, 20,QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + spacer = new QSpacerItem(10, 20, QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); hBoxLayout = new QHBoxLayout; hBoxLayout->addWidget(newLabel); hBoxLayout->addWidget(lblState); hBoxLayout->addSpacerItem(new QSpacerItem(5, 20, QSizePolicy::Fixed)); hBoxLayout->addWidget(lblSd); hBoxLayout->addSpacerItem(spacer); hBoxLayout->addWidget(printProgressWidget); setLayout(hBoxLayout); printTime = new QTime(); printTimer = new QTimer(); printTimer->setInterval(1000); printTimer->setSingleShot(false); connect(printTimer, &QTimer::timeout, this, &StatusWidget::updatePrintTime); } void StatusWidget::setSD(bool hasSd) { QString labelText = hasSd ? tr("SD") : QString(); lblSd->setText(labelText); } void StatusWidget::setState(const QString &state) { lblState->setText(state); } void StatusWidget::showPrintArea(bool visible) { printProgressWidget->setVisible(visible); if (visible) { - spacer->changeSize(10, 20, QSizePolicy::Fixed,QSizePolicy::Fixed); + spacer->changeSize(10, 20, QSizePolicy::Fixed, QSizePolicy::Fixed); printTime->start(); printTimer->start(); } else { printTimer->stop(); spacer->changeSize(10, 20, QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); } } void StatusWidget::updatePrintTime() { QTime temp(0, 0, 0); lblTime->setText(temp.addMSecs(printTime->elapsed()).toString(QStringLiteral("hh:mm:ss"))); } void StatusWidget::updatePrintProgress(const float &progress) { printingProgress->setValue(progress); if (progress >= 1) { QTime temp(0, 0, 0); lblTimeLeft->setText(temp.addMSecs((100 - progress) * (printTime->elapsed() / progress)).toString(QStringLiteral("hh:mm:ss"))); } else { lblTimeLeft->setText(QStringLiteral("??:??:??")); } }