├── .appveyor.yml ├── .clang-format ├── .gitignore ├── .gitmodules ├── .travis.yml ├── .travis ├── build.sh └── install.sh ├── CMakeLists.txt ├── Chigraph.srctrlprj ├── LICENSE ├── README.md ├── doc ├── chigraph.png └── looping.png ├── icons ├── 1024x1024 │ └── org.chigraph.chigraphgui.png ├── 128x128 │ └── org.chigraph.chigraphgui.png ├── 16x16 │ └── org.chigraph.chigraphgui.png ├── 256x256 │ └── org.chigraph.chigraphgui.png ├── 32x32 │ └── org.chigraph.chigraphgui.png ├── 512x512 │ └── org.chigraph.chigraphgui.png ├── 64x64 │ └── org.chigraph.chigraphgui.png ├── chigraphicon.svg └── export_svgs_to_png.sh ├── licenses ├── KF5.txt ├── Qt.txt └── nodeeditor.txt ├── org.chigraph.chigraphgui.desktop ├── scripts ├── build_frameworks.ps1 ├── format_code.sh ├── frameworks │ ├── Dockerfile │ └── build_frameworks.sh ├── generate_kf5_tarballs.sh ├── org.chigraph.chigraphgui.appdata.xml └── upload_chigraph_dockerimage.sh ├── setup.py ├── src ├── CMakeLists.txt ├── centraltabview.cpp ├── centraltabview.hpp ├── chigraphfunctiondetailsui.rc ├── chigraphfunctiontabviewui.rc ├── chigraphgui.qrc ├── chigraphguiui.rc ├── chigraphmodulebrowserui.rc ├── chigraphnodemodel.cpp ├── chigraphnodemodel.hpp ├── chigraphplugin.hpp ├── chiitemselectiondialog.cpp ├── chiitemselectiondialog.hpp ├── chiitemselectwidget.cpp ├── chiitemselectwidget.hpp ├── debugger │ ├── CMakeLists.txt │ ├── breakpointview.cpp │ ├── breakpointview.hpp │ ├── chigraphdebugger.qrc │ ├── chigraphguidebuggerui.rc │ ├── currentnodedecorator.hpp │ ├── debugger.json │ ├── debuggerplugin.cpp │ ├── debuggerplugin.hpp │ ├── debuggerworkerthread.cpp │ ├── debuggerworkerthread.hpp │ ├── variableview.cpp │ └── variableview.hpp ├── execparamlistwidget.cpp ├── execparamlistwidget.hpp ├── functiondetails.cpp ├── functiondetails.hpp ├── functioninouts.cpp ├── functioninouts.hpp ├── functionview.cpp ├── functionview.hpp ├── launchconfigurationdialog.cpp ├── launchconfigurationdialog.hpp ├── launchconfigurationmanager.cpp ├── launchconfigurationmanager.hpp ├── localvariables.cpp ├── localvariables.hpp ├── main.cpp ├── mainwindow.cpp ├── mainwindow.hpp ├── modulebrowser.cpp ├── modulebrowser.hpp ├── modulepropertiesdialog.cpp ├── modulepropertiesdialog.hpp ├── moduletreemodel.cpp ├── moduletreemodel.hpp ├── newmoduledialog.cpp ├── newmoduledialog.hpp ├── paramlistwidget.cpp ├── paramlistwidget.hpp ├── structedit.cpp ├── structedit.hpp ├── subprocessoutputview.cpp ├── subprocessoutputview.hpp ├── thememanager.cpp ├── thememanager.hpp ├── toolview.hpp ├── typeselector.cpp └── typeselector.hpp └── third_party └── .gitignore /.appveyor.yml: -------------------------------------------------------------------------------- 1 | clone_depth: 5 2 | 3 | configuration: 4 | - Release 5 | - Debug 6 | 7 | platform: 8 | - x64 9 | 10 | build_script: 11 | - 'git submodule update --init --recursive' 12 | - 'set PATH=%QTDIR%\bin;C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%' 13 | - "sh -c 'pacman -Syu --noconfirm'" 14 | - "sh -c 'pacman -S --noconfirm mingw-w64-x86_64-toolchain mingw-w64-x86_64-llvm mingw-w64-x86_64-clang mingw-w64-x86_64-clang-tools-extra mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja git mingw-w64-x86_64-qt5 bison flex mingw-w64-x86_64-python3'" 15 | - "python3 setup.py" 16 | - mkdir build 17 | - cd build 18 | - cmake "-GNinja" -DCMAKE_BUILD_TYPE="%configuration%" -DCMAKE_PREFIX_PATH="%QTDIR%" -DCG_BUILD_DEBUGGER=OFF .. 19 | - ninja 20 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | Language: Cpp 3 | 4 | IndentWidth: 4 5 | PointerAlignment: Left 6 | ColumnLimit: 100 7 | AccessModifierOffset: -4 8 | BreakBeforeBraces: Attach 9 | UseTab: ForIndentation 10 | TabWidth: 4 11 | AlignAfterOpenBracket: true 12 | PointerAlignment: Left 13 | AlignConsecutiveAssignments: true 14 | AlignConsecutiveDeclarations: true 15 | Cpp11BracedListStyle: true 16 | IndentCaseLabels: false 17 | AllowShortIfStatementsOnASingleLine: true 18 | AllowShortBlocksOnASingleLine: true 19 | AllowShortCaseLabelsOnASingleLine: true 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # builds 2 | build/ 3 | buildrel/ 4 | builddebug/ 5 | 6 | # KDevelop 7 | *.kdev4 8 | kdev4/ 9 | 10 | # VS Code 11 | .vscode/ 12 | 13 | # Cquery 14 | .cquery_cache 15 | 16 | .cache 17 | 18 | # Source trail 19 | *.srctrlbm 20 | *.srctrldb 21 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "chigraph"] 2 | path = chigraph 3 | url = https://github.com/chigraph/chigraph 4 | [submodule "third_party/nodeeditor"] 5 | path = third_party/nodeeditor 6 | url = https://github.com/chigraph/nodeeditor 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | language: cpp 3 | dist: trusty 4 | 5 | addons: 6 | apt: 7 | sources: 8 | - ubuntu-toolchain-r-test 9 | - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-4.0 main' 10 | key_url: 'http://apt.llvm.org/llvm-snapshot.gpg.key' 11 | - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.9 main' 12 | key_url: 'http://apt.llvm.org/llvm-snapshot.gpg.key' 13 | - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.8 main' 14 | key_url: 'http://apt.llvm.org/llvm-snapshot.gpg.key' 15 | - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.7 main' 16 | key_url: 'http://apt.llvm.org/llvm-snapshot.gpg.key' 17 | - sourceline: 'ppa:beineri/opt-qt562-trusty' 18 | - sourceline: 'ppa:beineri/opt-qt571-trusty' 19 | - sourceline: 'ppa:beineri/opt-qt58-trusty' 20 | - sourceline: 'ppa:presslabs/gitfs' 21 | 22 | matrix: 23 | include: 24 | 25 | # appimage 26 | - os: linux 27 | install: 28 | script: 29 | - ./scripts/appimage/appimage_recipie.sh 30 | after_success: 31 | - wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh 32 | - bash ./upload.sh ./Chigraph-x86_64.AppImage 33 | 34 | # sneak in 1 osx one so we can see it early 35 | - os: osx 36 | osx_image: xcode8.2 37 | env: BUILD_TYPE=Debug 38 | 39 | - env: CXX_COMPILER=g++-5 C_COMPILER=gcc-5 BUILD_TYPE=Debug QT_VERSION=562 LLVM_VERSION=3.7 PACKAGES='g++-5 gcc-5' 40 | - env: CXX_COMPILER=g++-5 C_COMPILER=gcc-5 BUILD_TYPE=Release QT_VERSION=571 LLVM_VERSION=3.8 PACKAGES='g++-5 gcc-5' 41 | - env: CXX_COMPILER=g++-6 C_COMPILER=gcc-6 BUILD_TYPE=Debug QT_VERSION=58 LLVM_VERSION=3.9 PACKAGES='g++-6 gcc-6' 42 | - env: CXX_COMPILER=g++-6 C_COMPILER=gcc-6 BUILD_TYPE=Release QT_VERSION=58 LLVM_VERSION=4.0 PACKAGES='g++-6 gcc-6' 43 | 44 | - os: osx 45 | osx_image: xcode8.2 46 | env: BUILD_TYPE=Release 47 | - os: osx 48 | osx_image: xcode8.1 49 | env: BUILD_TYPE=Debug 50 | - os: osx 51 | osx_image: xcode8.1 52 | env: BUILD_TYPE=Release 53 | - os: osx 54 | osx_image: xcode8 55 | env: BUILD_TYPE=Debug 56 | - os: osx 57 | osx_image: xcode8 58 | env: BUILD_TYPE=Release 59 | # Disabled until bottles are available 60 | # for LLVM and KF5. 61 | # - os: osx 62 | # osx_image: xcode7.3 63 | # env: BUILD_TYPE=Debug 64 | # - os: osx 65 | # osx_image: xcode7.3 66 | # env: BUILD_TYPE=Release 67 | 68 | 69 | branches: 70 | except: 71 | - # Do not build tags that we create when we upload to GitHub Releases 72 | - /^(?i:continuous)$/ 73 | 74 | 75 | install: 76 | - 'if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update && sudo apt-get install $PACKAGES llvm-${LLVM_VERSION}-dev libclang-${LLVM_VERSION}-dev libclang-common-${LLVM_VERSION}-dev libgit2 qt${QT_VERSION:0:2}base qt${QT_VERSION:0:2}script qt${QT_VERSION:0:2}declarative qt${QT_VERSION:0:2}tools qt${QT_VERSION:0:2}x11extras qt${QT_VERSION:0:2}svg ninja-build libedit-dev libxcb-keysyms1-dev libxml2-utils libudev-dev texinfo build-essential && source /opt/qt${QT_VERSION:0:2}/bin/qt${QT_VERSION:0:2}-env.sh; fi' 77 | - ./.travis/install.sh 78 | 79 | script: 80 | - ./.travis/build.sh 81 | -------------------------------------------------------------------------------- /.travis/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -xe 4 | 5 | if [ "$TRAVIS_OS_NAME" == "linux" ]; then 6 | 7 | cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ 8 | -DCMAKE_CXX_COMPILER=$CXX_COMPILER \ 9 | -DCMAKE_C_COMPILER=$C_COMPILER \ 10 | -GNinja -DCMAKE_CXX_FLAGS='--coverage' \ 11 | -DLLVM_CONFIG="/usr/lib/llvm-${LLVM_VERSION}/bin/llvm-config" 12 | 13 | ninja 14 | 15 | else 16 | 17 | cmake . \ 18 | -DCMAKE_PREFIX_PATH='/usr/local/opt/qt5/;/usr/local/opt/gettext' \ 19 | -DCMAKE_BUILD_TYPE=Debug \ 20 | -DLLVM_CONFIG=/usr/local/opt/llvm/bin/llvm-config \ 21 | -GNinja -DCG_BUILD_DEBUGGER=OFF 22 | ninja 23 | 24 | fi 25 | -------------------------------------------------------------------------------- /.travis/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -xe 4 | 5 | if [ "$TRAVIS_OS_NAME" == "linux" ]; then 6 | 7 | if [ "$LLVM_VERSION" == "3.9" ] || [ "$LLVM_VERSION" == "4.0" ]; then 8 | sudo apt-get install liblldb-${LLVM_VERSION}-dev 9 | else 10 | sudo apt-get install lldb-${LLVM_VERSION}-dev 11 | fi 12 | 13 | python3 ./setup.py 14 | 15 | else 16 | 17 | brew install cmake z ninja python3 || echo 18 | brew install llvm --with-clang 19 | 20 | brew tap chigraph/kf5 21 | brew install chigraph/kf5/kf5-extra-cmake-modules 22 | 23 | # kcoreaddons workaround 24 | brew install chigraph/kf5/kf5-kcoreaddons || brew link --force --overwrite chigraph/kf5/kf5-kcoreaddons 25 | 26 | brew install chigraph/kf5/kf5-karchive chigraph/kf5/kf5-ktexteditor chigraph/kf5/kf5-kjobwidgets \ 27 | chigraph/kf5/kf5-kdbusaddons chigraph/kf5/kf5-kio chigraph/kf5/kf5-kcrash \ 28 | chigraph/kf5/kf5-sonnet chigraph/kf5/kf5-syntax-highlighting chigraph/kf5/kf5-kparts \ 29 | chigraph/kf5/kf5-kguiaddons chigraph/kf5/kf5-kitemviews chigraph/kf5/kf5-kconfig \ 30 | chigraph/kf5/kf5-kconfigwidgets chigraph/kf5/kf5-kauth chigraph/kf5/kf5-kcodecs \ 31 | chigraph/kf5/kf5-kcompletion chigraph/kf5/kf5-kglobalaccel chigraph/kf5/kf5-kservice \ 32 | chigraph/kf5/kf5-kwindowsystem chigraph/kf5/kf5-ki18n chigraph/kf5/kf5-kxmlgui \ 33 | chigraph/kf5/kf5-kwidgetsaddons chigraph/kf5/kf5-ktextwidgets chigraph/kf5/kf5-kiconthemes 34 | 35 | fi 36 | 37 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.21) 2 | cmake_policy(SET CMP0057 NEW) 3 | 4 | project(chigraph-gui) 5 | 6 | option(CG_USE_SYSTEM_CHIGRAPH "Try to find chigraph instead of building it here" OFF) 7 | option(CG_BUILD_FOR_FLATPAK "Build for flatpak (turns off native file dialog)" OFF) 8 | 9 | if (CG_BUILD_FOR_FLATPAK) 10 | add_definitions(-DCHI_FOR_FLATPAK) 11 | endif() 12 | 13 | if (WIN32) 14 | set(GETTEXT_MSGMERGE_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gettext-win64/bin/msgmerge.exe CACHE FILEPATH "") 15 | set(GETTEXT_MSGFMT_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gettext-win64/bin/msgfmt.exe CACHE FILEPATH "") 16 | endif() 17 | 18 | set(BUILD_EXAMPLES OFF CACHE BOOL "") 19 | add_subdirectory(third_party/nodeeditor) 20 | 21 | if (CG_USE_SYSTEM_CHIGRAPH) 22 | find_package(Chigraph REQUIRED) 23 | else() 24 | add_subdirectory(chigraph) 25 | endif() 26 | add_subdirectory(src) 27 | -------------------------------------------------------------------------------- /Chigraph.srctrlprj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | build/compile_commands.json 7 | 8 | 9 | chigraph/third_party 10 | third_party 11 | chigraph/lib/support/include/chi/Support/json.hpp 12 | build 13 | 14 | 15 | chigraph/chi 16 | chigraph/lib/core/include 17 | chigraph/lib/core/src 18 | chigraph/lib/debugger/include 19 | chigraph/lib/debugger/src 20 | chigraph/lib/fetcher/include 21 | chigraph/lib/fetcher/src 22 | chigraph/lib/support/include 23 | chigraph/lib/support/src 24 | chigraph/test 25 | src 26 | 27 | C/C++ from Compilation Database 28 | 29 | 1 30 | 31 | enabled 32 | C/C++ from Compilation Database 33 | 34 | 35 | 8 36 | 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![chigraph logo](doc/chigraph.png) 3 | 4 | # Chigraph GUI 5 | This is the interface for chigraph to make creating [chigraph](https://github.com/chigraph/chigraph) modules easy. It's written in [Qt 5](https://www.qt.io) and [KDE Frameworks 5](https://api.kde.org/frameworks/index.html) 6 | 7 | 8 | ![screenshot](doc/looping.png) 9 | 10 | # Build Status 11 | | Platform | Status | 12 | | ----------- | -------------------------------------------------------------------------------- | 13 | | linux/macOS | [![Travis branch](https://img.shields.io/travis/chigraph/chigraph-gui/master.svg?style=flat-square)](https://travis-ci.org/chigraph/chigraph-gui) | 14 | | Windows | [![AppVeyor](https://img.shields.io/appveyor/ci/guapotaco/chigraph-gui.svg?style=flat-square)](https://ci.appveyor.com/project/GuapoTaco/chigraph-gui) | 15 | 16 | ## Features 17 | - Easily download modules from the internet 18 | - Debug your modules 19 | - See errors as you write them 20 | - Open Source (Apache 2) 21 | 22 | # Getting Involved 23 | - Graph a issue and run with it! You can always reach me on the gitter 24 | 25 | # Installing 26 | 27 | ## Flatpak 28 | There's a flatpak package for chigraph, and here's how to install it: 29 | 30 | ```bash 31 | flatpak install https://chigraph.io/flatpak/org.chigraph.chigraphgui.flatpakref 32 | ``` 33 | 34 | ## Build 35 | 36 | # Authors 37 | 38 | - Russell Greene (@russelltg) - Main contributor 39 | 40 | ## Technology Used 41 | - [Qt](https://www.qt.io) 42 | - [KF5](https://api.kde.org/frameworks/index.html) for super easy gui making 43 | - [Qt Node Editor](https://github.com/paceholder/nodeeditor) for node rendering/editing 44 | 45 | -------------------------------------------------------------------------------- /doc/chigraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chigraph/chigraph-gui/3f791759d4c63c1fc7903f96324cd44466abec4a/doc/chigraph.png -------------------------------------------------------------------------------- /doc/looping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chigraph/chigraph-gui/3f791759d4c63c1fc7903f96324cd44466abec4a/doc/looping.png -------------------------------------------------------------------------------- /icons/1024x1024/org.chigraph.chigraphgui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chigraph/chigraph-gui/3f791759d4c63c1fc7903f96324cd44466abec4a/icons/1024x1024/org.chigraph.chigraphgui.png -------------------------------------------------------------------------------- /icons/128x128/org.chigraph.chigraphgui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chigraph/chigraph-gui/3f791759d4c63c1fc7903f96324cd44466abec4a/icons/128x128/org.chigraph.chigraphgui.png -------------------------------------------------------------------------------- /icons/16x16/org.chigraph.chigraphgui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chigraph/chigraph-gui/3f791759d4c63c1fc7903f96324cd44466abec4a/icons/16x16/org.chigraph.chigraphgui.png -------------------------------------------------------------------------------- /icons/256x256/org.chigraph.chigraphgui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chigraph/chigraph-gui/3f791759d4c63c1fc7903f96324cd44466abec4a/icons/256x256/org.chigraph.chigraphgui.png -------------------------------------------------------------------------------- /icons/32x32/org.chigraph.chigraphgui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chigraph/chigraph-gui/3f791759d4c63c1fc7903f96324cd44466abec4a/icons/32x32/org.chigraph.chigraphgui.png -------------------------------------------------------------------------------- /icons/512x512/org.chigraph.chigraphgui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chigraph/chigraph-gui/3f791759d4c63c1fc7903f96324cd44466abec4a/icons/512x512/org.chigraph.chigraphgui.png -------------------------------------------------------------------------------- /icons/64x64/org.chigraph.chigraphgui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chigraph/chigraph-gui/3f791759d4c63c1fc7903f96324cd44466abec4a/icons/64x64/org.chigraph.chigraphgui.png -------------------------------------------------------------------------------- /icons/chigraphicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | 25 | 26 | 28 | image/svg+xml 29 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 44 | 45 | 46 | 71 | 77 | 81 | 87 | 88 | 89 | 95 | 96 | -------------------------------------------------------------------------------- /icons/export_svgs_to_png.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | 6 | imgdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 7 | 8 | mkdir -p 16x16 32x32 64x64 128x128 256x256 512x512 1024x1024 9 | 10 | ink=`which inkscape` 11 | $ink chigraphicon.svg -w 16 -h 16 -e 16x16/org.chigraph.chigraphgui.png 12 | $ink chigraphicon.svg -w 32 -h 32 -e 32x32/org.chigraph.chigraphgui.png 13 | $ink chigraphicon.svg -w 64 -h 64 -e 64x64/org.chigraph.chigraphgui.png 14 | $ink chigraphicon.svg -w 128 -h 128 -e 128x128/org.chigraph.chigraphgui.png 15 | $ink chigraphicon.svg -w 256 -h 256 -e 256x256/org.chigraph.chigraphgui.png 16 | $ink chigraphicon.svg -w 256 -h 256 -e 512x512/org.chigraph.chigraphgui.png 17 | $ink chigraphicon.svg -w 1024 -h 1024 -e 1024x1024/org.chigraph.chigraphgui.png 18 | -------------------------------------------------------------------------------- /licenses/KF5.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /licenses/Qt.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /licenses/nodeeditor.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /org.chigraph.chigraphgui.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=Chigraph 4 | Exec=chigraphgui 5 | Icon=org.chigraph.chigraphgui 6 | Categories=Qt;KDE;Development;IDE; 7 | 8 | -------------------------------------------------------------------------------- /scripts/build_frameworks.ps1: -------------------------------------------------------------------------------- 1 | 2 | $firstdir = pwd 3 | $scriptsdir = $PSScriptRoot 4 | 5 | $version = "5.30.0" 6 | $sversion = "5.30" 7 | 8 | if ($args.length -lt 3) { 9 | "Usage: .\build_frameworks.ps1 kf5.log) || (cat kf5.log && exist) 39 | } 40 | 41 | build_helper extra-cmake-modules 42 | build_helper kconfig 43 | build_helper kguiaddons 44 | build_helper ki18n 45 | build_helper kitemviews 46 | build_helper sonnet 47 | build_helper kwidgetsaddons 48 | build_helper kcompletion 49 | build_helper kdbusaddons 50 | build_helper karchive 51 | build_helper kcoreaddons 52 | build_helper kjobwidgets 53 | build_helper kwindowsystem 54 | build_helper kcrash 55 | build_helper kservice 56 | build_helper kcodecs 57 | build_helper kauth 58 | build_helper kconfigwidgets 59 | build_helper kiconthemes 60 | build_helper ktextwidgets 61 | build_helper kglobalaccel 62 | build_helper kxmlgui 63 | build_helper kbookmarks 64 | build_helper solid 65 | #build_helper knotifications 66 | #build_helper kwallet 67 | build_helper kio 68 | build_helper kparts 69 | #build_helper kitemmodels 70 | #build_helper threadweaver 71 | build_helper attica 72 | #build_helper knewstuff 73 | build_helper syntax-highlighting 74 | build_helper ktexteditor 75 | #build_helper kpackage 76 | #build_helper kdeclarative 77 | #build_helper kcmutils 78 | #build_helper knotifyconfig 79 | #build_helper libkomparediff2 80 | #build_helper kdoctools 81 | build_helper breeze-icons -DBINARY_ICONS_RESOURCE=1 82 | #build_helper kpty 83 | #build_helper kinit 84 | #build_helper konsole 85 | 86 | # cd $kf5dir/build 87 | # 88 | # foldername=breeze-5.9.2 89 | # 90 | # wget http://download.kde.org/stable/plasma/5.9.2/$foldername.tar.xz 91 | # tar xf $foldername.tar.xz 92 | # mkdir -p $foldername/build 93 | # cd $foldername/build 94 | # 95 | # cmake .. -DCMAKE_PREFIX_PATH="$kf5dir" -DCMAKE_INSTALL_PREFIX="$kf5dir" -DLIB_INSTALL_DIR=lib -DCMAKE_BUILD_TYPE=$btype $flags 96 | # cmake --build . 97 | # cmake --build . --target install 98 | -------------------------------------------------------------------------------- /scripts/generate_kf5_tarballs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | SCRIPTSDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 6 | cd $SCRIPTSDIR/frameworks 7 | 8 | docker build -t chigraph/frameworks-build . 9 | 10 | DOCKER_PROCESS=$(docker run -d chigraph/frameworks-build bash -c 'while true; do sleep 1000; done') 11 | 12 | docker exec -t $DOCKER_PROCESS bash -c 'cd / && git clone https://github.com/chigraph/chigraph --depth=1' 13 | docker exec -t $DOCKER_PROCESS bash -c 'source /opt/qt56/bin/qt56-env.sh && /chigraph/scripts/frameworks/build_frameworks.sh Debug -GNinja' 14 | docker exec -t $DOCKER_PROCESS bash -c 'source /opt/qt56/bin/qt56-env.sh && /chigraph/scripts/frameworks/build_frameworks.sh Release -GNinja' 15 | docker exec -t $DOCKER_PROCESS bash -c 'cd /chigraph/third_party && tar cJf kf5-debug-gcc-linux64.tar.xz kf5-debug' 16 | docker exec -t $DOCKER_PROCESS bash -c 'cd /chigraph/third_party && tar cJf kf5-release-gcc-linux64.tar.xz kf5-release' 17 | 18 | docker cp ${DOCKER_PROCESS}:/chigraph/third_party/kf5-debug-gcc-linux64.tar.xz ../ 19 | docker cp ${DOCKER_PROCESS}:/chigraph/third_party/kf5-release-gcc-linux64.tar.xz ../ 20 | -------------------------------------------------------------------------------- /scripts/org.chigraph.chigraphgui.appdata.xml: -------------------------------------------------------------------------------- 1 | ​ 2 | ​ 3 | ​ 4 | ​ org.chigraph.chigraphgui 5 | ​ FSFAP 6 | ​ Apache 2.0 7 | ​ Chigraph GUI 8 | ​ Write chigraph code 9 | ​ 10 | ​ 11 | ​

12 | ​ Chigraph GUI is a graphical interface to the chigraph language 13 |

14 | ​
15 | ​ 16 | ​ org.chigraph.chigraphgui.desktop 17 | ​ 18 | ​ 19 | ​ 20 | ​ If statement 21 | ​ https://raw.githubusercontent.com/chigraph/chigraph/master/doc/screenshots/if.png 22 | ​ 23 | ​ 24 | ​ http://www.hughsie.com/en_US/preferences.png 25 | ​ 26 | ​ 27 | ​ 28 | ​ https://raw.githubusercontent.com/chigraph/chigraph/master/doc/screenshots/looping.png 29 | ​ Chigraph 30 | ​ 31 | ​ 32 | ​ chigraphgui 33 | ​ 34 | ​ 35 | ​ 36 | ​ 37 | ​ 38 | ​

Initial Release

39 | ​
40 | ​
41 | ​
42 | ​
43 | -------------------------------------------------------------------------------- /scripts/upload_chigraph_dockerimage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | SCRIPTSDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 6 | cd $SCRIPTSDIR/appimage 7 | 8 | docker build . -t russelltg/chigraph-appimage:latest 9 | docker push russelltg/chigraph-appimage:latest 10 | 11 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import urllib.request 4 | import tarfile 5 | import platform 6 | import os 7 | import shutil 8 | from multiprocessing import Pool 9 | 10 | def dlAndExtract(tup): 11 | url = tup[0] 12 | filename = tup[1] 13 | extractto = tup[2] 14 | 15 | print("downloading " + filename) 16 | 17 | if not os.path.isfile(filename): 18 | # download 19 | with urllib.request.urlopen(url) as response, open(filename, 'wb') as out_file: 20 | shutil.copyfileobj(response, out_file) 21 | 22 | print("extracting " + filename + " to " + extractto) 23 | 24 | # extract 25 | tar = tarfile.open(filename) 26 | tar.extractall(extractto) 27 | 28 | 29 | chigraphDir = os.path.dirname(os.path.realpath(__file__)) 30 | thirdPartyDir = os.path.join(chigraphDir, "third_party") 31 | 32 | urls=[] 33 | 34 | print("Downloading dependencies for system: {}".format(platform.system())) 35 | 36 | if platform.system() == "Linux": 37 | 38 | urls.append(('https://github.com/chigraph/chigraph/releases/download/dependencies/kf5-5.32.0-debug-gcc-linux64.tar.xz', os.path.join(thirdPartyDir, "kf5-debug.tar.xz"), thirdPartyDir)) 39 | urls.append(('https://github.com/chigraph/chigraph/releases/download/dependencies/kf5-5.32.0-release-gcc-linux64.tar.xz', os.path.join(thirdPartyDir, "kf5-release.tar.xz"), thirdPartyDir)) 40 | 41 | elif platform.system() == "Windows": 42 | urls.append(('https://github.com/chigraph/chigraph/releases/download/dependencies/flexbison-win32.tar.xz', os.path.join(thirdPartyDir, "flexbison-win32.tar.xz"), thirdPartyDir)) 43 | urls.append(('https://github.com/chigraph/chigraph/releases/download/dependencies/gettext-win64.tar.xz', os.path.join(thirdPartyDir, "gettext-win64.tar.xz"), thirdPartyDir)) 44 | urls.append(('https://github.com/chigraph/chigraph/releases/download/dependencies/iconv-win64.tar.xz', os.path.join(thirdPartyDir, "iconv-win64.tar.xz"), thirdPartyDir)) 45 | urls.append(('https://github.com/chigraph/chigraph/releases/download/dependencies/zlib-win64.tar.xz', os.path.join(thirdPartyDir, "zlib-win64.tar.xz"), thirdPartyDir)) 46 | 47 | urls.append(('https://github.com/chigraph/chigraph/releases/download/dependencies/kf5-5.30.0-debug-msvc14-win64.tar.xz', os.path.join(thirdPartyDir, "kf5-debug.tar.xz"), thirdPartyDir)) 48 | urls.append(('https://github.com/chigraph/chigraph/releases/download/dependencies/kf5-5.30.0-release-msvc14-win64.tar.xz', os.path.join(thirdPartyDir, "kf5-release.tar.xz"), thirdPartyDir)) 49 | elif platform.system() == "Darwin": 50 | pass 51 | else: 52 | print("Unrecognized system: {}".format(platform.system())) 53 | 54 | for url in urls: 55 | dlAndExtract(url) 56 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(KDE_SKIP_TEST_SETTINGS ON) 2 | 3 | 4 | # make sure QtMain is linked 5 | cmake_policy(SET CMP0020 NEW) 6 | 7 | # Check that the dependencies dirs exist 8 | if (NOT APPLE) # apple uses brew 9 | if ("${CMAKE_BUILD_TYPE}" MATCHES "Debug") 10 | if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../third_party/kf5-debug") 11 | message(WARNING "Run setup.sh first if you wish to use the bundled kf5; trying to find system KF5") 12 | endif() 13 | else() 14 | if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../third_party/kf5-release") 15 | message(WARNING "Run setup.sh first if you wish to use the bundled kf5; trying to find system KF5") 16 | endif() 17 | endif() 18 | endif() 19 | 20 | 21 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 22 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 23 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 24 | 25 | # make sure they have pulled the submodules 26 | if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../third_party/nodeeditor/CMakeLists.txt") 27 | message(FATAL_ERROR "Pull the submodules first, run `git submodule update --init`") 28 | endif() 29 | 30 | # use the downloaded KF5 libraries 31 | if ("${CMAKE_BUILD_TYPE}" MATCHES "Debug") 32 | set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/kf5-debug) 33 | else() 34 | set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/kf5-release) 35 | endif() 36 | 37 | 38 | set(CMAKE_AUTORCC ON) 39 | set(CMAKE_AUTOMOC ON) 40 | 41 | 42 | find_package(ECM 1.0.0 REQUIRED NO_MODULE) 43 | set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 44 | 45 | include(KDEInstallDirs) 46 | include(KDECMakeSettings) 47 | include(FeatureSummary) 48 | 49 | # find qt 50 | find_package(Qt5 5.6.0 REQUIRED COMPONENTS Gui Script Xml Core Widgets Network PrintSupport Svg) 51 | find_package(Qt5 5.6.0 COMPONENTS DBus) 52 | 53 | find_package(KF5 REQUIRED COMPONENTS 54 | Attica Archive TextEditor JobWidgets DBusAddons KIO Crash Sonnet SyntaxHighlighting 55 | Parts GuiAddons ItemViews Config ConfigWidgets Auth Codecs Completion GlobalAccel 56 | Service WindowSystem CoreAddons I18n XmlGui WidgetsAddons TextWidgets IconThemes) 57 | 58 | set(CMAKE_CXX_STANDARD 17) 59 | 60 | if (CG_BUILD_DEBUGGER) 61 | add_subdirectory(debugger) 62 | endif() 63 | 64 | set(GUI_SRCS 65 | main.cpp 66 | mainwindow.cpp 67 | chigraphnodemodel.cpp 68 | functionview.cpp 69 | functiondetails.cpp 70 | paramlistwidget.cpp 71 | subprocessoutputview.cpp 72 | modulebrowser.cpp 73 | execparamlistwidget.cpp 74 | thememanager.cpp 75 | localvariables.cpp 76 | functioninouts.cpp 77 | typeselector.cpp 78 | centraltabview.cpp 79 | launchconfigurationmanager.cpp 80 | launchconfigurationdialog.cpp 81 | structedit.cpp 82 | moduletreemodel.cpp 83 | chiitemselectiondialog.cpp 84 | chiitemselectwidget.cpp 85 | newmoduledialog.cpp 86 | modulepropertiesdialog.cpp 87 | ) 88 | 89 | set(GUI_RESOURCES 90 | chigraphgui.qrc 91 | ) 92 | 93 | set(GUI_HEADERS 94 | mainwindow.hpp 95 | chigraphnodemodel.hpp 96 | functionview.hpp 97 | subprocessoutputview.hpp 98 | paramlistwidget.hpp 99 | functiondetails.hpp 100 | modulebrowser.hpp 101 | execparamlistwidget.hpp 102 | thememanager.hpp 103 | localvariables.hpp 104 | functioninouts.hpp 105 | typeselector.hpp 106 | centraltabview.hpp 107 | launchconfigurationmanager.hpp 108 | launchconfigurationdialog.hpp 109 | structedit.hpp 110 | moduletreemodel.hpp 111 | chiitemselectiondialog.hpp 112 | chiitemselectwidget.hpp 113 | newmoduledialog.hpp 114 | modulepropertiesdialog.hpp 115 | ) 116 | 117 | add_executable(chigraphgui ${GUI_SRCS} ${GUI_HEADERS} ${GUI_RESOURCES}) 118 | 119 | # for some reason cmake doesn't pick up on me wanting to do this...idk 120 | set_target_properties(chigraphgui PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") 121 | 122 | 123 | target_link_libraries(chigraphgui 124 | Qt5::Widgets 125 | KF5::Completion 126 | KF5::TextEditor 127 | KF5::Crash 128 | KF5::Service 129 | KF5::CoreAddons 130 | KF5::I18n 131 | KF5::Auth 132 | KF5::XmlGui 133 | KF5::WidgetsAddons 134 | KF5::TextWidgets 135 | KF5::IconThemes 136 | nodes 137 | chigraphcore 138 | ) 139 | 140 | if (CG_BUILD_DEBUGGER) 141 | target_link_libraries(chigraphgui chigraphguidebugger) 142 | endif() 143 | 144 | if(UNIX) 145 | target_compile_options(chigraphgui PRIVATE "-fexceptions") 146 | endif() 147 | 148 | # copy dlls 149 | if(WIN32) 150 | add_custom_target(copydlls ALL) 151 | foreach(QTLIB 152 | Qt5::Widgets Qt5::Core Qt5::Gui Qt5::Script 153 | Qt5::Network Qt5::DBus Qt5::Svg Qt5::PrintSupport Qt5::Xml 154 | KF5::Attica KF5::Crash KF5::Parts KF5::KIOCore KF5::KIOWidgets 155 | KF5::JobWidgets KF5::TextEditor KF5::SyntaxHighlighting 156 | KF5::DBusAddons KF5::Archive KF5::ConfigWidgets 157 | KF5::GuiAddons KF5::ItemViews KF5::Codecs KF5::Auth 158 | KF5::Completion KF5::SonnetCore KF5::SonnetUi 159 | KF5::Service KF5::ConfigGui KF5::WindowSystem 160 | KF5::GlobalAccel KF5::CoreAddons KF5::I18n KF5::XmlGui 161 | KF5::WidgetsAddons KF5::TextWidgets KF5::IconThemes KF5::AuthCore 162 | ) 163 | 164 | add_custom_command( 165 | TARGET copydlls POST_BUILD 166 | COMMAND ${CMAKE_COMMAND} -E copy_if_different 167 | $ 168 | $ 169 | COMMENT "Copying ${QTLIB} from $ to $" 170 | ) 171 | 172 | install(FILES $ DESTINATION bin) 173 | 174 | endforeach() 175 | 176 | find_package(Intl REQUIRED) 177 | get_filename_component(INTL_DIR ${Intl_LIBRARY} DIRECTORY) 178 | 179 | find_file(INTL_DLL "intl.dll" HINTS "${INTL_DIR}/../bin") # "$" "$") 180 | 181 | # copy libintl.dll 182 | add_custom_command( 183 | TARGET copydlls POST_BUILD 184 | COMMAND ${CMAKE_COMMAND} -E copy_if_different 185 | ${INTL_DLL} 186 | $ 187 | COMMENT "Copying libitnl from ${INTL_DLL} to $" 188 | ) 189 | 190 | # copy clang 191 | find_program(CLANG_EXE "clang") 192 | add_custom_command( 193 | TARGET copydlls POST_BUILD 194 | COMMAND ${CMAKE_COMMAND} -E copy_if_different 195 | ${CLANG_EXE} 196 | $ 197 | COMMENT "Copying clang from ${CLANG_EXE} to $" 198 | ) 199 | 200 | endif() 201 | 202 | install(TARGETS chigraphgui DESTINATION bin) 203 | 204 | # install desktop file and icons 205 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../org.chigraph.chigraphgui.desktop DESTINATION share/applications) 206 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/org.chigraph.chigraphgui.appdata.xml DESTINATION share/metadata) 207 | 208 | foreach(size 16 32 64 128 256 512 1024) 209 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../icons/${size}x${size}/org.chigraph.chigraphgui.png DESTINATION share/icons/hicolor/${size}x${size}/apps) 210 | endforeach() 211 | -------------------------------------------------------------------------------- /src/centraltabview.cpp: -------------------------------------------------------------------------------- 1 | #include "centraltabview.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "functionview.hpp" 13 | #include "structedit.hpp" 14 | 15 | CentralTabView::CentralTabView(QWidget* owner) : QTabWidget{owner} { 16 | auto closeAction = 17 | actionCollection()->addAction(KStandardAction::Close, QStringLiteral("close-function")); 18 | connect(closeAction, &QAction::triggered, this, [this] { closeTab(currentIndex()); }); 19 | 20 | connect(this, &QTabWidget::tabCloseRequested, this, &CentralTabView::closeTab); 21 | 22 | connect(this, &QTabWidget::currentChanged, this, [this](int idx) { 23 | // see if it's a function or struct 24 | auto wid = widget(idx); 25 | 26 | if (auto func = qobject_cast(wid)) { 27 | emit functionViewChanged(func, false); 28 | return; 29 | } 30 | if (auto str = qobject_cast(wid)) { emit structViewChanged(str, false); } 31 | }); 32 | 33 | setXMLFile("chigraphfunctiontabviewui.rc"); 34 | } 35 | 36 | void CentralTabView::selectNewFunction(chi::GraphFunction& func) { 37 | QString qualifiedFunctionName = 38 | QString::fromStdString(func.module().fullName() + ":" + func.name()); 39 | 40 | // see if it's already open 41 | auto funcViewIter = mOpenFunctions.find(qualifiedFunctionName); 42 | if (funcViewIter != mOpenFunctions.end()) { 43 | setCurrentWidget(funcViewIter->second); 44 | functionViewChanged(funcViewIter->second, false); 45 | return; 46 | } 47 | // if it's not already open, we'll have to create our own 48 | 49 | auto view = new FunctionView(func, this); 50 | int idx = addTab(view, qualifiedFunctionName); 51 | mOpenFunctions[qualifiedFunctionName] = view; 52 | setTabText(idx, qualifiedFunctionName); 53 | setTabIcon(idx, QIcon::fromTheme(QStringLiteral("code-context"))); 54 | setCurrentWidget(view); 55 | 56 | connect(view, &FunctionView::dirtied, this, [this, mod = &func.module()] { dirtied(*mod); }); 57 | connect(view, &FunctionView::functionDoubleClicked, this, &CentralTabView::selectNewFunction); 58 | 59 | functionViewChanged(view, true); 60 | } 61 | 62 | void CentralTabView::selectNewStruct(chi::GraphStruct& str) { 63 | QString qualifiedStructName = 64 | QString::fromStdString(str.module().fullName() + ":" + str.name()); 65 | 66 | auto strViewIter = mOpenStructs.find(qualifiedStructName); 67 | 68 | if (strViewIter != mOpenStructs.end()) { 69 | setCurrentWidget(strViewIter->second); 70 | structViewChanged(strViewIter->second, false); 71 | return; 72 | } 73 | 74 | auto view = new StructEdit(str, this); 75 | int idx = addTab(view, qualifiedStructName); 76 | 77 | mOpenStructs[qualifiedStructName] = view; 78 | setTabText(idx, qualifiedStructName); 79 | setTabIcon(idx, QIcon::fromTheme(QStringLiteral("code-class"))); 80 | 81 | setCurrentWidget(view); 82 | 83 | // TODO: dirtied? 84 | 85 | structViewChanged(view, true); 86 | } 87 | 88 | void CentralTabView::centerOnNode(chi::NodeInstance& inst) { 89 | // load the function 90 | selectNewFunction(inst.function()); 91 | 92 | // center on the node 93 | currentView()->centerOnNode(inst); 94 | } 95 | 96 | void CentralTabView::selectNode(chi::NodeInstance& inst) { 97 | auto view = viewFromFunction(inst.function()); 98 | 99 | if (!view) { return; } 100 | view->selectNode(inst); 101 | } 102 | 103 | void CentralTabView::refreshModule(chi::GraphModule& mod) { 104 | int currTabId = currentIndex(); 105 | 106 | // close the function views 107 | std::vector> functionNames; 108 | for (const auto& pair : mOpenFunctions) { 109 | if (&pair.second->function()->module() == &mod) { 110 | auto idx = indexOf(pair.second); 111 | functionNames.emplace_back(pair.second->function()->name(), idx); 112 | removeTab(idx); 113 | } 114 | } 115 | std::string fullName = mod.fullName(); 116 | mod.context().unloadModule(fullName); 117 | 118 | chi::ChiModule* cMod; 119 | mod.context().loadModule(fullName, &cMod); 120 | chi::GraphModule* gMod = dynamic_cast(cMod); 121 | 122 | // re-add the tabs in reverse order to keep the ids 123 | for (auto iter = functionNames.rbegin(); iter != functionNames.rend(); ++iter) { 124 | chi::GraphFunction* func = gMod->functionFromName(iter->first); 125 | QString qualifiedFunctionName = 126 | QString::fromStdString(gMod->fullName() + ":" + func->name()); 127 | auto view = new FunctionView(*func); 128 | insertTab(iter->second, view, qualifiedFunctionName); 129 | mOpenFunctions[qualifiedFunctionName] = view; 130 | 131 | connect(view, &FunctionView::dirtied, this, 132 | [this, mod = &func->module()] { dirtied(*mod); }); 133 | connect(view, &FunctionView::functionDoubleClicked, this, 134 | &CentralTabView::selectNewFunction); 135 | } 136 | 137 | setCurrentIndex(currTabId); 138 | } 139 | 140 | FunctionView* CentralTabView::viewFromFunction(chi::GraphFunction& func) { 141 | return viewFromFunctionName(func.module().fullName(), func.name()); 142 | } 143 | 144 | FunctionView* CentralTabView::viewFromFunctionName(const QString& fullName) { 145 | auto iter = mOpenFunctions.find(fullName); 146 | if (iter != mOpenFunctions.end()) { return iter->second; } 147 | return nullptr; 148 | } 149 | 150 | FunctionView* CentralTabView::viewFromFunctionName(const std::filesystem::path& mod, 151 | const std::string& function) { 152 | return viewFromFunctionName(QString::fromStdString(mod.string() + ":" + function)); 153 | } 154 | 155 | void CentralTabView::closeView(FunctionView* view) { closeTab(indexOf(view)); } 156 | void CentralTabView::closeView(StructEdit* view) { closeTab(indexOf(view)); } 157 | 158 | FunctionView* CentralTabView::currentView() { 159 | auto widget = currentWidget(); 160 | 161 | auto casted = qobject_cast(widget); 162 | 163 | if (casted == nullptr) { return nullptr; } 164 | 165 | return casted; 166 | } 167 | 168 | void CentralTabView::functionRenamed(chi::GraphFunction& func, const std::string& oldName, 169 | const std::vector& changed) { 170 | auto fullOldName = QString::fromStdString(func.module().fullName() + ":" + oldName); 171 | auto fullName = QString::fromStdString(func.module().fullName() + ":" + func.name()); 172 | 173 | // update the strcuture and rename the tab if it's open 174 | auto iter = mOpenFunctions.find(fullOldName); 175 | if (iter != mOpenFunctions.end()) { 176 | auto view = iter->second; 177 | mOpenFunctions.erase(iter); 178 | 179 | mOpenFunctions.emplace(fullName, view); 180 | 181 | // change tab text 182 | auto id = indexOf(view); 183 | if (id != -1) { setTabText(id, fullName); } 184 | } 185 | 186 | // refresh the changed nodes 187 | for (const auto node : changed) { 188 | auto view = viewFromFunction(node->function()); 189 | 190 | if (view) { view->refreshGuiForNode(*node); } 191 | } 192 | } 193 | 194 | void CentralTabView::structRenamed(chi::GraphStruct& str, const std::string& oldName, 195 | const std::vector& changed) { 196 | auto fullOldName = QString::fromStdString(str.module().fullName() + ":" + oldName); 197 | auto fullName = QString::fromStdString(str.module().fullName() + ":" + str.name()); 198 | 199 | // update the strcuture and rename the tab if it's open 200 | auto iter = mOpenStructs.find(fullOldName); 201 | if (iter != mOpenStructs.end()) { 202 | auto view = iter->second; 203 | mOpenStructs.erase(iter); 204 | 205 | mOpenStructs.emplace(fullName, view); 206 | 207 | // change tab text 208 | auto id = indexOf(view); 209 | if (id != -1) { setTabText(id, fullName); } 210 | } 211 | 212 | // refresh the changed nodes 213 | for (const auto node : changed) { 214 | auto view = viewFromFunction(node->function()); 215 | 216 | if (view) { view->refreshGuiForNode(*node); } 217 | } 218 | } 219 | 220 | void CentralTabView::functionDeleted(chi::GraphModule& mod, const std::string& funcName) { 221 | auto iter = mOpenFunctions.find(QString::fromStdString(mod.fullName() + ":" + funcName)); 222 | if (iter != mOpenFunctions.end()) { 223 | auto view = iter->second; 224 | closeView(view); 225 | } 226 | } 227 | 228 | void CentralTabView::structDeleted(chi::GraphModule& mod, const std::string& strName) { 229 | auto iter = mOpenStructs.find(QString::fromStdString(mod.fullName() + ":" + strName)); 230 | if (iter != mOpenStructs.end()) { 231 | auto view = iter->second; 232 | closeView(view); 233 | } 234 | 235 | return; 236 | } 237 | 238 | void CentralTabView::closeTab(int idx) { 239 | auto funcIter = std::find_if(mOpenFunctions.begin(), mOpenFunctions.end(), 240 | [this, idx](auto& p) { return p.second == this->widget(idx); }); 241 | 242 | if (funcIter != mOpenFunctions.end()) { mOpenFunctions.erase(funcIter); } 243 | auto strIter = std::find_if(mOpenStructs.begin(), mOpenStructs.end(), 244 | [this, idx](auto& p) { return p.second == this->widget(idx); }); 245 | if (strIter != mOpenStructs.end()) { mOpenStructs.erase(strIter); } 246 | assert((funcIter != mOpenFunctions.end() || strIter != mOpenStructs.end()) && 247 | "Internal error: a tab index was not in mOpenFunctions or mOpenStructs"); 248 | 249 | removeTab(idx); 250 | } 251 | -------------------------------------------------------------------------------- /src/centraltabview.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_FUNCTION_TAB_VIEW_HPP 4 | #define CHIGRAPHGUI_FUNCTION_TAB_VIEW_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class FunctionView; 14 | class StructEdit; 15 | 16 | class CentralTabView : public QTabWidget, public KXMLGUIClient { 17 | Q_OBJECT 18 | public: 19 | CentralTabView(QWidget* parent = nullptr); 20 | 21 | void selectNewFunction(chi::GraphFunction& func); 22 | void selectNewStruct(chi::GraphStruct& str); 23 | void centerOnNode(chi::NodeInstance& inst); 24 | void selectNode(chi::NodeInstance& inst); 25 | 26 | // refresh all the functions in the module 27 | void refreshModule(chi::GraphModule& mod); 28 | 29 | FunctionView* viewFromFunction(chi::GraphFunction& func); 30 | FunctionView* viewFromFunctionName(const QString& fullName); 31 | FunctionView* viewFromFunctionName(const std::filesystem::path& mod, 32 | const std::string& function); 33 | 34 | StructEdit* viewFromStruct(chi::GraphStruct& str); 35 | StructEdit* viewFromStructName(const QString& fullName); 36 | StructEdit* viewFromStructName(const std::filesystem::path& mod, const std::string& module); 37 | 38 | void closeView(FunctionView* view); 39 | void closeView(StructEdit* view); 40 | 41 | FunctionView* currentView(); 42 | 43 | signals: 44 | void dirtied(chi::GraphModule& mod); 45 | void functionViewChanged(FunctionView* func, bool newlyOpened); 46 | void structViewChanged(StructEdit* func, bool newlyOpened); 47 | 48 | public slots: 49 | void functionRenamed(chi::GraphFunction& func, const std::string& oldName, 50 | const std::vector& changed); 51 | void structRenamed(chi::GraphStruct& str, const std::string& oldName, 52 | const std::vector& changed); 53 | 54 | void functionDeleted(chi::GraphModule& mod, const std::string& funcName); 55 | void structDeleted(chi::GraphModule& mod, const std::string& strName); 56 | 57 | private: 58 | void closeTab(int idx); 59 | 60 | std::map mOpenFunctions; 61 | std::map mOpenStructs; 62 | }; 63 | 64 | #endif // CHIGRAPHGUI_FUNCTION_TAB_VIEW_HPP 65 | -------------------------------------------------------------------------------- /src/chigraphfunctiondetailsui.rc: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /src/chigraphfunctiontabviewui.rc: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | View 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/chigraphgui.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | chigraphguiui.rc 5 | chigraphmodulebrowserui.rc 6 | chigraphfunctiondetailsui.rc 7 | chigraphfunctiontabviewui.rc 8 | 9 | 10 | ../icons/128x128/org.chigraph.chigraphgui.png 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/chigraphguiui.rc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Process 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Main Toolbar 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/chigraphmodulebrowserui.rc: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/chigraphnodemodel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHI_GUI_CHIGNODEGUI_HPP 4 | #define CHI_GUI_CHIGNODEGUI_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | class ChigraphFlowSceneModel : public QtNodes::FlowSceneModel { 23 | Q_OBJECT 24 | public: 25 | ChigraphFlowSceneModel(chi::GraphFunction& func); 26 | void updateValidation(); 27 | 28 | QStringList modelRegistry() const override; 29 | 30 | QString nodeTypeCategory(QString const& name) const override; 31 | bool getTypeConvertable(QtNodes::TypeConverterId const& id) const override; 32 | 33 | // Retrieval functions 34 | ////////////////////// 35 | 36 | QtNodes::NodeIndex nodeIndex(const chi::NodeInstance& node) const; 37 | 38 | QList nodeUUids() const override; 39 | QtNodes::NodeIndex nodeIndex(const QUuid& ID) const override; 40 | QString nodeTypeIdentifier(QtNodes::NodeIndex const& index) const override; 41 | QString nodeCaption(QtNodes::NodeIndex const& index) const override; 42 | QPointF nodeLocation(QtNodes::NodeIndex const& index) const override; 43 | QWidget* nodeWidget(QtNodes::NodeIndex const& index) const override; 44 | bool nodeResizable(QtNodes::NodeIndex const& index) const override; 45 | QtNodes::NodeValidationState nodeValidationState( 46 | QtNodes::NodeIndex const& index) const override; 47 | 48 | /// Get the validation error/warning 49 | QString nodeValidationMessage(QtNodes::NodeIndex const& index) const override; 50 | 51 | /// Get the painter delegate 52 | QtNodes::NodePainterDelegate* nodePainterDelegate( 53 | QtNodes::NodeIndex const& index) const override; 54 | 55 | /// Get the count of DataPorts 56 | unsigned int nodePortCount(QtNodes::NodeIndex const& index, 57 | QtNodes::PortType portType) const override; 58 | 59 | /// Get the port caption 60 | QString nodePortCaption(QtNodes::NodeIndex const& index, QtNodes::PortIndex portID, 61 | QtNodes::PortType portType) const override; 62 | 63 | /// Get the port data type 64 | QtNodes::NodeDataType nodePortDataType(QtNodes::NodeIndex const& index, 65 | QtNodes::PortIndex portID, 66 | QtNodes::PortType portType) const override; 67 | 68 | /// Port Policy 69 | QtNodes::ConnectionPolicy nodePortConnectionPolicy(QtNodes::NodeIndex const& index, 70 | QtNodes::PortIndex portID, 71 | QtNodes::PortType portType) const override; 72 | 73 | /// Get a connection at a port 74 | std::vector> nodePortConnections( 75 | QtNodes::NodeIndex const& index, QtNodes::PortIndex portID, 76 | QtNodes::PortType portType) const override; 77 | 78 | // Mutation functions 79 | ///////////////////// 80 | 81 | /// Remove a connection 82 | bool removeConnection(QtNodes::NodeIndex const& leftNode, QtNodes::PortIndex leftPortID, 83 | QtNodes::NodeIndex const& rightNode, 84 | QtNodes::PortIndex rightPortID) override; 85 | 86 | /// Add a connection 87 | bool addConnection(QtNodes::NodeIndex const& leftNode, QtNodes::PortIndex leftPortID, 88 | QtNodes::NodeIndex const& rightNode, 89 | QtNodes::PortIndex rightPortID) override; 90 | 91 | /// Remove a node 92 | bool removeNode(QtNodes::NodeIndex const& index) override; 93 | 94 | /// Add a -- return {} if it fails 95 | QUuid addNode(QString const& typeID, QPointF const& pos) override; 96 | 97 | /// Move a node to a new location 98 | bool moveNode(QtNodes::NodeIndex const& index, QPointF newLocation) override; 99 | 100 | void connectionHovered(QtNodes::NodeIndex const& lhs, QtNodes::PortIndex lPortIndex, 101 | QtNodes::NodeIndex const& rhs, QtNodes::PortIndex rPortIndex, 102 | QPoint const& pos, bool entered) override { 103 | emit connectionWasHovered(lhs, lPortIndex, rhs, rPortIndex, pos, entered); 104 | } 105 | 106 | void nodeHovered(QtNodes::NodeIndex const& index, QPoint const& pos, bool entered) override { 107 | emit nodeWasHovered(index, pos, entered); 108 | } 109 | 110 | void nodeDoubleClicked(QtNodes::NodeIndex const& index, QPoint const& pos) override { 111 | emit nodeWasDoubleClicked(index, pos); 112 | } 113 | 114 | signals: 115 | 116 | void connectionWasHovered(QtNodes::NodeIndex const& lhs, QtNodes::PortIndex lPortIndex, 117 | QtNodes::NodeIndex const& rhs, QtNodes::PortIndex rPortIndex, 118 | QPoint const& pos, bool entered); 119 | void nodeWasHovered(QtNodes::NodeIndex const& index, QPoint const& pos, bool entered); 120 | void nodeWasDoubleClicked(QtNodes::NodeIndex const& index, QPoint const& pos); 121 | 122 | private: 123 | QWidget* createEmbeddedWidget(chi::NodeInstance& inst); 124 | 125 | chi::GraphFunction* mFunc; 126 | chi::Result mValidation; 127 | std::unordered_map mEmbeddedWidgets; 128 | }; 129 | 130 | #endif // CHI_GUI_CHIGNODEGUI_HPP 131 | -------------------------------------------------------------------------------- /src/chigraphplugin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_CHIGRAPH_PLUGIN 4 | #define CHIGRAPHGUI_CHIGRAPH_PLUGIN 5 | 6 | #include 7 | #include 8 | 9 | #include "toolview.hpp" 10 | 11 | class ChigraphPlugin : public KXMLGUIClient { 12 | public: 13 | virtual ~ChigraphPlugin() = default; 14 | 15 | virtual QVector toolViews() = 0; 16 | }; 17 | 18 | // tell qt that it's a thing 19 | #define ChigraphPlugin_iid "org.chigraph.chigraphgui.ChigraphPlugin" 20 | Q_DECLARE_INTERFACE(ChigraphPlugin, ChigraphPlugin_iid) 21 | 22 | #endif // CHIGRAPHGUI_CHIGRAPH_PLUGIN 23 | -------------------------------------------------------------------------------- /src/chiitemselectiondialog.cpp: -------------------------------------------------------------------------------- 1 | #include "chiitemselectiondialog.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | ChiItemSelectionDialog::ChiItemSelectionDialog(chi::Context& ctx, std::filesystem::path* toFill, 10 | WorkspaceTree::eType type, QWidget* parent) 11 | : QDialog{parent}, mType{type}, mToFill{toFill} { 12 | assert(toFill != nullptr); 13 | 14 | auto layout = new QVBoxLayout; 15 | setLayout(layout); 16 | 17 | mTreeView = new QTreeView; 18 | layout->addWidget(mTreeView); 19 | 20 | auto filter = [&] { 21 | switch (mType) { 22 | case WorkspaceTree::MODULE: return ModuleTreeModel::Modules; 23 | case WorkspaceTree::STRUCT: return ModuleTreeModel::Structs; 24 | case WorkspaceTree::FUNCTION: return ModuleTreeModel::Functions; 25 | case WorkspaceTree::FOLDER: return ModuleTreeModel::Folders; 26 | } 27 | // panic as a defult 28 | Q_ASSERT(false); 29 | return ModuleTreeModel::All; 30 | }(); 31 | 32 | // get model and set it 33 | mModel = ModuleTreeModel::createFromContext(ctx, filter); 34 | mTreeView->setModel(mModel.get()); 35 | 36 | mTreeView->setAnimated(true); 37 | mTreeView->setSortingEnabled(true); 38 | mTreeView->header()->close(); 39 | 40 | auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 41 | connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); 42 | connect(buttonBox, &QDialogButtonBox::accepted, this, 43 | [this] { tryAccept(mTreeView->currentIndex()); }); 44 | 45 | layout->addWidget(buttonBox); 46 | 47 | connect(mTreeView, &QTreeView::doubleClicked, this, &ChiItemSelectionDialog::tryAccept); 48 | } 49 | 50 | void ChiItemSelectionDialog::setCurrentItem(const std::filesystem::path& newItem) { 51 | auto index = mModel->indexFromName(newItem, mType); 52 | if (index.isValid()) { 53 | mTreeView->scrollTo(index); 54 | mTreeView->setCurrentIndex(index); 55 | } 56 | } 57 | 58 | std::filesystem::path ChiItemSelectionDialog::getItem( 59 | QWidget* parent, chi::Context& ctx, const QString& title, WorkspaceTree::eType type, 60 | const std::filesystem::path& startWithSelection) { 61 | std::filesystem::path ret; 62 | auto dialog = new ChiItemSelectionDialog(ctx, &ret, type, parent); 63 | dialog->setWindowTitle(title); 64 | dialog->setCurrentItem(startWithSelection); 65 | 66 | dialog->exec(); 67 | 68 | return ret; 69 | } 70 | 71 | void ChiItemSelectionDialog::tryAccept(const QModelIndex& index) { 72 | if (!index.isValid()) { return; } 73 | 74 | auto item = static_cast(index.internalPointer()); 75 | 76 | // make sure it's a folder and it isn't the src folder 77 | if (mType == item->type && item->parent->parent != nullptr) { 78 | *mToFill = item->fullName(); 79 | accept(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/chiitemselectiondialog.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_CHI_ITEM_SELECTION_DIALOG_HPP 4 | #define CHIGRAPHGUI_CHI_ITEM_SELECTION_DIALOG_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "moduletreemodel.hpp" 11 | 12 | class QTreeView; 13 | 14 | class ChiItemSelectionDialog : public QDialog { 15 | public: 16 | ChiItemSelectionDialog(chi::Context& ctx, std::filesystem::path* toFill, 17 | WorkspaceTree::eType type, QWidget* parent = nullptr); 18 | 19 | void setCurrentItem(const std::filesystem::path& newItem); 20 | 21 | static std::filesystem::path getItem(QWidget* parent, chi::Context& ctx, const QString& title, 22 | WorkspaceTree::eType type, 23 | const std::filesystem::path& startWithSelection = {}); 24 | 25 | private slots: 26 | void tryAccept(const QModelIndex& index); 27 | 28 | private: 29 | WorkspaceTree::eType mType; 30 | 31 | std::filesystem::path* mToFill; 32 | QTreeView* mTreeView; 33 | std::unique_ptr mModel; 34 | }; 35 | 36 | #endif // CHIGRAPHGUI_CHI_ITEM_SELECTION_DIALOG_HPP 37 | -------------------------------------------------------------------------------- /src/chiitemselectwidget.cpp: -------------------------------------------------------------------------------- 1 | #include "chiitemselectwidget.hpp" 2 | 3 | #include 4 | 5 | #include "chiitemselectiondialog.hpp" 6 | 7 | ChiItemSelectWidget::ChiItemSelectWidget(chi::Context& ctx, WorkspaceTree::eType type) { 8 | connect(this, &QPushButton::clicked, this, [this, &ctx, type](bool) { 9 | auto modName = 10 | ChiItemSelectionDialog::getItem(this, ctx, i18n("Select Item"), type, item()); 11 | 12 | if (modName.empty()) { return; } 13 | 14 | setItem(modName); 15 | }); 16 | 17 | setIcon(ModuleTreeModel::iconForItemType(type)); 18 | } 19 | 20 | std::filesystem::path ChiItemSelectWidget::item() const { return mData; } 21 | 22 | void ChiItemSelectWidget::setItem(const std::filesystem::path& newItem) { 23 | setText(QString::fromStdString(newItem.string())); 24 | mData = newItem; 25 | 26 | emit itemChanged(newItem); 27 | } 28 | -------------------------------------------------------------------------------- /src/chiitemselectwidget.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_CHI_ITEM_SELECT_WIDGET_HPP 4 | #define CHIGRAPHGUI_CHI_ITEM_SELECT_WIDGET_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "moduletreemodel.hpp" 11 | 12 | class ChiItemSelectWidget : public QPushButton { 13 | Q_OBJECT 14 | public: 15 | ChiItemSelectWidget(chi::Context& ctx, WorkspaceTree::eType type); 16 | 17 | void setItem(const std::filesystem::path& newItem); 18 | 19 | std::filesystem::path item() const; 20 | 21 | private: 22 | std::filesystem::path mData; 23 | signals: 24 | void itemChanged(const std::filesystem::path& itemName); 25 | }; 26 | 27 | #endif // CHIGRAPHGUI_CHI_ITEM_SELECT_WIDGET_HPP 28 | -------------------------------------------------------------------------------- /src/debugger/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(CMAKE_AUTOMOC ON) 3 | set(CMAKE_AUTORCC ON) 4 | 5 | set(DEBUGGER_PRIVATE_SRCS 6 | debuggerplugin.cpp 7 | debuggerworkerthread.cpp 8 | breakpointview.cpp 9 | variableview.cpp 10 | ) 11 | 12 | set(DEBUGGER_RESOURCE_FILES 13 | chigraphdebugger.qrc 14 | ) 15 | 16 | set(DEBUGGER_PUBLIC_SRCS 17 | debuggerplugin.hpp 18 | debuggerworkerthread.hpp 19 | breakpointview.hpp 20 | variableview.hpp 21 | ) 22 | 23 | set(CMAKE_CXX_STANDARD 17) 24 | 25 | add_library(chigraphguidebugger STATIC ${DEBUGGER_PRIVATE_SRCS} ${DEBUGGER_PUBLIC_SRCS} ${DEBUGGER_RESOURCE_FILES}) 26 | target_link_libraries(chigraphguidebugger 27 | PUBLIC 28 | Qt5::Widgets 29 | KF5::I18n 30 | KF5::XmlGui 31 | KF5::TextEditor 32 | 33 | nodes 34 | 35 | chigraphdebugger 36 | ) 37 | 38 | target_compile_definitions(chigraphguidebugger 39 | PUBLIC 40 | -DCHIGRAPH_WITH_DEBUGGER 41 | PRIVATE 42 | -DQT_STATICPLUGIN 43 | ) 44 | -------------------------------------------------------------------------------- /src/debugger/breakpointview.cpp: -------------------------------------------------------------------------------- 1 | #include "breakpointview.hpp" 2 | 3 | #include 4 | #include 5 | 6 | #include "../centraltabview.hpp" 7 | #include "../mainwindow.hpp" 8 | 9 | class BreakpointView::BreakpointItem : public QTreeWidgetItem { 10 | public: 11 | BreakpointItem(chi::NodeInstance& inst) : mInst{&inst} { 12 | setText(0, QString::fromStdString(inst.function().qualifiedName())); 13 | setText(1, QString::fromStdString(inst.stringId())); 14 | setText(2, QString::number(chi::lineNumberFromNode(inst))); 15 | } 16 | 17 | chi::NodeInstance& instance() const { return *mInst; } 18 | 19 | private: 20 | chi::NodeInstance* mInst; 21 | }; 22 | 23 | BreakpointView::BreakpointView() { 24 | setHeaderLabels(QStringList() << i18n("Function") << i18n("ID") << i18n("\"Line\"")); 25 | 26 | connect(this, &QTreeWidget::itemDoubleClicked, this, [](QTreeWidgetItem* item) { 27 | auto casted = dynamic_cast(item); 28 | 29 | if (casted != nullptr) { 30 | MainWindow::instance()->tabView().centerOnNode(casted->instance()); 31 | MainWindow::instance()->tabView().selectNode(casted->instance()); 32 | } 33 | }); 34 | } 35 | 36 | void BreakpointView::addBreakpoint(chi::NodeInstance& inst) { 37 | for (int i = 0; i < topLevelItemCount(); ++i) { 38 | if (&static_cast(topLevelItem(i))->instance() == &inst) return; 39 | } 40 | auto item = new BreakpointItem(inst); 41 | mBreakpoints.emplace(&inst, item); 42 | addTopLevelItem(item); 43 | } 44 | 45 | bool BreakpointView::removeBreakpoint(chi::NodeInstance& inst) { 46 | auto iter = mBreakpoints.find(&inst); 47 | if (iter == mBreakpoints.end()) { return false; } 48 | 49 | removeItemWidget(iter->second, 0); 50 | mBreakpoints.erase(iter); 51 | 52 | return true; 53 | } 54 | -------------------------------------------------------------------------------- /src/debugger/breakpointview.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CHIGRAPHGUI_DEBUGGER_BREAKPOINT_VIEW_HPP 2 | #define CHIGRAPHGUI_DEBUGGER_BREAKPOINT_VIEW_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../toolview.hpp" 9 | 10 | class BreakpointView : public QTreeWidget, public ToolView { 11 | class BreakpointItem; 12 | 13 | public: 14 | BreakpointView(); 15 | 16 | void addBreakpoint(chi::NodeInstance& inst); 17 | 18 | /// Remove a breakpoint 19 | /// \return true if one was removed, false if it wasn't found 20 | bool removeBreakpoint(chi::NodeInstance& inst); 21 | 22 | const std::unordered_map& breakpoints() { 23 | return mBreakpoints; 24 | } 25 | 26 | private: 27 | // ToolView interface 28 | QWidget* toolView() override { return this; } 29 | Qt::DockWidgetArea defaultArea() const override { return Qt::BottomDockWidgetArea; } 30 | QString label() override { return i18n("Breakpoints"); } 31 | QString dockObjectName() override { return QStringLiteral("breakpoints"); } 32 | 33 | std::unordered_map mBreakpoints; 34 | }; 35 | 36 | #endif // CHIGRAPHGUI_DEBUGGER_BREAKPOINT_VIEW_HPP 37 | -------------------------------------------------------------------------------- /src/debugger/chigraphdebugger.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | chigraphguidebuggerui.rc 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/debugger/chigraphguidebuggerui.rc: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Debug 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | Debugger Toolbar 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/debugger/currentnodedecorator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_DEBUGGER_CURRENT_NODE_DECORATOR_HPP 4 | #define CHIGRAPHGUI_DEBUGGER_CURRENT_NODE_DECORATOR_HPP 5 | 6 | #include 7 | #include 8 | 9 | class CurrentNodeDecorator : public QtNodes::NodePainterDelegate { 10 | void paint(QPainter* painter, QtNodes::NodeGeometry const& geometry, 11 | QtNodes::NodeIndex const& index) override { 12 | painter->drawRect(QRect(geometry.width() / 2, 0, 10, 10)); 13 | } 14 | }; 15 | 16 | #endif // CHIGRAPHGUI_DEBUGGER_CURRENT_NODE_DECORATOR_HPP 17 | -------------------------------------------------------------------------------- /src/debugger/debugger.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /src/debugger/debuggerplugin.cpp: -------------------------------------------------------------------------------- 1 | #include "debuggerplugin.hpp" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../centraltabview.hpp" 17 | #include "../chigraphnodemodel.hpp" 18 | #include "../mainwindow.hpp" 19 | #include "currentnodedecorator.hpp" 20 | 21 | DebuggerPlugin::DebuggerPlugin() { 22 | Q_INIT_RESOURCE(chigraphdebugger); 23 | 24 | qRegisterMetaType("lldb::SBEvent"); 25 | 26 | debugAction = actionCollection()->addAction( 27 | QStringLiteral("start-debug"), 28 | new QAction(QIcon::fromTheme(QStringLiteral("debug-run")), i18n("Debug"), nullptr)); 29 | actionCollection()->setDefaultShortcut(debugAction, Qt::Key_F8); 30 | connect(debugAction, &QAction::triggered, this, &DebuggerPlugin::debugStart); 31 | 32 | toggleBreakpointAction = 33 | actionCollection()->addAction(QStringLiteral("toggle-breakpoint"), 34 | new QAction(QIcon::fromTheme(QStringLiteral("draw-donut")), 35 | i18n("Toggle Breakpoint"), nullptr)); 36 | actionCollection()->setDefaultShortcut(toggleBreakpointAction, Qt::Key_F9); 37 | connect(toggleBreakpointAction, &QAction::triggered, this, &DebuggerPlugin::toggleBreakpoint); 38 | 39 | stepAction = actionCollection()->addAction( 40 | QStringLiteral("debug-step"), 41 | new QAction(QIcon::fromTheme(QStringLiteral("debug-step-over")), i18n("Step Over"), 42 | nullptr)); 43 | actionCollection()->setDefaultShortcut(stepAction, Qt::Key_F10); 44 | 45 | stepOutAction = actionCollection()->addAction( 46 | QStringLiteral("debug-step-out"), 47 | new QAction(QIcon::fromTheme(QStringLiteral("debug-step-out")), i18n("Step Out"), nullptr)); 48 | actionCollection()->setDefaultShortcut(stepOutAction, Qt::Key_F12); 49 | 50 | stepInAction = actionCollection()->addAction( 51 | QStringLiteral("debug-step-into"), 52 | new QAction(QIcon::fromTheme(QStringLiteral("debug-step-into")), i18n("Step Into"), 53 | nullptr)); 54 | actionCollection()->setDefaultShortcut(stepInAction, Qt::Key_F11); 55 | 56 | continueAction = actionCollection()->addAction( 57 | QStringLiteral("debug-continue"), 58 | new QAction(QIcon::fromTheme(QStringLiteral("media-playback-start")), i18n("Continue"), 59 | nullptr)); 60 | actionCollection()->setDefaultShortcut(continueAction, Qt::Key_F5); 61 | connect(continueAction, &QAction::triggered, this, &DebuggerPlugin::continueDebugging); 62 | 63 | mBreakpointView = new BreakpointView(); 64 | mVariableView = new VariableView(); 65 | 66 | connect(&MainWindow::instance()->tabView(), &CentralTabView::functionViewChanged, this, 67 | [this](FunctionView* view, bool isNew) { 68 | // only connect to it if it was just opened 69 | if (!isNew) { return; } 70 | 71 | connect(&view->model(), &ChigraphFlowSceneModel::connectionWasHovered, this, 72 | [this](QtNodes::NodeIndex const& lhs, QtNodes::PortIndex lPortIndex, 73 | QtNodes::NodeIndex const& rhs, QtNodes::PortIndex /*rPortIndex*/, 74 | QPoint const& pos, bool /*entered*/) { 75 | // only print value when it's stopped 76 | if (!stopped()) { return; } 77 | 78 | auto leftChiNode = 79 | reinterpret_cast(lhs.internalPointer()); 80 | 81 | Q_ASSERT(lPortIndex >= 0); 82 | 83 | // if it's an exec output, then return 84 | if (!leftChiNode->type().pure() && 85 | (size_t)lPortIndex <= leftChiNode->outputExecConnections.size()) { 86 | return; 87 | } 88 | 89 | auto dataConnID = 90 | leftChiNode->type().pure() 91 | ? lPortIndex 92 | : lPortIndex - leftChiNode->outputExecConnections.size(); 93 | 94 | // get the LLDB value 95 | auto value = mDebugger->inspectNodeOutput(*leftChiNode, dataConnID); 96 | if (!value.IsValid()) { return; } 97 | 98 | // display it 99 | QToolTip::showText(pos, QString::fromLatin1(value.GetValue()) + " : " + 100 | QString::fromLatin1(value.GetSummary())); 101 | }); 102 | }); 103 | 104 | setXMLFile("chigraphguidebuggerui.rc"); 105 | } 106 | 107 | void DebuggerPlugin::toggleBreakpoint() { 108 | auto currentView = MainWindow::instance()->tabView().currentView(); 109 | 110 | if (currentView == nullptr) { return; } 111 | 112 | for (auto node : currentView->selectedNodes()) { mBreakpointView->addBreakpoint(*node); } 113 | } 114 | 115 | void DebuggerPlugin::debugStart() { 116 | std::filesystem::path chiPath = 117 | std::filesystem::path(QApplication::applicationFilePath().toStdString()).parent_path() / 118 | "chi"; 119 | #ifdef _WIN32 120 | chiPath.replace_extension(".exe"); 121 | #endif 122 | 123 | MainWindow* window = MainWindow::instance(); 124 | 125 | mDebugger = nullptr; 126 | 127 | // delete it 128 | if (mThread) { mThread->wait(); } 129 | mEventListener = nullptr; 130 | 131 | auto currentConfig = window->launchManager().currentConfiguration(); 132 | if (!currentConfig.valid()) { return; } 133 | 134 | auto pair = window->loadModule(currentConfig.module()); 135 | 136 | if (!pair.first || !pair.second) { 137 | KMessageBox::detailedError(window, i18n("Failed to load module"), 138 | QString::fromStdString(pair.first.dump()), i18n("run: error")); 139 | return; 140 | } 141 | 142 | // TODO: this really really needs a fix 143 | mDebugger = std::make_shared(chiPath.string().c_str(), *pair.second); 144 | 145 | mThread = new QThread; 146 | mEventListener = std::make_unique(mDebugger); 147 | mEventListener->moveToThread(mThread); 148 | 149 | connect(mThread, &QThread::started, mEventListener.get(), &DebuggerWorkerThread::process); 150 | connect(mEventListener.get(), &DebuggerWorkerThread::eventOccured, this, 151 | [this, window](lldb::SBEvent ev) { 152 | if (lldb::SBProcess::GetStateFromEvent(ev) == lldb::eStateStopped) { 153 | variableView().setDisabled(false); 154 | mStopped = true; 155 | variableView().setFrame( 156 | mDebugger->lldbProcess().GetSelectedThread().GetSelectedFrame()); 157 | 158 | // get the node 159 | auto node = mDebugger->nodeFromFrame( 160 | mDebugger->lldbProcess().GetSelectedThread().GetSelectedFrame()); 161 | if (node == nullptr) { return; } 162 | 163 | window->tabView().centerOnNode(*node); 164 | 165 | } else { 166 | variableView().setDisabled(true); 167 | mStopped = false; 168 | } 169 | }); 170 | 171 | mThread->start(); 172 | 173 | // set breakpoints 174 | for (const auto& bp : breakpointView().breakpoints()) { mDebugger->setBreakpoint(*bp.first); } 175 | 176 | auto res = mDebugger->start(); 177 | if (!res) { 178 | qDebug() << QString::fromStdString(res.dump()); 179 | return; 180 | } 181 | } 182 | 183 | void DebuggerPlugin::continueDebugging() { 184 | if (mDebugger != nullptr) { mDebugger->processContinue(); } 185 | } 186 | -------------------------------------------------------------------------------- /src/debugger/debuggerplugin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_DEBUGGER_DEBUGGER_PLUGIN_HPP 4 | #define CHIGRAPHGUI_DEBUGGER_DEBUGGER_PLUGIN_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "../chigraphplugin.hpp" 11 | #include "breakpointview.hpp" 12 | #include "debuggerworkerthread.hpp" 13 | #include "variableview.hpp" 14 | 15 | class DebuggerPlugin : public QObject, public ChigraphPlugin { 16 | Q_OBJECT 17 | Q_PLUGIN_METADATA(IID ChigraphPlugin_iid FILE "debugger.json") 18 | Q_INTERFACES(ChigraphPlugin) 19 | 20 | public: 21 | DebuggerPlugin(); 22 | 23 | BreakpointView& breakpointView() { return *mBreakpointView; } 24 | VariableView& variableView() { return *mVariableView; } 25 | 26 | bool stopped() const { return mStopped; } 27 | 28 | private slots: 29 | void toggleBreakpoint(); 30 | void debugStart(); 31 | void continueDebugging(); 32 | 33 | private: 34 | // ChigraphPlugin interface 35 | QVector toolViews() override { 36 | return QVector({mBreakpointView, mVariableView}); 37 | } 38 | 39 | void hoverOverConnection(chi::NodeInstance& inst, int connID); 40 | 41 | bool mStopped = false; 42 | 43 | BreakpointView* mBreakpointView; 44 | VariableView* mVariableView; 45 | 46 | QAction* toggleBreakpointAction; 47 | QAction* debugAction; 48 | QAction* stepAction; 49 | QAction* stepInAction; 50 | QAction* stepOutAction; 51 | QAction* continueAction; 52 | 53 | std::shared_ptr mDebugger; 54 | std::unique_ptr mEventListener; 55 | QThread* mThread = nullptr; 56 | 57 | QtNodes::NodePainterDelegate* mCurrentNodeDecorator = nullptr; 58 | chi::NodeInstance* mCurrentNode = nullptr; 59 | }; 60 | 61 | #endif // CHIGRAPHGUI_DEBUGGER_DEBUGGER_PLUGIN_HPP 62 | -------------------------------------------------------------------------------- /src/debugger/debuggerworkerthread.cpp: -------------------------------------------------------------------------------- 1 | #include "debuggerworkerthread.hpp" 2 | 3 | Q_DECLARE_METATYPE(lldb::SBEvent) 4 | 5 | DebuggerWorkerThread::DebuggerWorkerThread(std::shared_ptr dbg) 6 | : mDebugger(std::move(dbg)) {} 7 | 8 | void DebuggerWorkerThread::process() { 9 | lldb::SBEvent ev; 10 | while (true) { 11 | // lock the listener 12 | auto strongPtr = mDebugger.lock(); 13 | if (strongPtr == nullptr) { return; } 14 | auto listener = strongPtr->lldbDebugger().GetListener(); 15 | 16 | listener.WaitForEvent(1, ev); 17 | if (ev.IsValid()) { eventOccured(ev); } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/debugger/debuggerworkerthread.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_DEBUGGER_DEBUGGER_WORKER_THREAD_HPP 4 | #define CHIGRAPHGUI_DEBUGGER_DEBUGGER_WORKER_THREAD_HPP 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | class DebuggerWorkerThread : public QObject { 12 | Q_OBJECT 13 | 14 | public: 15 | DebuggerWorkerThread(std::shared_ptr dbg); 16 | 17 | public slots: 18 | void process(); 19 | 20 | signals: 21 | 22 | void eventOccured(lldb::SBEvent ev); 23 | 24 | private: 25 | std::weak_ptr mDebugger; 26 | }; 27 | 28 | #endif // CHIGRAPHGUI_DEBUGGER_DEBUGGER_WORKER_THREAD_HPP 29 | -------------------------------------------------------------------------------- /src/debugger/variableview.cpp: -------------------------------------------------------------------------------- 1 | #include "variableview.hpp" 2 | 3 | #include 4 | 5 | VariableView::VariableView() { 6 | setHeaderLabels(QStringList() << i18n("Name") << i18n("Type") << i18n("Summary") 7 | << i18n("Value") << i18n("Obj Desc")); 8 | 9 | setDisabled(true); 10 | } 11 | 12 | void VariableView::setFrame(lldb::SBFrame frame) { 13 | clear(); 14 | 15 | auto vars = frame.GetVariables(true, // args 16 | true, // locals 17 | true, // statics 18 | true // in scope only 19 | ); 20 | 21 | for (uint32_t idx = 0; idx < vars.GetSize(); ++idx) { 22 | auto val = vars.GetValueAtIndex(idx); 23 | 24 | auto item = new QTreeWidgetItem(QStringList() << val.GetName() << val.GetDisplayTypeName() 25 | << val.GetSummary() << val.GetValue() 26 | << val.GetObjectDescription()); 27 | 28 | insertTopLevelItem(0, item); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/debugger/variableview.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_DEBUGGER_VARIABLE_VIEW_HPP 4 | #define CHIGRAPHGUI_DEBUGGER_VARIABLE_VIEW_HPP 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include "../toolview.hpp" 12 | 13 | class VariableView : public QTreeWidget, public ToolView { 14 | public: 15 | VariableView(); 16 | 17 | void setFrame(lldb::SBFrame frame); 18 | 19 | private: 20 | // ToolView interface 21 | QWidget* toolView() override { return this; } 22 | Qt::DockWidgetArea defaultArea() const override { return Qt::LeftDockWidgetArea; } 23 | QString label() override { return i18n("Variables"); } 24 | QString dockObjectName() override { return QStringLiteral("variable-view"); } 25 | }; 26 | 27 | #endif // CHIGRAPHGUI_DEBUGGER_VARIABLE_VIEW_HPP 28 | -------------------------------------------------------------------------------- /src/execparamlistwidget.cpp: -------------------------------------------------------------------------------- 1 | #include "execparamlistwidget.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "functionview.hpp" 12 | 13 | // namespace { 14 | // 15 | // QStringList createTypeOptions(const chi::GraphModule& mod) { 16 | // QStringList ret; 17 | // 18 | // // add the module 19 | // for (const auto& ty : mod.typeNames()) { 20 | // ret << QString::fromStdString(mod.fullName() + ":" + ty); 21 | // } 22 | // 23 | // // and its dependencies 24 | // for (auto dep : mod.dependencies()) { 25 | // auto depMod = mod.context().moduleByFullName(dep); 26 | // for (const auto& type : depMod->typeNames()) { 27 | // ret << QString::fromStdString(depMod->fullName() + ":" + type); 28 | // } 29 | // } 30 | // return ret; 31 | // } 32 | // 33 | // } // anon namespace 34 | 35 | ExecParamListWidget::ExecParamListWidget(QWidget* parent) : QWidget(parent) {} 36 | 37 | void ExecParamListWidget::setFunction(FunctionView* func, Type ty) { 38 | mFunc = func; 39 | mType = ty; 40 | 41 | if (layout()) { deleteLayout(layout()); } 42 | 43 | auto layout = new QGridLayout; 44 | setLayout(layout); 45 | 46 | // populate it 47 | auto& typeVec = 48 | ty == Input ? mFunc->function()->execInputs() : mFunc->function()->execOutputs(); 49 | 50 | auto id = 0; 51 | for (const auto& param : typeVec) { 52 | auto edit = new QLineEdit; 53 | edit->setText(QString::fromStdString(param)); 54 | connect(edit, &QLineEdit::textChanged, this, [this, id](const QString& newText) { 55 | if (mType == Input) { 56 | mFunc->function()->renameExecInput(id, newText.toStdString()); 57 | refreshEntry(); 58 | dirtied(); 59 | } else { 60 | mFunc->function()->renameExecOutput(id, newText.toStdString()); 61 | refreshExits(); 62 | dirtied(); 63 | } 64 | }); 65 | layout->addWidget(edit, id, 0); 66 | 67 | auto deleteButton = new QPushButton(QIcon::fromTheme(QStringLiteral("list-remove")), {}); 68 | connect(deleteButton, &QAbstractButton::clicked, this, [this, id](bool) { 69 | if (mType == Input) { 70 | mFunc->function()->removeExecInput(id); 71 | refreshEntry(); 72 | setFunction(mFunc, mType); 73 | dirtied(); 74 | } else { 75 | mFunc->function()->removeExecOutput(id); 76 | refreshExits(); 77 | setFunction(mFunc, mType); 78 | dirtied(); 79 | } 80 | }); 81 | layout->addWidget(deleteButton, id, 1); 82 | 83 | ++id; 84 | } 85 | 86 | // create the "new" button 87 | auto newButton = new QPushButton(QIcon::fromTheme("list-add"), {}); 88 | newButton->setSizePolicy({QSizePolicy::Maximum, QSizePolicy::Maximum}); 89 | connect(newButton, &QAbstractButton::clicked, this, [this](bool) { 90 | if (mType == Input) { 91 | mFunc->function()->addExecInput(""); 92 | refreshEntry(); 93 | dirtied(); 94 | 95 | setFunction(mFunc, mType); // TODO: not the most efficient way... 96 | } else { 97 | mFunc->function()->addExecOutput(""); 98 | refreshExits(); 99 | dirtied(); 100 | 101 | setFunction(mFunc, mType); 102 | } 103 | }); 104 | layout->addWidget(newButton, id, 1, Qt::AlignRight); 105 | } 106 | 107 | void ExecParamListWidget::refreshEntry() { 108 | auto entry = mFunc->function()->entryNode(); 109 | if (entry == nullptr) { return; } 110 | 111 | mFunc->refreshGuiForNode(*entry); 112 | } 113 | void ExecParamListWidget::refreshExits() { 114 | for (const auto& exit : mFunc->function()->nodesWithType("lang", "exit")) { 115 | mFunc->refreshGuiForNode(*exit); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/execparamlistwidget.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGGUI_EXECPARAMLISTWIDGET_HPP 4 | #define CHIGGUI_EXECPARAMLISTWIDGET_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class FunctionView; 12 | 13 | inline void deleteLayout(QLayout* layout) { 14 | QLayoutItem* item; 15 | QWidget* widget; 16 | while ((item = layout->takeAt(0))) { 17 | QLayout* sublayout = item->layout(); 18 | if (sublayout != 0) { 19 | deleteLayout(sublayout); 20 | } else if ((widget = item->widget()) != 0) { 21 | widget->hide(); 22 | delete widget; 23 | } else { 24 | delete item; 25 | } 26 | } 27 | 28 | delete layout; 29 | } 30 | 31 | class ExecParamListWidget : public QWidget { 32 | Q_OBJECT 33 | 34 | public: 35 | enum Type { Input, Output }; 36 | 37 | explicit ExecParamListWidget(QWidget* parent = nullptr); 38 | 39 | void setFunction(FunctionView* func, Type ty); 40 | 41 | signals: 42 | void dirtied(); 43 | 44 | private: 45 | void refreshEntry(); 46 | void refreshExits(); 47 | 48 | FunctionView* mFunc = nullptr; 49 | Type mType = Input; 50 | }; 51 | 52 | #endif // CHIGGUI_EXECPARAMLISTWIDGET_HPP 53 | -------------------------------------------------------------------------------- /src/functiondetails.cpp: -------------------------------------------------------------------------------- 1 | #include "functiondetails.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "functioninouts.hpp" 10 | #include "functionview.hpp" 11 | #include "localvariables.hpp" 12 | 13 | FunctionDetails::FunctionDetails(QWidget* parent) : QWidget{parent} { 14 | setXMLFile("chigraphfunctiondetailsui.rc"); 15 | 16 | setEnabled(false); 17 | 18 | auto layout = new QVBoxLayout; 19 | setLayout(layout); 20 | 21 | auto descSetterWidget = new QWidget; 22 | layout->addWidget(descSetterWidget); 23 | 24 | auto descHBox = new QHBoxLayout; 25 | descSetterWidget->setLayout(descHBox); 26 | 27 | auto descLabel = new QLabel(i18n("Description:")); 28 | descHBox->addWidget(descLabel); 29 | 30 | mDescEdit = new QLineEdit; 31 | descHBox->addWidget(mDescEdit); 32 | connect(mDescEdit, &QLineEdit::textChanged, this, [this](const QString& newText) { 33 | if (mFunction != nullptr) { 34 | auto stdStrNewText = newText.toStdString(); 35 | if (stdStrNewText != mFunction->function()->description()) { 36 | mFunction->function()->setDescription(stdStrNewText); 37 | dirtied(); 38 | } 39 | } 40 | }); 41 | 42 | auto inoutsbox = new QGroupBox(i18n("Inputs/Outputs")); 43 | layout->addWidget(inoutsbox); 44 | 45 | auto inslayout = new QVBoxLayout; 46 | inoutsbox->setLayout(inslayout); 47 | 48 | mInOuts = new FunctionInOuts; 49 | inslayout->addWidget(mInOuts); 50 | connect(mInOuts, &FunctionInOuts::dirtied, this, &FunctionDetails::dirtied); 51 | 52 | auto localsbox = new QGroupBox(i18n("Local Variables")); 53 | layout->addWidget(localsbox); 54 | 55 | auto localslayout = new QVBoxLayout; 56 | localsbox->setLayout(localslayout); 57 | 58 | mLocals = new LocalVariables; 59 | localslayout->addWidget(mLocals); 60 | connect(mLocals, &LocalVariables::dirtied, this, &FunctionDetails::dirtied); 61 | 62 | // add a spacer 63 | layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding)); 64 | } 65 | 66 | void FunctionDetails::loadFunction(FunctionView* funcView) { 67 | mFunction = funcView; 68 | 69 | mDescEdit->setText(QString::fromStdString(funcView->function()->description())); 70 | 71 | mInOuts->loadFunction(funcView); 72 | mLocals->loadFunction(funcView); 73 | } 74 | 75 | chi::GraphFunction* FunctionDetails::chiFunc() const { 76 | if (mFunction) { return mFunction->function(); } 77 | return nullptr; 78 | } 79 | -------------------------------------------------------------------------------- /src/functiondetails.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGGUI_FUNCTIONDETAILS_HPP 4 | #define CHIGGUI_FUNCTIONDETAILS_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "toolview.hpp" 11 | 12 | class FunctionView; 13 | class FunctionInOuts; 14 | class LocalVariables; 15 | 16 | class QLineEdit; 17 | 18 | class FunctionDetails : public QWidget, public ToolView { 19 | Q_OBJECT 20 | 21 | // ToolView interface 22 | public: 23 | QWidget* toolView() override { return this; } 24 | Qt::DockWidgetArea defaultArea() const override { return Qt::RightDockWidgetArea; } 25 | QString label() override { return i18n("Function Details"); } 26 | QString dockObjectName() override { return QStringLiteral("function-details"); } 27 | 28 | chi::GraphFunction* chiFunc() const; 29 | 30 | public: 31 | explicit FunctionDetails(QWidget* parent = nullptr); 32 | 33 | void loadFunction(FunctionView* funcView); 34 | 35 | signals: 36 | void dirtied(); 37 | 38 | private: 39 | FunctionInOuts* mInOuts; 40 | LocalVariables* mLocals; 41 | 42 | QLineEdit* mDescEdit; 43 | 44 | FunctionView* mFunction = nullptr; 45 | }; 46 | 47 | #endif // CHIGGUI_FUNCTIONDETAILS_HPP 48 | -------------------------------------------------------------------------------- /src/functioninouts.cpp: -------------------------------------------------------------------------------- 1 | #include "functioninouts.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "functionview.hpp" 9 | 10 | FunctionInOuts::FunctionInOuts(QWidget* parent) : QWidget(parent) { 11 | setSizePolicy({QSizePolicy::Preferred, QSizePolicy::Preferred}); 12 | 13 | auto layout = new QVBoxLayout; 14 | setLayout(layout); 15 | 16 | layout->addWidget(new QLabel(i18n("Exec Inputs"))); 17 | execins = new ExecParamListWidget; 18 | connect(execins, &ExecParamListWidget::dirtied, this, &FunctionInOuts::dirtied); 19 | layout->addWidget(execins); 20 | 21 | layout->addWidget(new QLabel(i18n("Exec Outputs"))); 22 | execouts = new ExecParamListWidget(); 23 | connect(execouts, &ExecParamListWidget::dirtied, this, &FunctionInOuts::dirtied); 24 | layout->addWidget(execouts); 25 | 26 | layout->addWidget(new QLabel(i18n("Data Inputs"))); 27 | ins = new ParamListWidget; 28 | connect(ins, &ParamListWidget::dirtied, this, &FunctionInOuts::dirtied); 29 | layout->addWidget(ins); 30 | 31 | layout->addWidget(new QLabel(i18n("Data Outputs"))); 32 | outs = new ParamListWidget; 33 | connect(outs, &ParamListWidget::dirtied, this, &FunctionInOuts::dirtied); 34 | layout->addWidget(outs); 35 | } 36 | 37 | void FunctionInOuts::loadFunction(FunctionView* func) { 38 | mFuncView = func; 39 | mFunc = func->function(); 40 | 41 | execins->setFunction(func, ExecParamListWidget::Input); 42 | execouts->setFunction(func, ExecParamListWidget::Output); 43 | 44 | ins->setFunction(func, ParamListWidget::Input); 45 | outs->setFunction(func, ParamListWidget::Output); 46 | } 47 | -------------------------------------------------------------------------------- /src/functioninouts.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGGUI_FUNCTION_IN_OUTS_HPP 4 | #define CHIGGUI_FUNCTION_IN_OUTS_HPP 5 | 6 | #include 7 | #include 8 | 9 | #include "execparamlistwidget.hpp" 10 | #include "paramlistwidget.hpp" 11 | 12 | class FunctionView; 13 | 14 | class FunctionInOuts : public QWidget { 15 | Q_OBJECT 16 | public: 17 | explicit FunctionInOuts(QWidget* parent = nullptr); 18 | 19 | public slots: 20 | void loadFunction(FunctionView* func); 21 | 22 | signals: 23 | void dirtied(); 24 | 25 | private: 26 | FunctionView* mFuncView = nullptr; 27 | chi::GraphFunction* mFunc = nullptr; 28 | 29 | ParamListWidget* ins; 30 | ParamListWidget* outs; 31 | 32 | ExecParamListWidget* execins; 33 | ExecParamListWidget* execouts; 34 | }; 35 | 36 | #endif // CHIGGUI_FUNCTION_IN_OUTS_HPP 37 | -------------------------------------------------------------------------------- /src/functionview.cpp: -------------------------------------------------------------------------------- 1 | #include "functionview.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "chigraphnodemodel.hpp" 15 | #include "mainwindow.hpp" 16 | 17 | using namespace QtNodes; 18 | 19 | FunctionView::FunctionView(chi::GraphFunction& func_, QWidget* parent) 20 | : QWidget(parent), mFunction{&func_} { 21 | auto hlayout = new QHBoxLayout(this); 22 | 23 | // TODO: see how to actually set the colors 24 | ConnectionStyle::setConnectionStyle(R"( 25 | { 26 | "ConnectionStyle": { 27 | "UseDataDefinedColors": true 28 | } 29 | } 30 | )"); 31 | 32 | hlayout->setMargin(0); 33 | hlayout->setSpacing(0); 34 | 35 | mModel = new ChigraphFlowSceneModel(*function()); 36 | 37 | mScene = new FlowScene(mModel); 38 | mModel->updateValidation(); 39 | 40 | mView = new FlowView(mScene); 41 | mView->setSceneRect(-320000, -320000, 640000, 640000); 42 | mView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 43 | mView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 44 | 45 | connect(mModel, &ChigraphFlowSceneModel::nodeWasDoubleClicked, this, 46 | [this](QtNodes::NodeIndex const& index, QPoint const&) { 47 | auto inst = reinterpret_cast(index.internalPointer()); 48 | 49 | auto& module = inst->type().module(); 50 | // cast to a GraphModule 51 | auto* castedModule = dynamic_cast(&module); 52 | if (castedModule == nullptr) { return; } 53 | 54 | auto func = castedModule->functionFromName(inst->type().name()); 55 | if (func == nullptr) { return; } 56 | 57 | emit functionDoubleClicked(*func); 58 | }); 59 | 60 | hlayout->addWidget(mView); 61 | } 62 | 63 | std::vector FunctionView::selectedNodes() { 64 | std::vector ret; 65 | 66 | auto guiNodes = mScene->selectedNodes(); 67 | ret.reserve(guiNodes.size()); 68 | 69 | for (auto n : guiNodes) { 70 | auto toAdd = reinterpret_cast(n.internalPointer()); 71 | 72 | if (toAdd) { ret.push_back(toAdd); } 73 | } 74 | 75 | return ret; 76 | } 77 | 78 | void FunctionView::selectNode(chi::NodeInstance& node) { 79 | // clear the selection 80 | scene().clearSelection(); 81 | auto guiNode = mScene->nodeGraphicsObject(mModel->nodeIndex(node)); 82 | if (guiNode == nullptr) { return; } 83 | 84 | // then select it 85 | guiNode->setSelected(true); 86 | } 87 | 88 | void FunctionView::centerOnNode(chi::NodeInstance& inst) { 89 | auto guiInst = mScene->nodeGraphicsObject(mModel->nodeIndex(inst)); 90 | 91 | if (guiInst) { mView->centerOn(guiInst); } 92 | } 93 | -------------------------------------------------------------------------------- /src/functionview.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGGUI_FUNCTIONVIEW_HPP 4 | #define CHIGGUI_FUNCTIONVIEW_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "chigraphnodemodel.hpp" 12 | 13 | class FunctionView : public QWidget { 14 | Q_OBJECT 15 | public: 16 | FunctionView(chi::GraphFunction& func_, QWidget* parent = nullptr); 17 | 18 | void centerOnNode(chi::NodeInstance& inst); 19 | 20 | void refreshGuiForNode(chi::NodeInstance& inst) { 21 | emit mModel->nodePortUpdated(mModel->nodeIndex(inst)); 22 | } 23 | 24 | chi::GraphFunction* function() const { return mFunction; } 25 | 26 | QtNodes::FlowScene& scene() const { return *mScene; } 27 | 28 | ChigraphFlowSceneModel& model() const { return *mModel; } 29 | 30 | std::vector selectedNodes(); 31 | 32 | void selectNode(chi::NodeInstance& node); 33 | 34 | signals: 35 | void dirtied(); 36 | void functionDoubleClicked(chi::GraphFunction& func); 37 | 38 | private: 39 | QtNodes::FlowScene* mScene; 40 | QtNodes::FlowView* mView; 41 | ChigraphFlowSceneModel* mModel; 42 | 43 | chi::GraphFunction* mFunction; 44 | }; 45 | 46 | #endif // CHIGGUI_FUNCTIONVIEW_HPP 47 | -------------------------------------------------------------------------------- /src/launchconfigurationdialog.cpp: -------------------------------------------------------------------------------- 1 | #include "launchconfigurationdialog.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "chiitemselectwidget.hpp" 17 | 18 | LaunchConfigurationDialog::LaunchConfigurationDialog(LaunchConfigurationManager& manager) 19 | : mManager{&manager} { 20 | setWindowTitle(i18n("Launch Configurations")); 21 | 22 | // config list 23 | mConfigList = new QListWidget; 24 | mConfigList->setEditTriggers(QAbstractItemView::SelectedClicked | 25 | QAbstractItemView::EditTrigger::EditKeyPressed); 26 | 27 | // init actions 28 | auto renameAction = 29 | new QAction(QIcon::fromTheme(QStringLiteral("edit-rename")), i18n("Rename"), nullptr); 30 | connect(renameAction, &QAction::triggered, this, 31 | [this] { mConfigList->openPersistentEditor(mConfigList->currentItem()); }); 32 | 33 | auto deleteAction = 34 | new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete"), nullptr); 35 | deleteAction->setShortcut(Qt::Key_Delete); 36 | connect(deleteAction, &QAction::triggered, this, [this] { 37 | auto currentItem = mConfigList->currentItem(); 38 | if (idToItem[currentItem] == currentlyEditing) { 39 | // if this is the case, then clear our fields and currentlyEditing 40 | currentlyEditing = {}; 41 | 42 | mModuleEdit->setItem({}); 43 | mWdEdit->setText({}); 44 | mArgsEdit->setText({}); 45 | } 46 | 47 | // remove it from the manager 48 | mManager->removeConfiguration(idToItem[currentItem]); 49 | 50 | // delete it 51 | delete mConfigList->takeItem(mConfigList->row(currentItem)); 52 | }); 53 | 54 | addAction(renameAction); 55 | addAction(deleteAction); 56 | 57 | // left side widget 58 | auto leftWidget = new QWidget; 59 | { 60 | auto layout = new QVBoxLayout; 61 | leftWidget->setLayout(layout); 62 | 63 | // buttons 64 | auto buttonWidget = new QWidget; 65 | { 66 | auto hbuttonlayout = new QHBoxLayout; 67 | buttonWidget->setLayout(hbuttonlayout); 68 | hbuttonlayout->setAlignment(Qt::AlignRight); 69 | 70 | // new button 71 | auto newButton = new QPushButton(QIcon::fromTheme(QStringLiteral("list-add")), {}); 72 | newButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 73 | connect(newButton, &QPushButton::pressed, this, 74 | &LaunchConfigurationDialog::addNewConfig); 75 | hbuttonlayout->addWidget(newButton); 76 | 77 | // delete button 78 | auto deleteButton = 79 | new QPushButton(QIcon::fromTheme(QStringLiteral("edit-delete")), {}); 80 | deleteButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 81 | connect(deleteButton, &QPushButton::pressed, deleteAction, &QAction::trigger); 82 | hbuttonlayout->addWidget(deleteButton); 83 | 84 | hbuttonlayout->addWidget(deleteButton); 85 | } 86 | 87 | layout->addWidget(buttonWidget); 88 | 89 | layout->addWidget(mConfigList); 90 | 91 | // populate it 92 | for (const auto& config : manager.configurations()) { 93 | auto listItem = new QListWidgetItem(config.name()); 94 | 95 | // make it editable 96 | listItem->setFlags(listItem->flags() | Qt::ItemIsEditable); 97 | 98 | mConfigList->addItem(listItem); 99 | 100 | // store it in the map 101 | idToItem[listItem] = config; 102 | } 103 | connect(mConfigList, &QListWidget::currentItemChanged, this, 104 | [this](QListWidgetItem* item, QListWidgetItem*) { selectConfig(item); }); 105 | connect(mConfigList, &QListWidget::itemChanged, this, 106 | [this](QListWidgetItem* item) { nameChanged(item->text()); }); 107 | 108 | // context menus 109 | mConfigList->setContextMenuPolicy(Qt::CustomContextMenu); 110 | connect(mConfigList, &QWidget::customContextMenuRequested, this, 111 | [this, renameAction, deleteAction](const QPoint& point) { 112 | auto item = mConfigList->itemAt(point); 113 | 114 | mConfigList->setCurrentItem(item); 115 | 116 | if (item == nullptr) { return; } 117 | 118 | QMenu menu; 119 | menu.addAction(renameAction); 120 | menu.addAction(deleteAction); 121 | 122 | menu.exec(mConfigList->mapToGlobal(point)); 123 | }); 124 | } 125 | 126 | // right side widget 127 | mSettingsWidget = new QWidget; 128 | { 129 | auto layout = new QFormLayout; 130 | mSettingsWidget->setLayout(layout); 131 | 132 | // module 133 | { 134 | mModuleEdit = new ChiItemSelectWidget(manager.context(), WorkspaceTree::MODULE); 135 | connect(mModuleEdit, &ChiItemSelectWidget::itemChanged, this, 136 | &LaunchConfigurationDialog::moduleChanged); 137 | layout->addRow(i18n("Module"), mModuleEdit); 138 | } 139 | 140 | // working directory 141 | { 142 | mWdEdit = new KUrlRequester(); 143 | // mWdEdit->setAcceptMode(QFileDialog::AcceptMode::AcceptOpen); 144 | mWdEdit->setMode(KFile::Directory); 145 | connect(mWdEdit, &KUrlRequester::textChanged, this, 146 | &LaunchConfigurationDialog::wdChanged); 147 | layout->addRow(i18n("Working Directory"), mWdEdit); 148 | } 149 | 150 | // arguments 151 | { 152 | mArgsEdit = new QLineEdit; 153 | mArgsEdit->setPlaceholderText(i18n("Enter arguments to be passed to the executable")); 154 | connect(mArgsEdit, &QLineEdit::textChanged, this, 155 | &LaunchConfigurationDialog::argsChanged); 156 | layout->addRow(i18n("Arguments"), mArgsEdit); 157 | } 158 | } 159 | 160 | auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); 161 | connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); 162 | 163 | auto rootSlider = new QSplitter; 164 | rootSlider->setChildrenCollapsible(false); 165 | rootSlider->addWidget(leftWidget); 166 | rootSlider->addWidget(mSettingsWidget); 167 | 168 | auto rootLayout = new QVBoxLayout; 169 | setLayout(rootLayout); 170 | rootLayout->addWidget(rootSlider); 171 | rootLayout->addWidget(buttonBox); 172 | 173 | // disable the settings by default--none selected 174 | mSettingsWidget->setEnabled(false); 175 | 176 | // select the first one 177 | if (mManager->configurations().size() > 1) { selectConfig(mManager->configurations()[0]); } 178 | } 179 | 180 | void LaunchConfigurationDialog::selectConfig(QListWidgetItem* newItem) { 181 | // find it 182 | auto iter = idToItem.find(newItem); 183 | if (iter == idToItem.end()) { return; } 184 | 185 | selectConfig(iter->second); 186 | } 187 | 188 | void LaunchConfigurationDialog::selectConfig(LaunchConfiguration config) { 189 | if (!config.valid()) { return; } 190 | 191 | currentlyEditing = config; 192 | 193 | mSettingsWidget->setEnabled(true); 194 | 195 | mWdEdit->setText(config.workingDirectory()); 196 | mModuleEdit->setItem(config.module().toStdString()); 197 | mArgsEdit->setText(config.arguments()); 198 | } 199 | 200 | void LaunchConfigurationDialog::addNewConfig() { 201 | auto config = mManager->newConfiguration(); 202 | config.setName(i18n("New Configuration")); 203 | 204 | auto newItem = new QListWidgetItem(config.name()); 205 | 206 | // make it editable 207 | newItem->setFlags(newItem->flags() | Qt::ItemIsEditable); 208 | 209 | mConfigList->addItem(newItem); 210 | 211 | idToItem[newItem] = config; 212 | 213 | selectConfig(config); 214 | } 215 | 216 | void LaunchConfigurationDialog::argsChanged(const QString& newArgs) { 217 | if (currentlyEditing.valid()) { currentlyEditing.setArguments(newArgs); } 218 | } 219 | 220 | void LaunchConfigurationDialog::moduleChanged(const std::filesystem::path& newModule) { 221 | if (currentlyEditing.valid()) { 222 | currentlyEditing.setModule(QString::fromStdString(newModule.string())); 223 | } 224 | } 225 | 226 | void LaunchConfigurationDialog::nameChanged(const QString& newName) { 227 | if (currentlyEditing.valid()) { currentlyEditing.setName(newName); } 228 | } 229 | 230 | void LaunchConfigurationDialog::wdChanged(const QString& newWd) { 231 | if (currentlyEditing.valid()) { currentlyEditing.setWorkingDirectory(newWd); } 232 | } 233 | -------------------------------------------------------------------------------- /src/launchconfigurationdialog.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRPAHGUI_LAUNCH_CONFIGURATION_DIALOG_HPP 4 | #define CHIGRPAHGUI_LAUNCH_CONFIGURATION_DIALOG_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "launchconfigurationmanager.hpp" 11 | 12 | class KUrlRequester; 13 | 14 | class QListWidget; 15 | class QLineEdit; 16 | class QListWidgetItem; 17 | 18 | class ChiItemSelectWidget; 19 | 20 | class LaunchConfigurationDialog : public QDialog { 21 | Q_OBJECT 22 | public: 23 | LaunchConfigurationDialog(LaunchConfigurationManager& manager); 24 | 25 | private slots: 26 | void addNewConfig(); 27 | void selectConfig(QListWidgetItem* newConfig); 28 | void selectConfig(LaunchConfiguration newConfig); 29 | 30 | void nameChanged(const QString& newName); 31 | void wdChanged(const QString& newWd); 32 | void moduleChanged(const std::filesystem::path& newModule); 33 | void argsChanged(const QString& newArgs); 34 | 35 | private: 36 | LaunchConfigurationManager* mManager; 37 | LaunchConfiguration currentlyEditing; 38 | 39 | std::unordered_map idToItem; 40 | 41 | KUrlRequester* mWdEdit; 42 | ChiItemSelectWidget* mModuleEdit; 43 | QLineEdit* mArgsEdit; 44 | QWidget* mSettingsWidget; 45 | 46 | QListWidget* mConfigList; 47 | }; 48 | 49 | #endif // CHIGRPAHGUI_LAUNCH_CONFIGURATION_DIALOG_HPP 50 | -------------------------------------------------------------------------------- /src/launchconfigurationmanager.cpp: -------------------------------------------------------------------------------- 1 | #include "launchconfigurationmanager.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | LaunchConfiguration::LaunchConfiguration(KConfigGroup grp) : mConfigGroup{grp} {} 11 | 12 | LaunchConfigurationManager::LaunchConfigurationManager(chi::Context& context) : mContext{&context} { 13 | KConfigGroup contextConfig(KSharedConfig::openConfig(), 14 | context.workspacePath().string().c_str()); 15 | 16 | mConfigGroup = contextConfig.group("launchconfigurations"); 17 | 18 | auto configurations = mConfigGroup.readEntry("configurations", QStringList()); 19 | auto currentName = mConfigGroup.readEntry("current", QString()); 20 | 21 | for (const auto& configName : configurations) { 22 | mConfigurations.emplace_back(mConfigGroup.group(configName)); 23 | 24 | if (configName == currentName) { mCurrent = mConfigurations[mConfigurations.size() - 1]; } 25 | } 26 | } 27 | 28 | LaunchConfiguration LaunchConfigurationManager::newConfiguration() { 29 | // generate uuid for it 30 | auto uuid = QUuid::createUuid(); 31 | 32 | // add it to the list 33 | mConfigGroup.writeEntry("configurations", 34 | mConfigGroup.readEntry("configurations", QStringList()) 35 | << uuid.toString()); 36 | 37 | auto group = mConfigGroup.group(uuid.toString()); 38 | 39 | mConfigurations.emplace_back(group); 40 | 41 | return mConfigurations[mConfigurations.size() - 1]; 42 | } 43 | 44 | void LaunchConfigurationManager::removeConfiguration(LaunchConfiguration config) { 45 | // remove it as the current if it's the current 46 | if (config.valid() && currentConfiguration().valid() && config == currentConfiguration()) { 47 | setCurrentConfiguration({}); 48 | } 49 | 50 | // find it and remove it from the list 51 | auto iter = std::find(mConfigurations.begin(), mConfigurations.end(), config); 52 | if (iter == mConfigurations.end()) { 53 | qDebug() << "Failed to find config to delete: " << config.id(); 54 | return; 55 | } 56 | 57 | mConfigurations.erase(iter); 58 | 59 | mConfigGroup.deleteEntry(config.id()); 60 | } 61 | 62 | void LaunchConfigurationManager::setCurrentConfiguration(LaunchConfiguration config) { 63 | mCurrent = config; 64 | 65 | if (config.valid()) { 66 | mConfigGroup.writeEntry("current", config.id()); 67 | } else { 68 | mConfigGroup.deleteEntry("current"); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/launchconfigurationmanager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_LAUNCH_CONFIGURATION_HPP 4 | #define CHIGRAPHGUI_LAUNCH_CONFIGURATION_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | struct LaunchConfiguration { 11 | // constructs an invalid configuration 12 | LaunchConfiguration() {} 13 | 14 | LaunchConfiguration(KConfigGroup grp); 15 | 16 | QString name() const { return mConfigGroup.readEntry("name", QString()); } 17 | QString module() const { return mConfigGroup.readEntry("module", QString()); } 18 | QString workingDirectory() const { 19 | return mConfigGroup.readEntry("workingdirectory", QString()); 20 | } 21 | QString arguments() const { return mConfigGroup.readEntry("arguments", QString()); } 22 | QStringList env() const { return mConfigGroup.readEntry("environment", QStringList()); } 23 | 24 | void setName(const QString& newName) { mConfigGroup.writeEntry("name", newName); } 25 | void setModule(const QString& newModule) { mConfigGroup.writeEntry("module", newModule); } 26 | void setWorkingDirectory(const QString& newWd) { 27 | mConfigGroup.writeEntry("workingdirectory", newWd); 28 | } 29 | void setArguments(const QString& newArgs) { mConfigGroup.writeEntry("arguments", newArgs); } 30 | void setEnv(const QStringList& newEnv) { mConfigGroup.writeEntry("environment", newEnv); } 31 | 32 | bool valid() const { return mConfigGroup.isValid(); } 33 | 34 | QString id() const { return mConfigGroup.name(); } 35 | 36 | bool operator==(const LaunchConfiguration& rhs) const { return id() == rhs.id(); } 37 | 38 | bool operator!=(const LaunchConfiguration& rhs) const { return id() != rhs.id(); } 39 | 40 | private: 41 | KConfigGroup mConfigGroup; 42 | }; 43 | 44 | class LaunchConfigurationManager : public QObject { 45 | Q_OBJECT 46 | public: 47 | LaunchConfigurationManager(chi::Context& context); 48 | 49 | LaunchConfigurationManager(const LaunchConfigurationManager&) = delete; 50 | LaunchConfigurationManager(LaunchConfigurationManager&&) = delete; 51 | 52 | LaunchConfigurationManager& operator=(const LaunchConfigurationManager&) = delete; 53 | LaunchConfigurationManager& operator=(LaunchConfigurationManager&&) = delete; 54 | 55 | const std::vector configurations() const { return mConfigurations; } 56 | 57 | LaunchConfiguration currentConfiguration() const { return mCurrent; } 58 | void setCurrentConfiguration(LaunchConfiguration config); 59 | 60 | LaunchConfiguration newConfiguration(); 61 | 62 | void removeConfiguration(LaunchConfiguration config); 63 | 64 | LaunchConfiguration configByName(const QString& str) { 65 | for (const auto& config : configurations()) { 66 | if (config.name() == str) { return config; } 67 | } 68 | return {}; 69 | } 70 | 71 | chi::Context& context() const { return *mContext; } 72 | 73 | private: 74 | LaunchConfiguration mCurrent; 75 | std::vector mConfigurations; 76 | KConfigGroup mConfigGroup; 77 | 78 | chi::Context* mContext; 79 | }; 80 | 81 | #endif // CHIGRAPHGUI_LAUNCH_CONFIGURATION_HPP 82 | -------------------------------------------------------------------------------- /src/localvariables.cpp: -------------------------------------------------------------------------------- 1 | #include "localvariables.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "execparamlistwidget.hpp" 13 | #include "paramlistwidget.hpp" 14 | #include "typeselector.hpp" 15 | 16 | LocalVariables::LocalVariables(QWidget* parent) : QWidget{parent} { 17 | setSizePolicy({QSizePolicy::Preferred, QSizePolicy::Preferred}); 18 | } 19 | 20 | void LocalVariables::loadFunction(FunctionView* func) { 21 | mFunctionView = func; 22 | 23 | if (layout()) { deleteLayout(layout()); } 24 | 25 | auto layout = new QGridLayout; 26 | setLayout(layout); 27 | 28 | auto id = 0; 29 | for (const auto& var : func->function()->localVariables()) { 30 | auto nameEdit = new QLineEdit; 31 | nameEdit->setText(QString::fromStdString(var.name)); 32 | connect(nameEdit, &QLineEdit::textChanged, this, [this, id](const QString& newText) { 33 | auto stdstr = newText.toStdString(); 34 | mFunctionView->function()->renameLocalVariable( 35 | mFunctionView->function()->localVariables()[id].name, stdstr); 36 | // update the nodes 37 | refreshReferencingNodes(stdstr); 38 | dirtied(); 39 | }); 40 | layout->addWidget(nameEdit, id, 0); 41 | 42 | auto tySelector = new TypeSelector(mFunctionView->function()->module()); 43 | tySelector->setCurrentType(var.type); 44 | connect(tySelector, &TypeSelector::typeSelected, this, 45 | [this, id](const chi::DataType& newType) { 46 | if (!newType.valid()) { return; } 47 | 48 | auto localName = mFunctionView->function()->localVariables()[id].name; 49 | 50 | mFunctionView->function()->retypeLocalVariable(localName, newType); 51 | refreshReferencingNodes(localName); 52 | dirtied(); 53 | }); 54 | layout->addWidget(tySelector, id, 1); 55 | 56 | auto deleteButton = new QPushButton(QIcon::fromTheme(QStringLiteral("list-remove")), {}); 57 | connect(deleteButton, &QPushButton::clicked, this, [this, id] { 58 | auto name = mFunctionView->function()->localVariables()[id].name; 59 | 60 | // delete the referencing gui nodes 61 | deleteReferencingNodes(name); 62 | 63 | mFunctionView->function()->removeLocalVariable(name); 64 | 65 | // refresh the local vars panel 66 | loadFunction(mFunctionView); 67 | dirtied(); 68 | }); 69 | layout->addWidget(deleteButton, id, 2); 70 | 71 | ++id; 72 | } 73 | auto newButton = new QPushButton(QIcon::fromTheme(QStringLiteral("list-add")), {}); 74 | newButton->setSizePolicy({QSizePolicy::Maximum, QSizePolicy::Maximum}); 75 | connect(newButton, &QPushButton::clicked, this, [this] { 76 | chi::DataType ty = mFunctionView->function()->context().langModule()->typeFromName("i32"); 77 | 78 | mFunctionView->function()->getOrCreateLocalVariable("", ty); 79 | 80 | loadFunction(mFunctionView); 81 | dirtied(); 82 | }); 83 | layout->addWidget(newButton, id, 2, Qt::AlignRight); 84 | } 85 | 86 | void LocalVariables::refreshReferencingNodes(const std::string& name) { 87 | auto setNodes = mFunctionView->function()->nodesWithType( 88 | mFunctionView->function()->module().fullName(), "_set_" + name); 89 | for (const auto& node : setNodes) { mFunctionView->refreshGuiForNode(*node); } 90 | auto getNodes = mFunctionView->function()->nodesWithType( 91 | mFunctionView->function()->module().fullName(), "_get_" + name); 92 | for (const auto& node : getNodes) { mFunctionView->refreshGuiForNode(*node); } 93 | } 94 | 95 | void LocalVariables::deleteReferencingNodes(const std::string& name) { 96 | auto setNodes = mFunctionView->function()->nodesWithType( 97 | mFunctionView->function()->module().fullName(), "_set_" + name); 98 | for (const auto& node : setNodes) { 99 | mFunctionView->model().removeNode(mFunctionView->model().nodeIndex(*node)); 100 | } 101 | auto getNodes = mFunctionView->function()->nodesWithType( 102 | mFunctionView->function()->module().fullName(), "_get_" + name); 103 | for (const auto& node : getNodes) { 104 | mFunctionView->model().removeNode(mFunctionView->model().nodeIndex(*node)); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/localvariables.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGGUI_LOCAL_VARIABLES_HPP 4 | #define CHIGGUI_LOCAL_VARIABLES_HPP 5 | 6 | #include 7 | 8 | #include "functionview.hpp" 9 | 10 | class LocalVariables : public QWidget { 11 | Q_OBJECT 12 | public: 13 | explicit LocalVariables(QWidget* parent = nullptr); 14 | 15 | void loadFunction(FunctionView* func); 16 | 17 | signals: 18 | void dirtied(); 19 | 20 | private: 21 | void refreshReferencingNodes(const std::string& name); 22 | void deleteReferencingNodes(const std::string& name); 23 | 24 | FunctionView* mFunctionView = nullptr; 25 | }; 26 | 27 | #endif // CHIGGUI_LOCAL_VARIABLES_HPP 28 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "mainwindow.hpp" 10 | 11 | #ifdef CHIGRAPH_WITH_DEBUGGER 12 | Q_IMPORT_PLUGIN(DebuggerPlugin) 13 | #endif 14 | 15 | int main(int argc, char** argv) { 16 | QApplication app(argc, argv); 17 | KCrash::initialize(); 18 | 19 | KLocalizedString::setApplicationDomain("chigraphgui"); 20 | 21 | KAboutData aboutData(QStringLiteral("chigraphgui"), i18n("Chigraph GUI"), QStringLiteral("1.0"), 22 | i18n("Chigraph Graphical User Interface"), KAboutLicense::GPL, 23 | i18n("(c) 2016 Russell Greene"), QStringLiteral(""), 24 | QStringLiteral("https://github.com/chigraph/chigraph"), 25 | QStringLiteral("https://github.com/chigraph/chigraph/issues")); 26 | 27 | aboutData.addAuthor( 28 | i18n("Russell Greene"), i18n("Programmer"), QStringLiteral("russellgreene8@gmail.com"), 29 | QStringLiteral("https://github.com/russelltg"), QStringLiteral("russelltg")); 30 | 31 | KAboutData::setApplicationData(aboutData); 32 | 33 | QCommandLineParser parser; 34 | parser.addHelpOption(); 35 | parser.addVersionOption(); 36 | 37 | aboutData.setupCommandLine(&parser); 38 | 39 | parser.process(app); 40 | 41 | aboutData.processCommandLine(&parser); 42 | 43 | #ifdef WIN32 44 | QIcon::setThemeName("breeze"); 45 | #endif 46 | auto win = new MainWindow(); 47 | win->show(); 48 | 49 | return app.exec(); 50 | } 51 | -------------------------------------------------------------------------------- /src/mainwindow.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGGUI_MAINWINDOW_H 4 | #define CHIGGUI_MAINWINDOW_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "functionview.hpp" 19 | #include "launchconfigurationmanager.hpp" 20 | 21 | class ModuleBrowser; 22 | class ThemeManager; 23 | class CentralTabView; 24 | 25 | class MainWindow : public KXmlGuiWindow { 26 | Q_OBJECT 27 | public: 28 | explicit MainWindow(QWidget* parent = nullptr); 29 | ~MainWindow(); 30 | 31 | chi::Context& context() const { return *mChigContext; } 32 | CentralTabView& tabView() const { return *mFunctionTabs; } 33 | 34 | LaunchConfigurationManager& launchManager() { return *mLaunchManager; } 35 | 36 | /// Load a module into the window. 37 | /// \exepcts `!name.isEmpty()` 38 | std::pair loadModule(const QString& name); 39 | 40 | private: 41 | static MainWindow* mInstance; 42 | 43 | public: 44 | static MainWindow* instance() { return mInstance; } 45 | 46 | public slots: 47 | void openWorkspaceDialog(); // this one opens a dialog 48 | void openWorkspace(const QUrl& url); // and this one doesn't 49 | void newWorkspace(); 50 | void save(); 51 | 52 | void moduleDirtied(chi::GraphModule& mod); 53 | 54 | signals: 55 | void workspaceOpened(chi::Context& workspace); 56 | void functionOpened(FunctionView* func); 57 | 58 | void newModuleCreated(chi::GraphModule& newModule); 59 | void newFunctionCreated(chi::GraphFunction& func); 60 | 61 | private: 62 | void closeEvent(QCloseEvent* event) override; 63 | 64 | void updateUsableConfigs(); 65 | 66 | std::unique_ptr mLaunchManager; 67 | 68 | KRecentFilesAction* mOpenRecentAction; // keep this so we can save the entries 69 | 70 | KSelectAction* mConfigSelectAction; 71 | 72 | // the tabs for open functions 73 | CentralTabView* mFunctionTabs = nullptr; 74 | 75 | // context & module 76 | std::unique_ptr mChigContext = nullptr; 77 | ModuleBrowser* mModuleBrowser = nullptr; 78 | 79 | std::unique_ptr mThemeManager; 80 | }; 81 | 82 | #endif // CHIGGUI_MAINWINDOW_H 83 | -------------------------------------------------------------------------------- /src/modulebrowser.cpp: -------------------------------------------------------------------------------- 1 | #include "modulebrowser.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "mainwindow.hpp" 19 | #include "modulepropertiesdialog.hpp" 20 | #include "moduletreemodel.hpp" 21 | #include "newmoduledialog.hpp" 22 | 23 | namespace fs = std::filesystem; 24 | 25 | ModuleBrowser::ModuleBrowser(QWidget* parent) : QTreeView(parent) { 26 | setXMLFile("chigraphmodulebrowserui.rc"); 27 | 28 | // setup actions 29 | newModuleAction = actionCollection()->addAction( 30 | QStringLiteral("new-module"), 31 | new QAction(QIcon::fromTheme(QStringLiteral("code-block")), i18n("New Module"), nullptr)); 32 | connect(newModuleAction, &QAction::triggered, this, &ModuleBrowser::newModule); 33 | 34 | newFunctionAction = actionCollection()->addAction( 35 | QStringLiteral("new-function"), new QAction(QIcon::fromTheme(QStringLiteral("message-new")), 36 | i18n("New Function"), nullptr)); 37 | connect(newFunctionAction, &QAction::triggered, this, &ModuleBrowser::newFunction); 38 | 39 | newStructAction = actionCollection()->addAction( 40 | QStringLiteral("new-struct"), 41 | new QAction(QIcon::fromTheme(QStringLiteral("window-new")), i18n("New Struct"), nullptr)); 42 | 43 | connect(newStructAction, &QAction::triggered, this, &ModuleBrowser::newStruct); 44 | 45 | deleteAction = actionCollection()->addAction( 46 | QStringLiteral("remove-item"), 47 | new QAction(QIcon::fromTheme(QStringLiteral("entry-delete")), i18n("Delete"), nullptr)); 48 | connect(deleteAction, &QAction::triggered, this, &ModuleBrowser::deleteItem); 49 | 50 | renameAction = actionCollection()->addAction( 51 | QStringLiteral("rename"), 52 | new QAction(QIcon::fromTheme(QStringLiteral("edit-rename")), i18n("Rename"), nullptr)); 53 | 54 | modulePropertiesAction = actionCollection()->addAction( 55 | QStringLiteral("module-properties"), 56 | new QAction(QIcon::fromTheme(QStringLiteral("document-properties")), 57 | i18n("Module Properties"), nullptr)); 58 | connect(modulePropertiesAction, &QAction::triggered, this, &ModuleBrowser::moduleProperties); 59 | 60 | setAnimated(true); 61 | setSortingEnabled(true); 62 | setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed); 63 | header()->close(); 64 | connect(this, &QTreeView::doubleClicked, this, [this](const QModelIndex& index) { 65 | auto item = static_cast(index.internalPointer()); 66 | 67 | switch (item->type) { 68 | case WorkspaceTree::FUNCTION: functionSelected(*item->func); return; 69 | case WorkspaceTree::STRUCT: structSelected(*item->str); return; 70 | default: return; 71 | } 72 | }); 73 | setContextMenuPolicy(Qt::CustomContextMenu); 74 | 75 | connect(this, &QWidget::customContextMenuRequested, this, [this](QPoint p) { 76 | auto idx = indexAt(p); 77 | if (!idx.isValid()) { return; } 78 | 79 | auto item = static_cast(idx.internalPointer()); 80 | 81 | if (!item) { return; } 82 | 83 | setCurrentIndex(idx); 84 | 85 | QMenu contextMenu; 86 | 87 | // add actions depending on the type 88 | switch (item->type) { 89 | case WorkspaceTree::MODULE: 90 | contextMenu.addAction(renameAction); 91 | contextMenu.addAction(newFunctionAction); 92 | contextMenu.addAction(newStructAction); 93 | contextMenu.addAction(deleteAction); 94 | contextMenu.addAction(modulePropertiesAction); 95 | break; 96 | case WorkspaceTree::FOLDER: 97 | contextMenu.addAction(renameAction); 98 | contextMenu.addAction(newModuleAction); 99 | // contextMenu.addAction(deleteAction); TODO: do this 100 | break; 101 | case WorkspaceTree::FUNCTION: 102 | contextMenu.addAction(renameAction); 103 | contextMenu.addAction(deleteAction); 104 | break; 105 | case WorkspaceTree::STRUCT: 106 | contextMenu.addAction(renameAction); 107 | contextMenu.addAction(deleteAction); 108 | break; 109 | } 110 | contextMenu.exec(mapToGlobal(p)); 111 | }); 112 | } 113 | 114 | ModuleBrowser::~ModuleBrowser() = default; 115 | 116 | std::unordered_set ModuleBrowser::dirtyModules() { return mDirtyModules; } 117 | 118 | void ModuleBrowser::loadWorkspace(chi::Context& context) { 119 | mContext = &context; 120 | 121 | mModel = ModuleTreeModel::createFromContext(context); 122 | mTree = mModel->tree(); 123 | 124 | connect(mModel.get(), &ModuleTreeModel::functionRenamed, this, &ModuleBrowser::functionRenamed); 125 | connect(mModel.get(), &ModuleTreeModel::structRenamed, this, &ModuleBrowser::structRenamed); 126 | 127 | setModel(mModel.get()); 128 | 129 | // expand src 130 | expand(mModel->index(0, 0, {})); 131 | } 132 | 133 | void ModuleBrowser::moduleDirtied(chi::GraphModule& dirtied) { 134 | mDirtyModules.insert(&dirtied); 135 | updateDirtyStatus(dirtied, true); 136 | } 137 | 138 | void ModuleBrowser::moduleSaved(chi::GraphModule& saved) { 139 | updateDirtyStatus(saved, false); 140 | mDirtyModules.erase(&saved); 141 | } 142 | 143 | void ModuleBrowser::newModule() { 144 | fs::path startingDir; 145 | 146 | // get the currently selected folder 147 | auto idx = currentIndex(); 148 | if (idx.isValid()) { 149 | auto item = static_cast(idx.internalPointer()); 150 | 151 | startingDir = item->fullName(); 152 | } 153 | 154 | // create a new module dialog 155 | auto dialog = new NewModuleDialog(this, context(), startingDir); 156 | dialog->exec(); 157 | } 158 | 159 | void ModuleBrowser::newFunction() { 160 | fs::path owningModule; 161 | 162 | auto idx = currentIndex(); 163 | if (idx.isValid()) { 164 | auto item = static_cast(idx.internalPointer()); 165 | 166 | if (item->type != WorkspaceTree::MODULE) { return; } 167 | 168 | owningModule = item->fullName(); 169 | } 170 | 171 | // get the module from the context 172 | chi::ChiModule* mod; 173 | auto res = context().loadModule(owningModule, &mod); 174 | 175 | if (!res) { 176 | KMessageBox::detailedError(this, "Failed to load module", 177 | QString::fromStdString(res.dump())); 178 | return; 179 | } 180 | 181 | chi::GraphModule* gMod = static_cast(mod); 182 | // add the function TODO: detect if "New Function" is already taken 183 | auto func = gMod->getOrCreateFunction("New Function", {}, {}, {""}, {""}); 184 | Q_ASSERT(func); 185 | 186 | // add a entry node 187 | std::unique_ptr entryTy; 188 | res += func->createEntryNodeType(&entryTy); 189 | Q_ASSERT(!!res); 190 | 191 | res += func->insertNode(std::move(entryTy), 0.f, 0.f); 192 | Q_ASSERT(!!res); 193 | 194 | // update the model 195 | mModel->updateModule(owningModule); 196 | } 197 | 198 | void ModuleBrowser::newStruct() { 199 | fs::path owningModule; 200 | 201 | auto idx = currentIndex(); 202 | if (idx.isValid()) { 203 | auto item = static_cast(idx.internalPointer()); 204 | 205 | if (item->type != WorkspaceTree::MODULE) { return; } 206 | 207 | owningModule = item->fullName(); 208 | } 209 | 210 | // get the module from the context 211 | chi::ChiModule* mod; 212 | auto res = context().loadModule(owningModule, &mod); 213 | 214 | if (!res) { 215 | KMessageBox::detailedError(this, "Failed to load module", 216 | QString::fromStdString(res.dump())); 217 | return; 218 | } 219 | 220 | auto gMod = static_cast(mod); 221 | 222 | // TODO: rename this to something that's garunteed to not exist 223 | gMod->getOrCreateStruct("New Struct"); 224 | 225 | mModel->updateModule(owningModule); 226 | } 227 | 228 | void ModuleBrowser::moduleProperties() { 229 | fs::path owningModule; 230 | 231 | auto idx = currentIndex(); 232 | if (idx.isValid()) { 233 | auto item = static_cast(idx.internalPointer()); 234 | 235 | if (item->type != WorkspaceTree::MODULE) { return; } 236 | 237 | owningModule = item->fullName(); 238 | } 239 | 240 | // load the module 241 | chi::ChiModule* mod; 242 | auto res = context().loadModule(owningModule, &mod); 243 | if (!res) { 244 | qDebug() << "Failed to load module " << QString::fromStdString(owningModule.string()); 245 | } 246 | 247 | auto castedMod = static_cast(mod); 248 | 249 | auto dialog = new ModulePropertiesDialog(this, *castedMod); 250 | dialog->exec(); 251 | } 252 | 253 | void ModuleBrowser::deleteItem() { 254 | // see which type it is 255 | auto idx = currentIndex(); 256 | if (!idx.isValid()) { return; } 257 | 258 | auto item = static_cast(idx.internalPointer()); 259 | 260 | switch (item->type) { 261 | case WorkspaceTree::FUNCTION: { 262 | // close the function if it's still open 263 | emit functionDeleted(item->func->module(), item->func->name()); 264 | 265 | // delete it from the module 266 | // TODO: do diagnostics on what this hurts 267 | item->func->module().removeFunction(*item->func); 268 | 269 | mModel->updateModule(item->parent->fullName()); 270 | 271 | break; 272 | } 273 | case WorkspaceTree::STRUCT: { 274 | // close the function if it's still open 275 | emit structDeleted(item->str->module(), item->str->name()); 276 | 277 | // delete it from the module 278 | // TODO: do diagnostics on what this hurts 279 | item->str->module().removeStruct(*item->str); 280 | 281 | mModel->updateModule(item->parent->fullName()); 282 | 283 | break; 284 | } 285 | // TODO: implement the rest 286 | default: return; 287 | } 288 | return; 289 | } 290 | 291 | void ModuleBrowser::updateDirtyStatus(chi::GraphModule& updated, bool dirty) { 292 | // find the item 293 | WorkspaceTree* item; 294 | QModelIndex idx; // get the idx of it so we can emit dataChanged 295 | std::tie(item, idx) = idxFromModuleName(updated.fullName()); 296 | 297 | mModel->dataChanged(idx, idx); 298 | 299 | if (item->name.toStdString() != 300 | fs::path(updated.fullName()).filename().replace_extension("").string()) { 301 | return; 302 | } 303 | 304 | item->dirty = dirty; 305 | } 306 | 307 | std::pair ModuleBrowser::idxFromModuleName(const fs::path& name) { 308 | WorkspaceTree* item = mTree; 309 | QModelIndex idx; // get the idx of it so we can emit dataChanged 310 | for (auto componentIter = name.begin(); componentIter != name.end(); ++componentIter) { 311 | auto component = *componentIter; 312 | 313 | auto id = 0ull; 314 | for (const auto& ch : item->children) { 315 | if (ch->name.toStdString() == component.string() && 316 | (ch->type == WorkspaceTree::MODULE) == (componentIter == --name.end())) { 317 | item = ch.get(); 318 | idx = mModel->index(id, 0, idx); 319 | break; 320 | } 321 | 322 | ++id; 323 | } 324 | } 325 | 326 | return {item, idx}; 327 | } 328 | -------------------------------------------------------------------------------- /src/modulebrowser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_MODULE_BROWSER_HPP 4 | #define CHIGRAPHGUI_MODULE_BROWSER_HPP 5 | 6 | #include 7 | #include 8 | 9 | class MainWindow; 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "toolview.hpp" 18 | 19 | struct WorkspaceTree; 20 | class ModuleTreeModel; 21 | 22 | class ModuleBrowser : public QTreeView, public ToolView { 23 | Q_OBJECT 24 | 25 | // ToolView interface 26 | public: 27 | QWidget* toolView() override { return this; } 28 | Qt::DockWidgetArea defaultArea() const override { return Qt::LeftDockWidgetArea; } 29 | QString label() override { return i18n("Module Browser"); } 30 | QString dockObjectName() override { return QStringLiteral("module-browser"); } 31 | 32 | chi::Context& context() const { return *mContext; } 33 | 34 | public: 35 | ModuleBrowser(QWidget* parent = nullptr); 36 | ~ModuleBrowser(); 37 | 38 | std::unordered_set dirtyModules(); 39 | 40 | ModuleTreeModel* model() { return mModel.get(); } 41 | 42 | signals: 43 | void functionSelected(chi::GraphFunction& func); 44 | void structSelected(chi::GraphStruct& str); 45 | 46 | void functionRenamed(chi::GraphFunction& func, const std::string& oldName, 47 | const std::vector updatedNodes); 48 | void structRenamed(chi::GraphStruct& str, const std::string& oldName, 49 | const std::vector updatedNodes); 50 | 51 | void functionDeleted(chi::GraphModule& mod, const std::string& funcName); 52 | void structDeleted(chi::GraphModule& mod, const std::string& strName); 53 | 54 | public slots: 55 | void loadWorkspace(chi::Context& context); 56 | void moduleDirtied(chi::GraphModule& dirtied); 57 | void moduleSaved(chi::GraphModule& saved); 58 | 59 | private slots: 60 | void newModule(); 61 | void newFunction(); 62 | void newStruct(); 63 | void moduleProperties(); 64 | void deleteItem(); 65 | 66 | private: 67 | void updateDirtyStatus(chi::GraphModule& updated, bool dirty); 68 | std::pair idxFromModuleName(const std::filesystem::path& name); 69 | 70 | chi::Context* mContext = nullptr; 71 | 72 | std::unordered_set mDirtyModules; 73 | 74 | WorkspaceTree* mTree = nullptr; 75 | std::unique_ptr mModel; 76 | 77 | QAction* newModuleAction; 78 | QAction* newFunctionAction; 79 | QAction* newStructAction; 80 | QAction* deleteAction; 81 | QAction* renameAction; 82 | QAction* modulePropertiesAction; 83 | }; 84 | 85 | #endif // CHIGRAPHGUI_MODULE_BROWSER_HPP 86 | -------------------------------------------------------------------------------- /src/modulepropertiesdialog.cpp: -------------------------------------------------------------------------------- 1 | #include "modulepropertiesdialog.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "chiitemselectiondialog.hpp" 13 | 14 | ModulePropertiesDialog::ModulePropertiesDialog(QWidget* parent, chi::GraphModule& modToEdit) 15 | : QDialog{parent}, mModule{&modToEdit} { 16 | setWindowTitle(QString::fromStdString(modToEdit.fullName()) + " - " + i18n("Properties")); 17 | 18 | auto rootLayout = new QVBoxLayout{}; 19 | setLayout(rootLayout); 20 | 21 | // dependencies pane 22 | auto depsList = new QListWidget; 23 | rootLayout->addWidget(depsList); 24 | 25 | // populate it 26 | for (const auto& dep : modToEdit.dependencies()) { 27 | depsList->addItem(QString::fromStdString(dep.string())); 28 | } 29 | 30 | // create new button 31 | auto newDepButton = 32 | new QPushButton{QIcon::fromTheme(QStringLiteral("gtk-add")), i18n("New Dependency")}; 33 | rootLayout->addWidget(newDepButton); 34 | connect(newDepButton, &QPushButton::clicked, this, [this, depsList](bool) { 35 | // open a module selection dialog 36 | 37 | std::filesystem::path newDep = ChiItemSelectionDialog::getItem( 38 | this, mModule->context(), i18n("Select new dependency"), WorkspaceTree::MODULE); 39 | 40 | if (newDep.empty()) { return; } 41 | 42 | if (mModule->dependencies().count(newDep) != 0) { return; } 43 | 44 | // add it to the module 45 | auto res = mModule->addDependency(newDep); 46 | 47 | if (!res) { 48 | KMessageBox::detailedError(this, i18n("Failed to add dependency for module"), 49 | QString::fromStdString(res.dump())); 50 | 51 | return; 52 | } 53 | 54 | // add it to the list 55 | depsList->addItem(QString::fromStdString(newDep.string())); 56 | }); 57 | 58 | // the C support button 59 | auto checkBox = new QCheckBox(i18n("C Support")); 60 | rootLayout->addWidget(checkBox); 61 | 62 | connect(checkBox, &QCheckBox::stateChanged, this, [this](int newState) { 63 | switch (newState) { 64 | case Qt::Unchecked: mModule->setCEnabled(false); return; 65 | case Qt::Checked: mModule->setCEnabled(true); return; 66 | default: return; 67 | } 68 | }); 69 | checkBox->setCheckState(mModule->cEnabled() ? Qt::Checked : Qt::Unchecked); 70 | } 71 | -------------------------------------------------------------------------------- /src/modulepropertiesdialog.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGUI_MODULE_PROPERTIES_DIALOG_HPP 4 | #define CHIGUI_MODULE_PROPERTIES_DIALOG_HPP 5 | 6 | #include 7 | #include 8 | 9 | // for editing properties like dependencies and C support 10 | class ModulePropertiesDialog : public QDialog { 11 | public: 12 | ModulePropertiesDialog(QWidget* parent, chi::GraphModule& modToEdit); 13 | 14 | private: 15 | chi::GraphModule* mModule; 16 | }; 17 | 18 | #endif // CHIGUI_MODULE_PROPERTIES_DIALOG_HPP 19 | -------------------------------------------------------------------------------- /src/moduletreemodel.cpp: -------------------------------------------------------------------------------- 1 | #include "moduletreemodel.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace fs = std::filesystem; 13 | 14 | QIcon ModuleTreeModel::iconForItemType(WorkspaceTree::eType type) { 15 | switch (type) { 16 | case WorkspaceTree::MODULE: return QIcon::fromTheme(QStringLiteral("code-block")); 17 | case WorkspaceTree::FUNCTION: return QIcon::fromTheme(QStringLiteral("code-context")); 18 | case WorkspaceTree::STRUCT: return QIcon::fromTheme(QStringLiteral("code-class")); 19 | case WorkspaceTree::FOLDER: return QIcon::fromTheme(QStringLiteral("stock_folder")); 20 | default: return {}; 21 | } 22 | } 23 | 24 | std::unique_ptr ModuleTreeModel::createFromContext(chi::Context& context, 25 | Filter filter) { 26 | auto modules = context.listModulesInWorkspace(); 27 | 28 | auto tree = std::make_unique(); 29 | 30 | // add src object 31 | auto srcTree = std::make_unique(); 32 | srcTree->parent = tree.get(); 33 | srcTree->type = WorkspaceTree::FOLDER; 34 | srcTree->row = 0; 35 | srcTree->name = QStringLiteral("src"); 36 | 37 | // create the tree 38 | for (const auto& modStr : modules) { 39 | auto mod = fs::path(modStr); 40 | WorkspaceTree* parent = srcTree.get(); 41 | 42 | // for each component of mod 43 | for (auto componentIter = mod.begin(); componentIter != mod.end(); ++componentIter) { 44 | fs::path component = *componentIter; 45 | bool isModule = componentIter == --mod.end(); 46 | 47 | // make sure it exists 48 | bool found = false; 49 | for (const auto& child : parent->children) { 50 | if (child->name.toStdString() == component.string() && 51 | (child->type == WorkspaceTree::MODULE) == isModule) { 52 | found = true; 53 | parent = child.get(); 54 | break; 55 | } 56 | } 57 | if (!found) { 58 | if ((isModule && (filter & ModuleBit)) || (!isModule && (filter & Folders))) { 59 | // insert it 60 | auto newChild = std::make_unique(); 61 | newChild->parent = parent; 62 | newChild->type = isModule ? WorkspaceTree::MODULE : WorkspaceTree::FOLDER; 63 | newChild->row = parent->children.size(); 64 | newChild->name = QString::fromStdString(component.string()); 65 | parent->children.push_back(std::move(newChild)); 66 | 67 | parent = parent->children[parent->children.size() - 1].get(); 68 | } 69 | } 70 | } 71 | } 72 | 73 | tree->children.push_back(std::move(srcTree)); 74 | 75 | return std::make_unique(std::move(tree), context, filter); 76 | } 77 | 78 | void ModuleTreeModel::updateModule(const std::filesystem::path& name) { 79 | auto idx = indexFromName(name, WorkspaceTree::MODULE); 80 | 81 | if (!idx.isValid()) { return; } 82 | 83 | auto tree = static_cast(idx.internalPointer()); 84 | 85 | // don't even bother 86 | if (tree->module == nullptr) { return; } 87 | 88 | // delete all subs 89 | beginRemoveRows(idx, 0, tree->children.size() - 1); 90 | tree->children.clear(); 91 | endRemoveRows(); 92 | 93 | beginInsertRows(idx, 0, 94 | (mFilter & FunctionBit ? tree->module->functions().size() - 1 : 0) + 95 | (mFilter & StructBit ? tree->module->structs().size() - 1 : 0)); 96 | tree->module = nullptr; 97 | fetchMore(idx); 98 | endInsertRows(); 99 | } 100 | 101 | QModelIndex ModuleTreeModel::indexFromName(const std::filesystem::path& name, 102 | WorkspaceTree::eType type) { 103 | auto currentItem = mTree->children[0].get(); 104 | 105 | for (auto iter = name.begin(); iter != name.end(); ++iter) { 106 | bool isLastItem = iter == --name.end(); 107 | auto expectedType = isLastItem ? type : WorkspaceTree::FOLDER; 108 | 109 | bool succeeded = false; 110 | 111 | // find it in the children 112 | for (const auto& item : currentItem->children) { 113 | if (item->name.toStdString() == *iter && item->type == expectedType) { 114 | currentItem = item.get(); 115 | succeeded = true; 116 | break; 117 | } 118 | } 119 | 120 | if (!succeeded) { return {}; } 121 | } 122 | 123 | return createIndex(currentItem->row, 0, currentItem); 124 | } 125 | 126 | int ModuleTreeModel::columnCount(const QModelIndex& parent) const { return 1; } 127 | 128 | QModelIndex ModuleTreeModel::index(int row, int column, const QModelIndex& parent) const { 129 | if (!hasIndex(row, column, parent)) { return {}; } 130 | 131 | WorkspaceTree* parentItem; 132 | if (parent.isValid()) { 133 | parentItem = static_cast(parent.internalPointer()); 134 | } else { 135 | parentItem = tree(); 136 | } 137 | 138 | // make cast valid 139 | Q_ASSERT(row >= 0); 140 | 141 | if ((size_t)row < parentItem->children.size()) { 142 | return createIndex(row, column, parentItem->children[row].get()); 143 | } 144 | return {}; 145 | } 146 | 147 | QModelIndex ModuleTreeModel::parent(const QModelIndex& index) const { 148 | if (!index.isValid()) { return {}; } 149 | 150 | auto childItem = static_cast(index.internalPointer()); 151 | auto parentItem = childItem->parent; 152 | 153 | if (parentItem == tree()) { return {}; } 154 | 155 | return createIndex(parentItem->row, 0, parentItem); 156 | } 157 | 158 | bool ModuleTreeModel::hasChildren(const QModelIndex& index) const { 159 | if (!index.isValid()) { return true; } 160 | 161 | auto item = static_cast(index.internalPointer()); 162 | 163 | // if both struct and function are disabled, then just return false for module 164 | return (item->type == WorkspaceTree::MODULE && 165 | (mFilter & StructBit || mFilter & FunctionBit)) || 166 | item->type == WorkspaceTree::FOLDER; 167 | } 168 | 169 | bool ModuleTreeModel::canFetchMore(const QModelIndex& index) const { 170 | if (!index.isValid()) { return false; } 171 | 172 | auto item = static_cast(index.internalPointer()); 173 | 174 | return item->type == WorkspaceTree::MODULE && (mFilter & StructBit || mFilter & FunctionBit); 175 | } 176 | 177 | void ModuleTreeModel::fetchMore(const QModelIndex& index) { 178 | if (!index.isValid()) { return; } 179 | 180 | auto item = static_cast(index.internalPointer()); 181 | 182 | if (item->module != nullptr) { 183 | // it's already been fetched 184 | return; 185 | } 186 | 187 | // get the name 188 | fs::path p = item->fullName(); 189 | 190 | // load it 191 | chi::ChiModule* mod; 192 | chi::Result res = mCtx->loadModule(p, &mod); 193 | if (!res) { 194 | KMessageBox::detailedError(nullptr, 195 | R"(Failed to load JsonModule from file ")" + 196 | QString::fromStdString(p.string()) + R"(")", 197 | QString::fromStdString(res.dump()), "Error Loading"); 198 | 199 | return; 200 | } 201 | 202 | item->module = static_cast(mod); 203 | 204 | if (mFilter & FunctionBit) { 205 | // add functions 206 | for (const auto& func : item->module->functions()) { 207 | auto child = std::make_unique(); 208 | child->func = func.get(); 209 | child->parent = item; 210 | child->name = QString::fromStdString(func->name()); 211 | child->row = item->children.size(); 212 | child->type = WorkspaceTree::FUNCTION; 213 | 214 | item->children.push_back(std::move(child)); 215 | } 216 | } 217 | 218 | if (mFilter & StructBit) { 219 | // add structs 220 | for (const auto& str : item->module->structs()) { 221 | auto child = std::make_unique(); 222 | child->str = str.get(); 223 | child->name = QString::fromStdString(str->name()); 224 | child->parent = item; 225 | child->row = item->children.size(); 226 | child->type = WorkspaceTree::STRUCT; 227 | 228 | item->children.push_back(std::move(child)); 229 | } 230 | } 231 | } 232 | 233 | int ModuleTreeModel::rowCount(const QModelIndex& index) const { 234 | WorkspaceTree* parentItem; 235 | if (index.isValid()) { 236 | parentItem = static_cast(index.internalPointer()); 237 | } else { 238 | parentItem = tree(); 239 | } 240 | 241 | return parentItem->children.size(); 242 | } 243 | 244 | QVariant ModuleTreeModel::data(const QModelIndex& index, int role) const { 245 | if (!index.isValid()) { return {}; } 246 | 247 | auto item = static_cast(index.internalPointer()); 248 | 249 | switch (role) { 250 | case Qt::DisplayRole: 251 | if (item->dirty) { 252 | return "* " + item->name; 253 | } else { 254 | return item->name; 255 | } 256 | case Qt::DecorationRole: return iconForItemType(item->type); 257 | case Qt::FontRole: 258 | if (item->dirty || (item->parent != nullptr && item->parent->dirty)) { 259 | QFont bold; 260 | bold.setBold(true); 261 | return bold; 262 | } 263 | return {}; 264 | default: return {}; 265 | } 266 | } 267 | 268 | Qt::ItemFlags ModuleTreeModel::flags(const QModelIndex& index) const { 269 | if (!index.isValid()) { return {}; } 270 | 271 | auto item = static_cast(index.internalPointer()); 272 | 273 | Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; 274 | 275 | if (item->type == WorkspaceTree::FUNCTION || item->type == WorkspaceTree::STRUCT) { 276 | flags |= Qt::ItemIsEditable; 277 | } 278 | 279 | return flags; 280 | } 281 | 282 | bool ModuleTreeModel::setData(const QModelIndex& index, const QVariant& value, int role) { 283 | if (!index.isValid()) { return {}; } 284 | 285 | if (role == Qt::EditRole) { 286 | auto item = static_cast(index.internalPointer()); 287 | 288 | if (value.toString().isEmpty()) { return false; } 289 | 290 | switch (item->type) { 291 | case WorkspaceTree::FUNCTION: { 292 | auto oldName = item->func->name(); 293 | 294 | // set the function name 295 | auto nodesToUpdate = item->func->setName(value.toString().toStdString()); 296 | item->name = QString::fromStdString(item->func->name()); 297 | 298 | emit functionRenamed(*item->func, oldName, nodesToUpdate); 299 | 300 | } break; 301 | case WorkspaceTree::STRUCT: { 302 | auto oldName = item->str->name(); 303 | 304 | // set the struct name 305 | auto nodesToUpdate = item->str->setName(value.toString().toStdString()); 306 | item->name = QString::fromStdString(item->str->name()); 307 | 308 | emit structRenamed(*item->str, oldName, nodesToUpdate); 309 | 310 | } break; 311 | default: return false; 312 | } 313 | 314 | dataChanged(index, index, {Qt::DisplayRole}); 315 | return true; 316 | } 317 | 318 | return false; 319 | } 320 | -------------------------------------------------------------------------------- /src/moduletreemodel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_MODULE_TREE_MODEL_HPP 4 | #define CHIGRAPHGUI_MODULE_TREE_MODEL_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct WorkspaceTree { 12 | enum eType { FUNCTION, MODULE, STRUCT, FOLDER }; 13 | 14 | WorkspaceTree* parent = nullptr; 15 | std::vector> children; 16 | chi::GraphModule* module = nullptr; 17 | chi::GraphFunction* func = nullptr; 18 | chi::GraphStruct* str = nullptr; 19 | QString name; 20 | bool dirty = false; 21 | int row = 0; 22 | eType type; 23 | 24 | // get full name 25 | std::filesystem::path fullName() const { 26 | std::filesystem::path ret = name.toStdString(); 27 | 28 | auto parent = this->parent; 29 | while (parent != nullptr) { 30 | // don't ` / ret` when ret is empty to avoid trailing slash 31 | if (ret.empty()) { 32 | ret = parent->name.toStdString(); 33 | } else { 34 | ret = parent->name.toStdString() / ret; 35 | } 36 | parent = parent->parent; 37 | } 38 | 39 | if (ret.string().size() <= 4) { return ""; } 40 | ret = ret.string().substr(4); // remove src/ at the beginning 41 | 42 | return ret; 43 | } 44 | }; 45 | 46 | class ModuleTreeModel : public QAbstractItemModel { 47 | Q_OBJECT 48 | public: 49 | static QIcon iconForItemType(WorkspaceTree::eType type); 50 | 51 | enum Filter { 52 | Folders = 0b1, 53 | ModuleBit = 0b10, 54 | Modules = ModuleBit | Folders, 55 | FunctionBit = 0b100, 56 | Functions = FunctionBit | Folders | Modules, 57 | StructBit = 0b1000, 58 | Structs = StructBit | Folders | Modules, 59 | All = Structs | Functions | Modules | Folders, 60 | }; 61 | 62 | ModuleTreeModel(std::unique_ptr t, chi::Context& ctx, 63 | Filter filter = Filter::All) 64 | : mTree{std::move(t)}, mCtx{&ctx}, mFilter{filter} {} 65 | 66 | // create a model from just the context 67 | static std::unique_ptr createFromContext(chi::Context& context, 68 | Filter filter = Filter::All); 69 | 70 | void updateModule(const std::filesystem::path& name); 71 | 72 | QModelIndex indexFromName(const std::filesystem::path& name, WorkspaceTree::eType type); 73 | 74 | int columnCount(const QModelIndex& parent) const override; 75 | QModelIndex index(int row, int column, const QModelIndex& parent) const override; 76 | QModelIndex parent(const QModelIndex& index) const override; 77 | bool hasChildren(const QModelIndex& index) const override; 78 | bool canFetchMore(const QModelIndex& index) const override; 79 | void fetchMore(const QModelIndex& index) override; 80 | int rowCount(const QModelIndex& index) const override; 81 | QVariant data(const QModelIndex& index, int role) const override; 82 | Qt::ItemFlags flags(const QModelIndex& index) const override; 83 | bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; 84 | 85 | WorkspaceTree* tree() const { return mTree.get(); } 86 | 87 | signals: 88 | void functionRenamed(chi::GraphFunction& func, const std::string& oldName, 89 | const std::vector updatedNodes); 90 | void structRenamed(chi::GraphStruct& str, const std::string& oldName, 91 | const std::vector updatedNodes); 92 | 93 | private: 94 | std::unique_ptr mTree; 95 | chi::Context* mCtx; 96 | Filter mFilter; 97 | }; 98 | 99 | #endif // CHIGRAPHGUI_MODULE_TREE_MODEL_HPP 100 | -------------------------------------------------------------------------------- /src/newmoduledialog.cpp: -------------------------------------------------------------------------------- 1 | #include "newmoduledialog.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "chiitemselectwidget.hpp" 13 | #include "mainwindow.hpp" 14 | 15 | NewModuleDialog::NewModuleDialog(QWidget* parent, chi::Context& context, 16 | const std::filesystem::path& folder) 17 | : QDialog(parent) { 18 | setWindowTitle(i18n("New Module")); 19 | 20 | auto rootLayout = new QVBoxLayout; 21 | setLayout(rootLayout); 22 | 23 | auto proxyWidget = new QWidget; 24 | 25 | auto layout = new QFormLayout(); 26 | proxyWidget->setLayout(layout); 27 | 28 | mFolderWidget = new ChiItemSelectWidget(context, WorkspaceTree::FOLDER); 29 | mFolderWidget->setItem(folder); 30 | mNameEdit = new QLineEdit(); 31 | 32 | auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); 33 | connect(buttonBox, &QDialogButtonBox::accepted, this, [this, &context] { 34 | if (mNameEdit->text().isEmpty()) { return; } 35 | 36 | // create the new module 37 | auto fullPath = mFolderWidget->item() / mNameEdit->text().toStdString(); 38 | 39 | auto mod = context.newGraphModule(fullPath); 40 | mod->addDependency("lang"); 41 | 42 | mod->saveToDisk(); 43 | 44 | MainWindow::instance()->newModuleCreated(*mod); 45 | 46 | accept(); 47 | }); 48 | connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); 49 | 50 | layout->addRow(i18n("Create In"), mFolderWidget); 51 | layout->addRow(i18n("Name"), mNameEdit); 52 | 53 | rootLayout->addWidget(proxyWidget); 54 | rootLayout->addWidget(buttonBox); 55 | } 56 | -------------------------------------------------------------------------------- /src/newmoduledialog.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_NEW_MODULE_DIALOG_HPP 4 | #define CHIGRAPHGUI_NEW_MODULE_DIALOG_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class ChiItemSelectWidget; 11 | class QLineEdit; 12 | 13 | class NewModuleDialog : public QDialog { 14 | public: 15 | NewModuleDialog(QWidget* parent, chi::Context& context, 16 | const std::filesystem::path& folder = ""); 17 | 18 | private: 19 | ChiItemSelectWidget* mFolderWidget; 20 | QLineEdit* mNameEdit; 21 | }; 22 | 23 | #endif // CHIGRAPHGUI_NEW_MODULE_DIALOG_HPP 24 | -------------------------------------------------------------------------------- /src/paramlistwidget.cpp: -------------------------------------------------------------------------------- 1 | #include "paramlistwidget.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "execparamlistwidget.hpp" 16 | #include "functionview.hpp" 17 | #include "typeselector.hpp" 18 | 19 | QStringList createTypeOptions(const chi::GraphModule& mod) { 20 | QStringList ret; 21 | 22 | // add the module 23 | for (const auto& ty : mod.typeNames()) { 24 | ret << QString::fromStdString(mod.fullName() + ":" + ty); 25 | } 26 | 27 | // and its dependencies 28 | for (auto dep : mod.dependencies()) { 29 | auto depMod = mod.context().moduleByFullName(dep); 30 | for (const auto& type : depMod->typeNames()) { 31 | ret << QString::fromStdString(depMod->fullName() + ":" + type); 32 | } 33 | } 34 | return ret; 35 | } 36 | 37 | ParamListWidget::ParamListWidget(QWidget* parent) : QWidget(parent) {} 38 | 39 | void ParamListWidget::setFunction(FunctionView* func, Type ty) { 40 | mFunc = func; 41 | mType = ty; 42 | 43 | if (layout()) { deleteLayout(layout()); } 44 | 45 | auto layout = new QGridLayout; 46 | setLayout(layout); 47 | 48 | // populate it 49 | auto& typeVec = 50 | ty == Input ? mFunc->function()->dataInputs() : mFunc->function()->dataOutputs(); 51 | 52 | auto id = 0; 53 | for (const auto& param : typeVec) { 54 | auto edit = new QLineEdit; 55 | edit->setText(QString::fromStdString(param.name)); 56 | connect(edit, &QLineEdit::textChanged, this, [this, id](const QString& newText) { 57 | if (mType == Input) { 58 | mFunc->function()->renameDataInput(id, newText.toStdString()); 59 | refreshEntry(); 60 | } else { 61 | mFunc->function()->renameDataOutput(id, newText.toStdString()); 62 | refreshExits(); 63 | } 64 | dirtied(); 65 | }); 66 | layout->addWidget(edit, id, 0, Qt::AlignTop); 67 | 68 | auto tySelector = new TypeSelector(mFunc->function()->module()); 69 | tySelector->setCurrentType(param.type); 70 | connect(tySelector, &TypeSelector::typeSelected, this, 71 | [this, id](const chi::DataType& newType) { 72 | if (!newType.valid()) { return; } 73 | 74 | if (mType == Input) { 75 | mFunc->function()->retypeDataInput(id, newType); 76 | refreshEntry(); 77 | } else { 78 | mFunc->function()->retypeDataOutput(id, newType); 79 | refreshExits(); 80 | } 81 | dirtied(); 82 | }); 83 | layout->addWidget(tySelector, id, 1, Qt::AlignTop); 84 | 85 | auto deleteButton = new QPushButton(QIcon::fromTheme(QStringLiteral("list-remove")), {}); 86 | connect(deleteButton, &QAbstractButton::clicked, this, [this, id](bool) { 87 | if (mType == Input) { 88 | mFunc->function()->removeDataInput(id); 89 | refreshEntry(); 90 | setFunction(mFunc, mType); 91 | } else { 92 | mFunc->function()->removeDataOutput(id); 93 | refreshExits(); 94 | setFunction(mFunc, mType); 95 | } 96 | dirtied(); 97 | }); 98 | layout->addWidget(deleteButton, id, 2, Qt::AlignTop); 99 | 100 | ++id; 101 | } 102 | 103 | // create the "new" button 104 | auto newButton = new QPushButton(QIcon::fromTheme("list-add"), {}); 105 | newButton->setSizePolicy({QSizePolicy::Maximum, QSizePolicy::Maximum}); 106 | connect(newButton, &QAbstractButton::clicked, this, [this](bool) { 107 | if (mType == Input) { 108 | mFunc->function()->addDataInput( 109 | mFunc->function()->context().moduleByFullName("lang")->typeFromName("i32"), ""); 110 | refreshEntry(); 111 | 112 | setFunction(mFunc, mType); // TODO: not the most efficient way... 113 | } else { 114 | mFunc->function()->addDataOutput( 115 | mFunc->function()->context().moduleByFullName("lang")->typeFromName("i32"), ""); 116 | refreshExits(); 117 | 118 | setFunction(mFunc, mType); 119 | } 120 | dirtied(); 121 | }); 122 | layout->addWidget(newButton, id, 2, Qt::AlignRight | Qt::AlignTop); 123 | } 124 | 125 | void ParamListWidget::refreshEntry() { 126 | auto entry = mFunc->function()->entryNode(); 127 | if (entry == nullptr) { return; } 128 | mFunc->refreshGuiForNode(*entry); 129 | } 130 | void ParamListWidget::refreshExits() { 131 | for (const auto& exit : mFunc->function()->nodesWithType("lang", "exit")) { 132 | mFunc->refreshGuiForNode(*exit); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/paramlistwidget.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGGUI_PARAMLISTWIDGET_HPP 4 | #define CHIGGUI_PARAMLISTWIDGET_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class FunctionView; 11 | 12 | QStringList createTypeOptions(const chi::GraphModule& mod); 13 | 14 | class ParamListWidget : public QWidget { 15 | Q_OBJECT 16 | 17 | public: 18 | enum Type { Input, Output }; 19 | 20 | explicit ParamListWidget(QWidget* parent = nullptr); 21 | 22 | void setFunction(FunctionView* func, Type ty); 23 | signals: 24 | void dirtied(); 25 | 26 | private: 27 | void refreshEntry(); 28 | void refreshExits(); 29 | 30 | FunctionView* mFunc = nullptr; 31 | Type mType = Input; 32 | }; 33 | 34 | #endif // CHIGGUI_PARAMLISTWIDGET_HPP 35 | -------------------------------------------------------------------------------- /src/structedit.cpp: -------------------------------------------------------------------------------- 1 | #include "structedit.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "centraltabview.hpp" 14 | #include "execparamlistwidget.hpp" 15 | #include "functionview.hpp" 16 | #include "typeselector.hpp" 17 | 18 | StructEdit::StructEdit(chi::GraphStruct& str, CentralTabView* centralTabWidget) 19 | : mStruct{&str}, mTabs{centralTabWidget} { 20 | makeGUI(); 21 | } 22 | 23 | void StructEdit::makeGUI() { 24 | // destroy the previous layout 25 | if (auto oldLay = layout()) { deleteLayout(oldLay); } 26 | 27 | auto layout = new QGridLayout; 28 | setLayout(layout); 29 | 30 | auto id = 0; 31 | for (const auto& namedType : mStruct->types()) { 32 | auto edit = new QLineEdit; 33 | edit->setText(QString::fromStdString(namedType.name)); 34 | 35 | connect(edit, &QLineEdit::textChanged, this, [this, id](const QString& newText) { 36 | mStruct->modifyType(id, mStruct->types()[id].type, newText.toStdString()); 37 | refreshReferences(); 38 | }); 39 | layout->addWidget(edit, id, 0); 40 | 41 | auto tySelector = new TypeSelector(mStruct->module()); 42 | tySelector->setCurrentType(namedType.type); 43 | connect(tySelector, &TypeSelector::typeSelected, this, 44 | [this, id](const chi::DataType& newType) { 45 | if (!newType.valid()) { return; } 46 | 47 | mStruct->modifyType(id, newType, mStruct->types()[id].name); 48 | 49 | refreshReferences(); 50 | }); 51 | layout->addWidget(tySelector, id, 1, Qt::AlignTop); 52 | 53 | auto deleteButton = new QPushButton(QIcon::fromTheme(QStringLiteral("list-remove")), {}); 54 | connect(deleteButton, &QAbstractButton::clicked, this, [this, id](bool) { 55 | mStruct->removeType(id); 56 | refreshReferences(); 57 | 58 | makeGUI(); 59 | }); 60 | layout->addWidget(deleteButton, id, 2); 61 | 62 | ++id; 63 | } 64 | 65 | // create the "new" button 66 | auto newButton = new QPushButton(QIcon::fromTheme("list-add"), {}); 67 | newButton->setSizePolicy({QSizePolicy::Maximum, QSizePolicy::Maximum}); 68 | connect(newButton, &QAbstractButton::clicked, this, [this](bool) { 69 | mStruct->addType(mStruct->context().langModule()->typeFromName("i32"), {}, 70 | mStruct->types().size()); 71 | 72 | refreshReferences(); 73 | 74 | makeGUI(); 75 | }); 76 | layout->addWidget(newButton, id, 2, Qt::AlignRight); 77 | 78 | layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding), id + 1, 0); 79 | } 80 | 81 | void StructEdit::refreshReferences() { 82 | auto& ctx = mStruct->context(); 83 | 84 | auto allInstances = 85 | ctx.findInstancesOfType(mStruct->module().fullNamePath(), "_make_" + mStruct->name()); 86 | auto breakInstances = 87 | ctx.findInstancesOfType(mStruct->module().fullNamePath(), "_break_" + mStruct->name()); 88 | 89 | allInstances.reserve(allInstances.size() + breakInstances.size()); 90 | std::copy(breakInstances.begin(), breakInstances.end(), std::back_inserter(allInstances)); 91 | 92 | // just refresh the gui 93 | for (auto inst : allInstances) { 94 | auto view = mTabs->viewFromFunction(inst->function()); 95 | 96 | if (view != nullptr) { view->refreshGuiForNode(*inst); } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/structedit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_STRUCT_EDIT_HPP 4 | #define CHIGRAPHGUI_STRUCT_EDIT_HPP 5 | 6 | #include 7 | #include 8 | 9 | class CentralTabView; 10 | 11 | class StructEdit : public QWidget { 12 | Q_OBJECT 13 | public: 14 | explicit StructEdit(chi::GraphStruct& str, CentralTabView* tabWidget); 15 | 16 | private: 17 | void makeGUI(); 18 | 19 | void refreshReferences(); 20 | 21 | chi::GraphStruct* mStruct; 22 | CentralTabView* mTabs; 23 | }; 24 | 25 | #endif // CHIGRAPHGUI_STRUCT_EDIT_HPP 26 | -------------------------------------------------------------------------------- /src/subprocessoutputview.cpp: -------------------------------------------------------------------------------- 1 | #include "subprocessoutputview.hpp" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace fs = std::filesystem; 19 | 20 | SubprocessOutputView::SubprocessOutputView(chi::GraphModule* module) : mModule(module) { 21 | // compile! 22 | chi::OwnedLLVMModule llmod; 23 | chi::Result res = 24 | module->context().compileModule(module->fullName(), chi::CompileSettings::Default, &llmod); 25 | 26 | if (!res) { 27 | KMessageBox::detailedError(this, "Failed to compile module", 28 | QString::fromStdString(res.dump())); 29 | 30 | return; 31 | } 32 | 33 | // write it to a temporary file 34 | fs::path tempBitcodeFile = chi::makeTempPath(".bc"); 35 | LLVMWriteBitcodeToFile(*llmod, tempBitcodeFile.string().c_str()); 36 | setReadOnly(true); 37 | 38 | std::filesystem::path chiPath = 39 | std::filesystem::path(QApplication::applicationFilePath().toStdString()).parent_path() / 40 | "chi"; 41 | #ifdef _WIN32 42 | chiPath.replace_extension(".exe"); 43 | #endif 44 | 45 | Q_ASSERT(std::filesystem::is_regular_file(chiPath)); 46 | 47 | // run in lli 48 | mProcess = new QProcess(this); 49 | mProcess->setProgram(QString::fromStdString(chiPath.string())); 50 | 51 | auto args = QStringList() << QStringLiteral("interpret") << QStringLiteral("-i") 52 | << QString::fromStdString(tempBitcodeFile.string()) 53 | << QStringLiteral("-O2"); 54 | mProcess->setArguments(args); 55 | 56 | connect(mProcess, &QProcess::readyReadStandardOutput, this, 57 | [this] { appendPlainText(mProcess->readAllStandardOutput().constData()); }); 58 | 59 | connect(mProcess, &QProcess::readyReadStandardOutput, this, [this] { 60 | appendHtml("" + 61 | QString(mProcess->readAllStandardOutput().constData()).toHtmlEscaped() + 62 | ""); 63 | }); 64 | 65 | connect(mProcess, 66 | static_cast(&QProcess::finished), this, 67 | &SubprocessOutputView::processFinished); 68 | 69 | mProcess->start(); 70 | } 71 | 72 | void SubprocessOutputView::cancelProcess() { 73 | if (mProcess != nullptr) { mProcess->kill(); } 74 | } 75 | -------------------------------------------------------------------------------- /src/subprocessoutputview.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGGUI_SUBPROCESS_OUTPUT_VIEW_HPP 4 | #define CHIGGUI_SUBPROCESS_OUTPUT_VIEW_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class SubprocessOutputView : public QPlainTextEdit { 11 | Q_OBJECT 12 | public: 13 | SubprocessOutputView(chi::GraphModule* module); 14 | void cancelProcess(); 15 | 16 | chi::GraphModule* module() const { return mModule; } 17 | bool running() const { return mProcess != nullptr && mProcess->state() == QProcess::Running; } 18 | signals: 19 | void processFinished(int exitCode, QProcess::ExitStatus exitStatus); 20 | 21 | private: 22 | chi::GraphModule* mModule; 23 | QProcess* mProcess = nullptr; 24 | }; 25 | 26 | #endif // CHIGGUI_SUBPROCESS_OUTPUT_VIEW_HPP 27 | -------------------------------------------------------------------------------- /src/thememanager.cpp: -------------------------------------------------------------------------------- 1 | #include "thememanager.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | ThemeManager::ThemeManager(KActionMenu* menu) : mMenu{menu} { 18 | Q_ASSERT(menu != nullptr); 19 | 20 | // clear the menu 21 | mMenu->menu()->clear(); 22 | 23 | mActGroup = std::make_unique(mMenu); 24 | 25 | connect(mActGroup.get(), &QActionGroup::triggered, this, &ThemeManager::changePalette); 26 | 27 | // create the default skin 28 | auto defAct = new QAction(QStringLiteral("Default"), mActGroup.get()); 29 | defAct->setCheckable(true); 30 | mMenu->addAction(defAct); 31 | 32 | auto availThemes = availableThemeFiles(); 33 | availThemes.sort(); 34 | 35 | for (const auto& themeFilename : availThemes) { 36 | // load the config 37 | auto config = KSharedConfig::openConfig(themeFilename); 38 | 39 | // create a simple theme icon 40 | auto themeIcon = createSchemePreviewIcon(config); 41 | 42 | // read the name of the theme 43 | auto group = KConfigGroup{config, "General"}; 44 | auto info = QFileInfo{themeFilename}; 45 | const auto& name = group.readEntry("Name", info.baseName()); 46 | 47 | // create the action 48 | auto action = new QAction(name, mActGroup.get()); 49 | action->setIcon(themeIcon); 50 | action->setCheckable(true); 51 | 52 | // add it to the map 53 | mThemeNameToFile[name] = themeFilename; 54 | 55 | // add it to the menu 56 | mMenu->addAction(action); 57 | } 58 | 59 | // add the configuration dialog to the end 60 | mMenu->addSeparator(); 61 | auto configAct = new QAction(i18n("Configuration..."), mMenu); 62 | configAct->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-theme"))); 63 | mMenu->addAction(configAct); 64 | connect(configAct, &QAction::triggered, this, [this] { 65 | // open the colors dialog 66 | auto job = new KIO::CommandLauncherJob(QStringLiteral("kcmshell5 colors")); 67 | job->setAutoDelete(true); 68 | job->start(); 69 | 70 | connect(job, &KIO::CommandLauncherJob::finished, this, [](KJob* job) { 71 | if (job->error() != 0) { 72 | KMessageBox::error( 73 | 0, i18n("Cannot start Colors Settings panel from KDE Control Center. " 74 | "Please check your system...")); 75 | } 76 | }); 77 | }); 78 | } 79 | 80 | QIcon ThemeManager::createSchemePreviewIcon(const KSharedConfigPtr& config) const { 81 | const uchar bits1[] = {0xff, 0xff, 0xff, 0x2c, 0x16, 0x0b}; 82 | const uchar bits2[] = {0x68, 0x34, 0x1a, 0xff, 0xff, 0xff}; 83 | const QSize bitsSize(24, 2); 84 | const QBitmap b1 = QBitmap::fromData(bitsSize, bits1); 85 | const QBitmap b2 = QBitmap::fromData(bitsSize, bits2); 86 | 87 | QPixmap pixmap(23, 16); 88 | pixmap.fill(Qt::black); // FIXME use some color other than black for borders? 89 | 90 | KConfigGroup group(config, "WM"); 91 | QPainter p(&pixmap); 92 | KColorScheme windowScheme(QPalette::Active, KColorScheme::Window, config); 93 | p.fillRect(1, 1, 7, 7, windowScheme.background()); 94 | p.fillRect(2, 2, 5, 2, QBrush(windowScheme.foreground().color(), b1)); 95 | 96 | KColorScheme buttonScheme(QPalette::Active, KColorScheme::Button, config); 97 | p.fillRect(8, 1, 7, 7, buttonScheme.background()); 98 | p.fillRect(9, 2, 5, 2, QBrush(buttonScheme.foreground().color(), b1)); 99 | 100 | p.fillRect(15, 1, 7, 7, group.readEntry("activeBackground", QColor(96, 148, 207))); 101 | p.fillRect(16, 2, 5, 2, QBrush(group.readEntry("activeForeground", QColor(255, 255, 255)), b1)); 102 | 103 | KColorScheme viewScheme(QPalette::Active, KColorScheme::View, config); 104 | p.fillRect(1, 8, 7, 7, viewScheme.background()); 105 | p.fillRect(2, 12, 5, 2, QBrush(viewScheme.foreground().color(), b2)); 106 | 107 | KColorScheme selectionScheme(QPalette::Active, KColorScheme::Selection, config); 108 | p.fillRect(8, 8, 7, 7, selectionScheme.background()); 109 | p.fillRect(9, 12, 5, 2, QBrush(selectionScheme.foreground().color(), b2)); 110 | 111 | p.fillRect(15, 8, 7, 7, group.readEntry("inactiveBackground", QColor(224, 223, 222))); 112 | p.fillRect(16, 12, 5, 2, QBrush(group.readEntry("inactiveForeground", QColor(20, 19, 18)), b2)); 113 | 114 | p.end(); 115 | return pixmap; 116 | } 117 | 118 | QStringList ThemeManager::availableThemeFiles() const { 119 | const auto colorSchemeLocs = 120 | QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, 121 | QStringLiteral("color-schemes"), QStandardPaths::LocateDirectory); 122 | 123 | QStringList ret; 124 | for (const auto& colorDirName : colorSchemeLocs) { 125 | auto dir = QDir{colorDirName}; 126 | 127 | for (const auto& scheme : dir.entryList(QStringList("*.colors"), QDir::Files)) { 128 | ret << dir.absoluteFilePath(scheme); 129 | } 130 | } 131 | 132 | return ret; 133 | } 134 | 135 | void ThemeManager::changePalette() { setTheme(theme()); } 136 | 137 | void ThemeManager::setTheme(const QString& name) { 138 | QString themeName = name; 139 | 140 | if (themeName.isEmpty()) { themeName = QStringLiteral("Default"); } 141 | 142 | auto filename = mThemeNameToFile.value(themeName, QStringLiteral("Default")); 143 | 144 | KSharedConfigPtr config = KSharedConfig::openConfig(filename); 145 | qApp->setPalette(KColorScheme::createApplicationPalette(config)); 146 | } 147 | QString ThemeManager::theme() { 148 | auto currentAct = mActGroup->checkedAction(); 149 | 150 | if (currentAct != nullptr) { return currentAct->text().remove('&'); } 151 | return QStringLiteral("Default"); 152 | } 153 | -------------------------------------------------------------------------------- /src/thememanager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGGUI_THEME_MANAER_HPP 4 | #define CHIGGUI_THEME_MANAER_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class ThemeManager : public QObject { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit ThemeManager(KActionMenu* menu); 16 | 17 | void setTheme(const QString& name); 18 | QString theme(); 19 | QStringList availableThemeFiles() const; 20 | QIcon createSchemePreviewIcon(const KSharedConfigPtr& ptr) const; 21 | 22 | private: 23 | void changePalette(); 24 | 25 | KActionMenu* mMenu; 26 | 27 | std::unique_ptr mActGroup; 28 | 29 | QMap mThemeNameToFile; 30 | }; 31 | 32 | #endif // CHIGGUI_THEME_MANAER_HPP 33 | -------------------------------------------------------------------------------- /src/toolview.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGRAPHGUI_TOOL_VIEW_HPP 4 | #define CHIGRAPHGUI_TOOL_VIEW_HPP 5 | 6 | #include 7 | 8 | class ToolView : public KXMLGUIClient { 9 | public: 10 | virtual QWidget* toolView() = 0; 11 | virtual Qt::DockWidgetArea defaultArea() const = 0; 12 | virtual QString label() = 0; 13 | virtual QString dockObjectName() = 0; 14 | }; 15 | 16 | #endif // CHIGRAPHGUI_TOOL_VIEW_HPP 17 | -------------------------------------------------------------------------------- /src/typeselector.cpp: -------------------------------------------------------------------------------- 1 | #include "typeselector.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace { 12 | 13 | class StringListValidator : public QValidator { 14 | public: 15 | explicit StringListValidator(QStringList acceptableValues) 16 | : mAcceptableValues{std::move(acceptableValues)} {} 17 | 18 | State validate(QString& input, int& pos) const override { 19 | if (mAcceptableValues.contains(input)) { return Acceptable; } 20 | return Intermediate; 21 | } 22 | 23 | private: 24 | QStringList mAcceptableValues; 25 | }; 26 | 27 | } // anonymous namespace 28 | 29 | TypeSelector::TypeSelector(chi::ChiModule& module, QWidget* parent) 30 | : KComboBox(true, parent), mModule{&module} { 31 | KCompletion* completer = completionObject(); 32 | 33 | setCompletionMode(KCompletion::CompletionPopupAuto); 34 | 35 | QStringList possibleTypes; 36 | // add the module 37 | for (const auto& ty : module.typeNames()) { 38 | possibleTypes << QString::fromStdString(module.fullName() + ":" + ty); 39 | } 40 | 41 | // and its dependencies 42 | for (auto dep : module.dependencies()) { 43 | auto depMod = module.context().moduleByFullName(dep); 44 | for (const auto& type : depMod->typeNames()) { 45 | possibleTypes << QString::fromStdString(depMod->fullName() + ":" + type); 46 | } 47 | } 48 | 49 | completer->setItems(possibleTypes); 50 | setValidator(new StringListValidator(std::move(possibleTypes))); 51 | 52 | connect(this, static_cast(&KComboBox::returnPressed), this, 53 | [this](const QString&){ typeSelected(currentType()); }); 54 | } 55 | 56 | void TypeSelector::setCurrentType(const chi::DataType& ty) { 57 | setCurrentText(QString::fromStdString(ty.qualifiedName())); 58 | } 59 | 60 | chi::DataType TypeSelector::currentType() { 61 | std::string mod, name; 62 | std::tie(mod, name) = chi::parseColonPair(currentText().toStdString()); 63 | 64 | chi::DataType ty; 65 | auto res = mModule->context().typeFromModule(mod, name, &ty); 66 | if (!res) { 67 | KMessageBox::detailedError(this, i18n("Failed to get type"), 68 | QString::fromStdString(res.dump())); 69 | return {}; 70 | } 71 | 72 | return ty; 73 | } 74 | -------------------------------------------------------------------------------- /src/typeselector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHIGGUI_TYPE_SELECTOR_HPP 4 | #define CHIGGUI_TYPE_SELECTOR_HPP 5 | 6 | #include 7 | #include 8 | 9 | class TypeSelector : public KComboBox { 10 | Q_OBJECT 11 | public: 12 | explicit TypeSelector(chi::ChiModule& module, QWidget* parent = nullptr); 13 | 14 | void setCurrentType(const chi::DataType& ty); 15 | chi::DataType currentType(); 16 | 17 | signals: 18 | 19 | void typeSelected(const chi::DataType& type); 20 | 21 | private: 22 | chi::ChiModule* mModule; 23 | }; 24 | 25 | #endif // CHIGGUI_TYPE_SELECTOR_HPP 26 | -------------------------------------------------------------------------------- /third_party/.gitignore: -------------------------------------------------------------------------------- 1 | flexbison-win32.tar.xz 2 | flexbison-win32/ 3 | 4 | gettext-win64.tar.xz 5 | gettext-win64/ 6 | 7 | iconv-win64.tar.xz 8 | iconv-win64/ 9 | 10 | zlib-win64.tar.xz 11 | zlib-win64 12 | 13 | kf5-5.30.0-debug-msvc14-win64.tar.xz 14 | kf5-debug/ 15 | 16 | kf5-5.30.0-release-msvc14-win64.tar.xz 17 | kf5-release/ 18 | --------------------------------------------------------------------------------