velesbh commited on
Commit
a87d9a5
·
verified ·
1 Parent(s): a2809e3

Upload 56 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +2 -34
  2. .github/workflows/codeql.yml +92 -0
  3. .gitignore +6 -3
  4. LICENSE +201 -0
  5. README.md +118 -15
  6. banner.jpeg +0 -0
  7. build.py +41 -0
  8. codes/Demo/pom.xml +54 -0
  9. codes/Demo/src/main/java/org/cubegpt/54672e99/Main.java +30 -0
  10. codes/Demo/src/main/resources/config.yml +1 -0
  11. codes/Demo/src/main/resources/plugin.yml +10 -0
  12. codes/Demo/target/Demo-1.0-SNAPSHOT.jar +0 -0
  13. codes/Demo/target/classes/config.yml +1 -0
  14. codes/Demo/target/classes/org/cubegpt/54672e99/Main.class +0 -0
  15. codes/Demo/target/classes/plugin.yml +10 -0
  16. codes/Demo/target/maven-archiver/pom.properties +3 -0
  17. codes/Demo/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +1 -0
  18. codes/Demo/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +1 -0
  19. codes/ExamplePlugin4/pom.xml +40 -0
  20. codes/ExamplePlugin4/src/main/java/org/cubegpt/188eba63/Main.java +20 -0
  21. codes/ExamplePlugin4/src/main/resources/config.yml +1 -0
  22. codes/ExamplePlugin4/src/main/resources/plugin.yml +5 -0
  23. codes/ExamplePlugin4/target/ExamplePlugin4-1.0-SNAPSHOT.jar +0 -0
  24. codes/ExamplePlugin4/target/classes/config.yml +1 -0
  25. codes/ExamplePlugin4/target/classes/org/cubegpt/188eba63/Main.class +0 -0
  26. codes/ExamplePlugin4/target/classes/plugin.yml +5 -0
  27. codes/ExamplePlugin4/target/maven-archiver/pom.properties +3 -0
  28. codes/ExamplePlugin4/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +1 -0
  29. codes/ExamplePlugin4/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +1 -0
  30. config.py +60 -0
  31. config.yaml +90 -0
  32. console.py +121 -0
  33. core.py +177 -0
  34. cube_qgui/__init__.py +18 -0
  35. cube_qgui/__main__.py +122 -0
  36. cube_qgui/banner_tools.py +106 -0
  37. cube_qgui/base_frame.py +286 -0
  38. cube_qgui/base_tools.py +212 -0
  39. cube_qgui/factory.py +168 -0
  40. cube_qgui/manager.py +80 -0
  41. cube_qgui/notebook_tools.py +952 -0
  42. cube_qgui/os_tools.py +45 -0
  43. cube_qgui/resources/demo/panda.jpg +0 -0
  44. cube_qgui/resources/icon/double_down.png +0 -0
  45. cube_qgui/resources/icon/double_up.png +0 -0
  46. cube_qgui/resources/icon/github.png +0 -0
  47. cube_qgui/resources/icon/play_w.png +0 -0
  48. cube_qgui/resources/icon/up_cloud.png +0 -0
  49. cube_qgui/theme/ttkbootstrap_themes.json +104 -0
  50. cube_qgui/third_party/__init__.py +4 -0
.gitattributes CHANGED
@@ -1,34 +1,2 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tflite filter=lfs diff=lfs merge=lfs -text
29
- *.tgz filter=lfs diff=lfs merge=lfs -text
30
- *.wasm filter=lfs diff=lfs merge=lfs -text
31
- *.xz filter=lfs diff=lfs merge=lfs -text
32
- *.zip filter=lfs diff=lfs merge=lfs -text
33
- *.zst filter=lfs diff=lfs merge=lfs -text
34
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.github/workflows/codeql.yml ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # For most projects, this workflow file will not need changing; you simply need
2
+ # to commit it to your repository.
3
+ #
4
+ # You may wish to alter this file to override the set of languages analyzed,
5
+ # or to provide custom queries or build logic.
6
+ #
7
+ # ******** NOTE ********
8
+ # We have attempted to detect the languages in your repository. Please check
9
+ # the `language` matrix defined below to confirm you have the correct set of
10
+ # supported CodeQL languages.
11
+ #
12
+ name: "CodeQL"
13
+
14
+ on:
15
+ push:
16
+ branches: [ "main" ]
17
+ pull_request:
18
+ branches: [ "main" ]
19
+ schedule:
20
+ - cron: '17 3 * * 1'
21
+
22
+ jobs:
23
+ analyze:
24
+ name: Analyze (${{ matrix.language }})
25
+ # Runner size impacts CodeQL analysis time. To learn more, please see:
26
+ # - https://gh.io/recommended-hardware-resources-for-running-codeql
27
+ # - https://gh.io/supported-runners-and-hardware-resources
28
+ # - https://gh.io/using-larger-runners (GitHub.com only)
29
+ # Consider using larger runners or machines with greater resources for possible analysis time improvements.
30
+ runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
31
+ timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
32
+ permissions:
33
+ # required for all workflows
34
+ security-events: write
35
+
36
+ # required to fetch internal or private CodeQL packs
37
+ packages: read
38
+
39
+ # only required for workflows in private repositories
40
+ actions: read
41
+ contents: read
42
+
43
+ strategy:
44
+ fail-fast: false
45
+ matrix:
46
+ include:
47
+ - language: python
48
+ build-mode: none
49
+ # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
50
+ # Use `c-cpp` to analyze code written in C, C++ or both
51
+ # Use 'java-kotlin' to analyze code written in Java, Kotlin or both
52
+ # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
53
+ # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
54
+ # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
55
+ # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
56
+ # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
57
+ steps:
58
+ - name: Checkout repository
59
+ uses: actions/checkout@v4
60
+
61
+ # Initializes the CodeQL tools for scanning.
62
+ - name: Initialize CodeQL
63
+ uses: github/codeql-action/init@v3
64
+ with:
65
+ languages: ${{ matrix.language }}
66
+ build-mode: ${{ matrix.build-mode }}
67
+ # If you wish to specify custom queries, you can do so here or in a config file.
68
+ # By default, queries listed here will override any specified in a config file.
69
+ # Prefix the list here with "+" to use these queries and those in the config file.
70
+
71
+ # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
72
+ # queries: security-extended,security-and-quality
73
+
74
+ # If the analyze step fails for one of the languages you are analyzing with
75
+ # "We were unable to automatically build your code", modify the matrix above
76
+ # to set the build mode to "manual" for that language. Then modify this step
77
+ # to build your code.
78
+ # ℹ️ Command-line programs to run using the OS shell.
79
+ # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
80
+ - if: matrix.build-mode == 'manual'
81
+ run: |
82
+ echo 'If you are using a "manual" build mode for one or more of the' \
83
+ 'languages you are analyzing, replace this with the commands to build' \
84
+ 'your code, for example:'
85
+ echo ' make bootstrap'
86
+ echo ' make release'
87
+ exit 1
88
+
89
+ - name: Perform CodeQL Analysis
90
+ uses: github/codeql-action/analyze@v3
91
+ with:
92
+ category: "/language:${{matrix.language}}"
.gitignore CHANGED
@@ -1,4 +1,7 @@
1
-
2
- .venv/
3
  __pycache__
4
- .DS_Store
 
 
 
 
 
 
 
 
1
  __pycache__
2
+ generated/*
3
+ temp/*
4
+ build/*
5
+ logs/*
6
+ test.py
7
+ _config.yaml
LICENSE ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.
README.md CHANGED
@@ -1,20 +1,123 @@
1
- ---
2
- title: Bukkitgpt
3
- emoji: 🌍
4
- colorFrom: yellow
5
- colorTo: indigo
6
- sdk: docker
7
- pinned: false
8
- license: mit
9
- ---
 
 
 
10
 
11
- This is a templated Space for [Shiny for Python](https://shiny.rstudio.com/py/).
 
12
 
 
 
13
 
14
- To get started with a new app do the following:
15
 
16
- 1) Install Shiny with `pip install shiny`
17
- 2) Create a new app with `shiny create .`
18
- 3) Then run the app with `shiny run --reload`
19
 
20
- To learn more about this framework please see the [Documentation](https://shiny.rstudio.com/py/docs/overview.html).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div align="center">
2
+ <img src="https://github.com/CubeGPT/CubeAgents/blob/master/banner.jpeg?raw=true"/>
3
+ <img src="https://img.shields.io/badge/Cube-Agents-blue">
4
+ <a href="https://github.com/CubeGPT/BuilderGPT/pulls"><img src="https://img.shields.io/badge/PRs-welcome-20BF20"></a>
5
+ <img src="https://img.shields.io/badge/License-Apache-red">
6
+ <a href="https://discord.gg/kTZtXw8s7r"><img src="https://img.shields.io/discord/1212765516532289587
7
+ "></a>
8
+ <!-- <p>English | <a href="https://github.com/CubeGPT/CubeAgents/blob/master/README-zh_cn.md">简体中文</a></p> -->
9
+ <br>
10
+ <a href="https://discord.gg/kTZtXw8s7r">Join our discord</a>
11
+ <br/>
12
+ </div>
13
 
14
+ > [!NOTE]
15
+ > Developers and translators are welcome to join the CubeGPT Team!
16
 
17
+ ## Introduction
18
+ > Give GPT your idea, AI generates customized Minecraft server plugins with one click, which is suitable for Bukkit, Spigot, Paper, Purpur, Arclight, CatServer, Magma, Mohist and other Bukkit-based servers.
19
 
20
+ BukkitGPT is an open source, free, AI-powered Minecraft Bukkit plugin generator. It was developed for minecraft server owners who are not technically savvy but need to implement all kinds of customized small plugins. From code to build, debug, all done by gpt.
21
 
22
+ ## WebApp
23
+ Don't want to prepare the Python & Maven environment? Try our [WebApp](http://cubegpt.org/), designed for non-developers, just enter the plugin name and description, and you can get the plugin jar file.
 
24
 
25
+ *The service is paid since the API key we are using is not free. You can get 1 key for 5 generations for $1 [here](https://buymeacoffee.com/baimoqilin/e/293180) or [here (for Chinese users)](https://afdian.com/item/b839835461e311efbd1252540025c377)
26
+
27
+ ## Partner
28
+ [![](https://www.bisecthosting.com/partners/custom-banners/c37f58c7-c49b-414d-b53c-1a6e1b1cff71.webp)](https://bisecthosting.com/cubegpt)
29
+
30
+ ## Features
31
+
32
+ ### Core
33
+ - Automatically generate code
34
+ - Automatically fix bugs
35
+ - AI `Better Description`
36
+
37
+ ### GUI
38
+ - Creating projects
39
+ - Projects management
40
+
41
+ ## Plans and TODOs
42
+
43
+ Moved to [Projects Tab](https://github.com/orgs/CubeGPT/projects/4).
44
+
45
+ ### Other projects of CubeGPT Team
46
+ - [x] Bukkit plugin generator. {*.jar} ([BukkitGPT-v3](https://github.com/CubeGPT/BukkitGPT-v3))
47
+ - [ ] Structure generator. {*.schem} (BuilderGPT, or something?)
48
+ - [ ] Serverpack generator. {*.zip} (ServerpackGPT or ServerGPT, or..?)
49
+ - [ ] Have ideas or want to join our team? Send [us](mailto:[email protected]) an email!
50
+
51
+ ## How it works
52
+ When the user types the plugin description, the program lets `gpt-3.5-turbo` optimize the prompt, and then gives the optimized prompt to `gpt-4-turbo-preview`. `gpt-4-turbo-preview` will return it in json format, for example:
53
+ ```
54
+ {
55
+ "output": [
56
+ {
57
+ "file": "%WORKING_PATH%/Main.java",
58
+ "code": "package ...;\nimport org.bukkit.Bukkit;\npublic class Main extends JavaPlugin implements CommandExecutor {\n..."
59
+ },
60
+ {
61
+ "file": "src/main/resources/plugin.yml",
62
+ "code": "name: ...\nversion: ...\n..."
63
+ },
64
+ {
65
+ "file\": "src/main/resources/config.yml",
66
+ "code\": "..."
67
+ },
68
+ {
69
+ "file": "pom.xml",
70
+ "code": "..."
71
+ }
72
+ ]
73
+ }
74
+ ```
75
+ The program parses this prompt, copies the entire `projects/template` folder and names it `artifact_name`, and puts the code from the prompt into the each file. Finally the program builds the jar using maven.
76
+
77
+ ## Requirements
78
+ You can use BukkitGPT on any computer with [Java](https://www.azul.com/downloads/), [Maven](https://maven.apache.org/), [Python 3+](https://www.python.org/).
79
+
80
+ And you need to install this package:
81
+ ```
82
+ pip install openai
83
+ ```
84
+
85
+ ## Quick Start
86
+
87
+ *(Make sure you have the [Python](https://www.python.org) environment installed on your computer)*
88
+
89
+
90
+ ### Python/UI
91
+
92
+ 1. Download `Source Code.zip` from [the release page](https://github.com/CubeGPT/BukkitGPT-v3/releases) and unzip it.
93
+ 2. Edit `config.yaml`, fill in your OpenAI Apikey. If you don't know how, remember that [Google](https://www.google.com/) and [Bing](https://www.bing.com/) are always your best friends.
94
+ 3. Install dependencies by running `pip install -r requirements.txt`.
95
+ 4. Run `ui.py` (bash `python console.py`).
96
+ 5. Enter the artifact name & description & package id as instructed to generate your plugin.
97
+ 6. Copy your plugin from `projects/<artifact_name>/target/<artifact_name>-<version>.jar` to your server `plugins/` folder.
98
+ 7. Restart your server and enjoy your AI-powered-plugin.
99
+
100
+ ## Troubleshooting
101
+
102
+ ### The POM for org.spigotmc:spigot:jar:1.13.2-R0.1-SNAPSHOT is missing
103
+ Solution: [Download BuildTools](https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar), place it in an empty folder, double-click it, choose "1.13.2" in `Settings/Select Version`, click `Compile` in the bottom right corner and let it finish. And then go to your BukkitGPT folder, in `projects/<artifact_name_of_your_plugin>`, double-click `build.bat`. You'll find your plugin in `projects/<artifact_name_of_your_plugin>/target` folder.
104
+
105
+ ## Contributing
106
+ If you like the project, you can give the project a star, or [submit an issue](https://github.com/CubeGPT/BukkitGPT-v3/issues) or [pull request](https://github.com/CubeGPT/BukkitGPT-v3/pulls) to help make it better.
107
+
108
+ ## License
109
+ ```
110
+ Copyright [2024] [CubeGPT Team]
111
+
112
+ Licensed under the Apache License, Version 2.0 (the "License");
113
+ you may not use this file except in compliance with the License.
114
+ You may obtain a copy of the License at
115
+
116
+ http://www.apache.org/licenses/LICENSE-2.0
117
+
118
+ Unless required by applicable law or agreed to in writing, software
119
+ distributed under the License is distributed on an "AS IS" BASIS,
120
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
121
+ See the License for the specific language governing permissions and
122
+ limitations under the License.
123
+ ```
banner.jpeg ADDED
build.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from subprocess import Popen, PIPE, STDOUT
2
+ from log_writer import logger
3
+
4
+
5
+ def build_plugin(artifact_name):
6
+ project_path = f"codes/{artifact_name}"
7
+ build_command = [
8
+ "cd",
9
+ project_path,
10
+ "&&",
11
+ "mvn",
12
+ "-V",
13
+ "-B",
14
+ "clean",
15
+ "package",
16
+ "--file",
17
+ "pom.xml",
18
+ ]
19
+
20
+ process = Popen(build_command, stdout=PIPE, stderr=STDOUT, shell=True)
21
+
22
+ def log_subprocess_output(pipe):
23
+ output = ""
24
+ for line in iter(pipe.readline, b""):
25
+ str_line = str(line)
26
+ output += str_line
27
+ logger(f"building -> {str_line}")
28
+ return output
29
+
30
+ with process.stdout:
31
+ output = log_subprocess_output(process.stdout)
32
+
33
+ process.wait()
34
+
35
+ return output
36
+
37
+
38
+ if __name__ == "__main__":
39
+ result = build_plugin("ExamplePlugin2")
40
+ print(result)
41
+ print(type(result))
codes/Demo/pom.xml ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project xmlns="http://maven.apache.org/POM/4.0.0"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5
+ <modelVersion>4.0.0</modelVersion>
6
+
7
+ <groupId>org.cubegpt</groupId>
8
+ <artifactId>Demo</artifactId>
9
+ <version>1.0-SNAPSHOT</version>
10
+ <packaging>jar</packaging>
11
+
12
+ <dependencies>
13
+ <dependency>
14
+ <groupId>org.bukkit</groupId>
15
+ <artifactId>bukkit</artifactId>
16
+ <version>1.13.2-R0.1-SNAPSHOT</version>
17
+ <scope>provided</scope>
18
+ </dependency>
19
+ </dependencies>
20
+
21
+ <build>
22
+ <sourceDirectory>src/main/java</sourceDirectory>
23
+ <resources>
24
+ <resource>
25
+ <directory>src/main/resources</directory>
26
+ <filtering>true</filtering>
27
+ </resource>
28
+ </resources>
29
+ <plugins>
30
+ <plugin>
31
+ <groupId>org.apache.maven.plugins</groupId>
32
+ <artifactId>maven-compiler-plugin</artifactId>
33
+ <version>3.8.1</version>
34
+ <configuration>
35
+ <source>1.8</source>
36
+ <target>1.8</target>
37
+ </configuration>
38
+ </plugin>
39
+ <plugin>
40
+ <groupId>org.apache.maven.plugins</groupId>
41
+ <artifactId>maven-jar-plugin</artifactId>
42
+ <configuration>
43
+ <archive>
44
+ <manifest>
45
+ <addClasspath>true</addClasspath>
46
+ <classpathPrefix>lib/</classpathPrefix>
47
+ <mainClass>org.cubegpt._54672e99.Main</mainClass>
48
+ </manifest>
49
+ </archive>
50
+ </configuration>
51
+ </plugin>
52
+ </plugins>
53
+ </build>
54
+ </project>
codes/Demo/src/main/java/org/cubegpt/54672e99/Main.java ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package org.cubegpt._54672e99;
2
+
3
+ import org.bukkit.Bukkit;
4
+ import org.bukkit.plugin.java.JavaPlugin;
5
+ import org.bukkit.event.Listener;
6
+ import org.bukkit.event.EventHandler;
7
+ import org.bukkit.event.player.PlayerJoinEvent;
8
+ import org.bukkit.command.CommandExecutor;
9
+ import org.bukkit.command.Command;
10
+ import org.bukkit.command.CommandSender;
11
+ import org.bukkit.entity.Player;
12
+
13
+ public class Main extends JavaPlugin implements Listener {
14
+
15
+ @Override
16
+ public void onEnable() {
17
+ getServer().getPluginManager().registerEvents(this, this);
18
+ Bukkit.getConsoleSender().sendMessage("Plugin enabled!");
19
+ }
20
+
21
+ @EventHandler
22
+ public void onPlayerJoin(PlayerJoinEvent event) {
23
+ event.getPlayer().sendMessage("hello");
24
+ }
25
+
26
+ @Override
27
+ public void onDisable() {
28
+ Bukkit.getConsoleSender().sendMessage("Plugin disabled!");
29
+ }
30
+ }
codes/Demo/src/main/resources/config.yml ADDED
@@ -0,0 +1 @@
 
 
1
+ greeting-message: 'hello'
codes/Demo/src/main/resources/plugin.yml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Demo
2
+ version: 1.0
3
+ main: org.cubegpt._54672e99.Main
4
+ api-version: 1.13
5
+ author: CubeGPT
6
+ dependencies: []
7
+ commands:
8
+ demo:
9
+ description: Sends a greeting message to everyone.
10
+ usage: /<command>
codes/Demo/target/Demo-1.0-SNAPSHOT.jar ADDED
Binary file (3.22 kB). View file
 
codes/Demo/target/classes/config.yml ADDED
@@ -0,0 +1 @@
 
 
1
+ greeting-message: 'hello'
codes/Demo/target/classes/org/cubegpt/54672e99/Main.class ADDED
Binary file (919 Bytes). View file
 
codes/Demo/target/classes/plugin.yml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Demo
2
+ version: 1.0
3
+ main: org.cubegpt._54672e99.Main
4
+ api-version: 1.13
5
+ author: CubeGPT
6
+ dependencies: []
7
+ commands:
8
+ demo:
9
+ description: Sends a greeting message to everyone.
10
+ usage: /<command>
codes/Demo/target/maven-archiver/pom.properties ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ artifactId=Demo
2
+ groupId=org.cubegpt
3
+ version=1.0-SNAPSHOT
codes/Demo/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst ADDED
@@ -0,0 +1 @@
 
 
1
+ org\cubegpt\_54672e99\Main.class
codes/Demo/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst ADDED
@@ -0,0 +1 @@
 
 
1
+ D:\zhousl\BukkitGPT\BukkitGPT-v3\codes\Demo\src\main\java\org\cubegpt\54672e99\Main.java
codes/ExamplePlugin4/pom.xml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project xmlns="http://maven.apache.org/POM/4.0.0"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5
+ <modelVersion>4.0.0</modelVersion>
6
+
7
+ <groupId>org.cubegpt</groupId>
8
+ <artifactId>ExamplePlugin4</artifactId>
9
+ <version>1.0-SNAPSHOT</version>
10
+ <packaging>jar</packaging>
11
+
12
+ <dependencies>
13
+ <dependency>
14
+ <groupId>org.bukkit</groupId>
15
+ <artifactId>bukkit</artifactId>
16
+ <version>1.13.2-R0.1-SNAPSHOT</version>
17
+ <scope>provided</scope>
18
+ </dependency>
19
+ </dependencies>
20
+
21
+ <build>
22
+ <sourceDirectory>src/main/java</sourceDirectory>
23
+ <resources>
24
+ <resource>
25
+ <directory>src/main/resources</directory>
26
+ </resource>
27
+ </resources>
28
+ <plugins>
29
+ <plugin>
30
+ <groupId>org.apache.maven.plugins</groupId>
31
+ <artifactId>maven-compiler-plugin</artifactId>
32
+ <version>3.8.0</version>
33
+ <configuration>
34
+ <source>1.8</source>
35
+ <target>1.8</target>
36
+ </configuration>
37
+ </plugin>
38
+ </plugins>
39
+ </build>
40
+ </project>
codes/ExamplePlugin4/src/main/java/org/cubegpt/188eba63/Main.java ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package org.cubegpt._188eba63;
2
+
3
+ import org.bukkit.Bukkit;
4
+ import org.bukkit.event.EventHandler;
5
+ import org.bukkit.event.Listener;
6
+ import org.bukkit.event.player.PlayerJoinEvent;
7
+ import org.bukkit.plugin.java.JavaPlugin;
8
+
9
+ public class Main extends JavaPlugin implements Listener {
10
+
11
+ @Override
12
+ public void onEnable() {
13
+ Bukkit.getServer().getPluginManager().registerEvents(this, this);
14
+ }
15
+
16
+ @EventHandler
17
+ public void onPlayerJoin(PlayerJoinEvent event) {
18
+ event.getPlayer().sendMessage("hello");
19
+ }
20
+ }
codes/ExamplePlugin4/src/main/resources/config.yml ADDED
@@ -0,0 +1 @@
 
 
1
+ message: "hello"
codes/ExamplePlugin4/src/main/resources/plugin.yml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ name: ExamplePlugin4
2
+ version: 1.0
3
+ main: org.cubegpt._188eba63.Main
4
+ api-version: 1.13
5
+ author: CubeGPT
codes/ExamplePlugin4/target/ExamplePlugin4-1.0-SNAPSHOT.jar ADDED
Binary file (2.96 kB). View file
 
codes/ExamplePlugin4/target/classes/config.yml ADDED
@@ -0,0 +1 @@
 
 
1
+ message: "hello"
codes/ExamplePlugin4/target/classes/org/cubegpt/188eba63/Main.class ADDED
Binary file (841 Bytes). View file
 
codes/ExamplePlugin4/target/classes/plugin.yml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ name: ExamplePlugin4
2
+ version: 1.0
3
+ main: org.cubegpt._188eba63.Main
4
+ api-version: 1.13
5
+ author: CubeGPT
codes/ExamplePlugin4/target/maven-archiver/pom.properties ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ artifactId=ExamplePlugin4
2
+ groupId=org.cubegpt
3
+ version=1.0-SNAPSHOT
codes/ExamplePlugin4/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst ADDED
@@ -0,0 +1 @@
 
 
1
+ org\cubegpt\_188eba63\Main.class
codes/ExamplePlugin4/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst ADDED
@@ -0,0 +1 @@
 
 
1
+ D:\zhousl\BukkitGPT\BukkitGPT-v3\codes\ExamplePlugin4\src\main\java\org\cubegpt\188eba63\Main.java
config.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import yaml
2
+ from log_writer import logger
3
+
4
+
5
+ def load_config():
6
+ """
7
+ Loads the configuration from the 'config.yaml' file and sets the global variables accordingly.
8
+
9
+ If the 'GENERATE_MODEL' key in the configuration is set to 'gpt-4', it forces the use of 'gpt-4-turbo-preview'
10
+ as the value for the 'GENERATE_MODEL' key, since 'gpt-4' no longer supports json modes.
11
+
12
+ Returns:
13
+ None
14
+ """
15
+ with open("config.yaml", "r") as conf:
16
+ config_content = yaml.safe_load(conf)
17
+ for key, value in config_content.items():
18
+ if key == "GENERATE_MODEL" and value == "gpt-4":
19
+ globals()[
20
+ key
21
+ ] = "gpt-4-turbo-preview" # Force using gpt-4-turbo-preview if the user set the GENERATE_MODEL to gpt-4. Because gpt-4 is not longer supports json modes.
22
+ globals()[key] = value
23
+ logger(f"config: {key} -> {value}")
24
+
25
+
26
+ def edit_config(key, value):
27
+ """
28
+ Edits the config file.
29
+
30
+ Args:
31
+ key (str): The key to edit.
32
+ value (str): The value to set.
33
+
34
+ Returns:
35
+ bool: True
36
+ """
37
+
38
+ with open("config.yaml", "r") as conf:
39
+ config_content = conf.readlines()
40
+
41
+ with open("config.yaml", "w") as conf:
42
+ for line in config_content:
43
+ if line.startswith(key):
44
+ if value == True:
45
+ write_value = "True"
46
+ elif value == False:
47
+ write_value = "False"
48
+ else:
49
+ write_value = f'"{value}"'
50
+ if "#" in line:
51
+ conf.write(f"{key}: {write_value} # {line.split('#')[1]}\n")
52
+ else:
53
+ conf.write(f"{key}: {write_value}\n")
54
+ else:
55
+ conf.write(line)
56
+
57
+ return True
58
+
59
+
60
+ load_config()
config.yaml ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ########## EDIT REQUIRED ##########
2
+
3
+ # GPT SETTINGS #
4
+ # Get your api key from openai. Remember google/bing is always your best friend.
5
+ # Model names: gpt-4-turbo-preview, gpt-3.5-turbo, etc.
6
+ # Recommend -> gpt-4-turbo (Better performance, more expensive), gpt-4-o (Good performance, cheaper)
7
+
8
+ API_KEY: "" # Free API Key with GPT-4 access: https://github.com/CubeGPT/.github/discussions/1
9
+ BASE_URL: "https://api.openai.com/v1"
10
+
11
+ GENERATION_MODEL: "gpt-4-turbo-2024-04-09"
12
+ FIXING_MODEL: "gpt-4-turbo-2024-04-09"
13
+
14
+ # DEVELOPER SETTINGS #
15
+ VERSION_NUMBER: "0.1.1"
16
+
17
+ # PROMPT SETTINGS #
18
+ # If you don't know what it is, please don't touch it. Be sure to backup before editing.
19
+
20
+ ## Code Generation ##
21
+ SYS_GEN: |
22
+ You're a minecraft bukkit plugin coder AI. Game Version: 1.13.2 (1.13.2-R0.1-SNAPSHOT)
23
+ Write the code & choose a artifact name for the following files with the infomation which is also provided by the user:
24
+ codes/%ARTIFACT_NAME%/src/main/java/%PKG_ID_LST%Main.java
25
+ codes/%ARTIFACT_NAME%/src/main/resources/plugin.yml
26
+ codes/%ARTIFACT_NAME%/src/main/resources/config.yml
27
+ codes/%ARTIFACT_NAME%/pom.xml
28
+ Response in json format:
29
+ {
30
+ \"codes\": [
31
+ {
32
+ \"file\": \"codes/%ARTIFACT_NAME%/src/main/java/%PKG_ID_LST%Main.java\",
33
+ \"code\": \"package ...;\\nimport org.bukkit.Bukkit;\\npublic class Main extends JavaPlugin implements CommandExecutor {\\n... (The code you need to write)\"
34
+ },
35
+ {
36
+ \"file\": \"codes/%ARTIFACT_NAME%/src/main/resources/plugin.yml\",
37
+ \"code\": \"name: ...\\nversion: ...\\n...\"
38
+ },
39
+ {
40
+ \"file\": \"codes/%ARTIFACT_NAME%/src/main/resources/config.yml\",
41
+ \"code\": \"...\"
42
+ },
43
+ {
44
+ \"file\": \"codes/%ARTIFACT_NAME%/pom.xml\",
45
+ \"code\": \"...\"
46
+ }
47
+ ]
48
+ }
49
+ You should never response anything else. Never use Markdown format. Use \n for line feed, and never forget to use \ before ". Never write uncompeleted codes, such as leave a comment that says "// Your codes here" or "// Uncompeleted".
50
+
51
+ USR_GEN: |
52
+ %DESCRIPTION%
53
+
54
+ SYS_FIX: |
55
+ You're a minecraft bukkit plugin coder AI. Game Version: 1.13.2 (1.13.2-R0.1-SNAPSHOT)
56
+ Fix the error in the code provided by user. The error message is also provided by the user.
57
+ Response in json format:
58
+ {
59
+ \"codes\": [
60
+ {
61
+ \"file\": \"codes/%ARTIFACT_NAME%/src/main/java/%PKG_ID_LST%Main.java\",
62
+ \"code\": \"package ...;\\nimport org.bukkit.Bukkit;\\npublic class Main extends JavaPlugin implements CommandExecutor {\\n... (The code you need to write)\"
63
+ },
64
+ {
65
+ \"file\": \"codes/%ARTIFACT_NAME%/src/main/resources/plugin.yml\",
66
+ \"code\": \"name: ...\\nversion: ...\\n...\"
67
+ },
68
+ {
69
+ \"file\": \"codes/%ARTIFACT_NAME%/src/main/resources/config.yml\",
70
+ \"code\": \"...\"
71
+ },
72
+ {
73
+ \"file\": \"codes/%ARTIFACT_NAME%/pom.xml\",
74
+ \"code\": \"...\"
75
+ }
76
+ ]
77
+ }
78
+ You should never response anything else. Never use Markdown format. Use \n for line feed, and never forget to use \ before ". Never write uncompeleted codes, such as leave a comment that says "// Your codes here" or "// Original code" or "// Uncompeleted".
79
+
80
+ USR_FIX: |
81
+ Main.java:
82
+ %MAIN_JAVA%
83
+ plugin.yml:
84
+ %PLUGIN_YML%
85
+ config.yml:
86
+ %CONFIG_YML%
87
+ pom.xml:
88
+ %POM_XML%
89
+ error message:
90
+ %P_ERROR_MSG%
console.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import uuid
3
+ import shutil
4
+
5
+ from log_writer import logger
6
+ import core
7
+ import config
8
+ import build
9
+
10
+ if __name__ == "__main__":
11
+ main_java = None
12
+ plugin_yml = None
13
+ config_yml = None
14
+ pom_xml = None
15
+
16
+ core.initialize()
17
+
18
+ print("BukkitGPT v3 beta console running")
19
+
20
+ # Get user inputs
21
+ name = input("Enter the plugin name: ")
22
+ description = input("Enter the plugin description: ")
23
+
24
+ artifact_name = name.replace(" ", "")
25
+ package_id = f"org.cubegpt.{uuid.uuid4().hex[:8]}"
26
+
27
+ pkg_id_path = ""
28
+ for id in package_id.split("."):
29
+ pkg_id_path += id + "/"
30
+
31
+ logger(f"user_input -> name: {name}")
32
+ logger(f"user_input -> description: {description}")
33
+ logger(f"random_generate -> package_id: {package_id}")
34
+ logger(f"str_path -> pkg_id_path: {pkg_id_path}")
35
+
36
+ print("Generating plugin...")
37
+
38
+ codes = core.askgpt(
39
+ config.SYS_GEN.replace("%ARTIFACT_NAME%", artifact_name).replace(
40
+ "%PKG_ID_LST%", pkg_id_path
41
+ ),
42
+ config.USR_GEN.replace("%DESCRIPTION", description),
43
+ config.GENERATION_MODEL,
44
+ )
45
+ logger(f"codes: {codes}")
46
+
47
+ core.response_to_action(codes)
48
+
49
+ print("Code generated. Building now...")
50
+
51
+ result = build.build_plugin(artifact_name)
52
+
53
+ if "BUILD SUCCESS" in result:
54
+ print(
55
+ f"Build complete. Find your plugin at 'codes/{artifact_name}/target/{artifact_name}.jar'"
56
+ )
57
+ elif "Compilation failure":
58
+ print("Build failed. Passing the error to ChatGPT and let it to fix it?")
59
+ fix = input("Y/n: ")
60
+ if fix == "n":
61
+ print("Exiting...")
62
+ sys.exit(0)
63
+ else:
64
+ print("Passing the error to ChatGPT...")
65
+
66
+ files = [
67
+ f"codes/{artifact_name}/src/main/java/{pkg_id_path}Main.java",
68
+ f"codes/{artifact_name}/src/main/resources/plugin.yml",
69
+ f"codes/{artifact_name}/src/main/resources/config.yml",
70
+ f"codes/{artifact_name}/pom.xml",
71
+ ]
72
+
73
+ ids = ["main_java", "plugin_yml", "config_yml", "pom_xml"]
74
+
75
+ for file in files:
76
+ with open(file, "r") as f:
77
+ code = f.read()
78
+ id = ids[files.index(file)]
79
+ globals()[id] = code
80
+
81
+ print("Generating...")
82
+ codes = core.askgpt(
83
+ config.SYS_FIX.replace("%ARTIFACT_NAME%", artifact_name),
84
+ config.USR_FIX.replace("%MAIN_JAVA%", main_java)
85
+ .replace("%PLUGIN_YML%", plugin_yml)
86
+ .replace("%CONFIG_YML%", config_yml)
87
+ .replace("%POM_XML%", pom_xml)
88
+ .replace("%P_ERROR_MSG%", result),
89
+ config.FIXING_MODEL,
90
+ )
91
+
92
+ shutil.rmtree(f"codes/{artifact_name}")
93
+ core.response_to_action(codes)
94
+
95
+ print("Code generated. Building now...")
96
+
97
+ result = build.build_plugin(artifact_name)
98
+
99
+ if "BUILD SUCCESS" in result:
100
+ print(
101
+ f"Build complete. Find your plugin at 'codes/{artifact_name}/target/{artifact_name}.jar'"
102
+ )
103
+ else:
104
+ print(
105
+ "Build failed. Please check the logs && send the log to @BaimoQilin on discord."
106
+ )
107
+ print("Exiting...")
108
+ sys.exit(0)
109
+
110
+ else:
111
+ print(
112
+ "Unknown error. Please check the logs && send the log to @BaimoQilin on discord."
113
+ )
114
+ print("Exiting...")
115
+ sys.exit(0)
116
+
117
+
118
+ else:
119
+ print(
120
+ "Error: Please run console.py as the main program instead of importing it from another program."
121
+ )
core.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from openai import OpenAI
2
+ import chardet
3
+ import sys
4
+ import json
5
+ import locale
6
+ import os
7
+
8
+ from log_writer import logger
9
+ import config
10
+
11
+
12
+ def initialize():
13
+ """
14
+ Initializes the software.
15
+
16
+ This function logs the software launch, including the version number and platform.
17
+
18
+ Args:
19
+ None
20
+
21
+ Returns:
22
+ None
23
+ """
24
+ locale.setlocale(locale.LC_ALL, "en_US.UTF-8")
25
+ logger(f"Launch. Software version {config.VERSION_NUMBER}, platform {sys.platform}")
26
+
27
+ if (
28
+ "gpt-3.5" in config.GENERATION_MODEL
29
+ and config.BYPASS_NO_GPT35_FOR_GENERATION_LIMIT is False
30
+ ):
31
+ print(
32
+ "gpt-3.5 writes bugs *all the time* and is not recommended for code generation. Switching to gpt-4."
33
+ )
34
+ config.edit_config(
35
+ "GENERATION_MODEL", config.GENERATION_MODEL.replace("gpt-3.5", "gpt-4")
36
+ )
37
+
38
+
39
+ def askgpt(
40
+ system_prompt: str,
41
+ user_prompt: str,
42
+ model_name: str,
43
+ disable_json_mode: bool = False,
44
+ image_url: str = None,
45
+ ):
46
+ """
47
+ Interacts with ChatGPT using the specified prompts.
48
+
49
+ Args:
50
+ system_prompt (str): The system prompt.
51
+ user_prompt (str): The user prompt.
52
+ model_name (str): The model name to use.
53
+ disable_json_mode (bool): Whether to disable JSON mode.
54
+
55
+ Returns:
56
+ str: The response from ChatGPT.
57
+ """
58
+ if image_url is not None and config.USE_DIFFERENT_APIKEY_FOR_VISION_MODEL:
59
+ logger("Using different API key for vision model.")
60
+ client = OpenAI(api_key=config.VISION_API_KEY, base_url=config.VISION_BASE_URL)
61
+ else:
62
+ client = OpenAI(api_key=config.API_KEY, base_url=config.BASE_URL)
63
+
64
+ logger("Initialized the OpenAI client.")
65
+
66
+ # Define the messages for the conversation
67
+ if image_url is not None:
68
+ messages = [
69
+ {"role": "system", "content": system_prompt},
70
+ {
71
+ "role": "user",
72
+ "content": [
73
+ {"type": "text", "text": user_prompt},
74
+ {"type": "image_url", "image_url": {"url": image_url}},
75
+ ],
76
+ },
77
+ ]
78
+ else:
79
+ messages = [
80
+ {"role": "system", "content": system_prompt},
81
+ {"role": "user", "content": user_prompt},
82
+ ]
83
+
84
+ logger(f"askgpt: system {system_prompt}")
85
+ logger(f"askgpt: user {user_prompt}")
86
+
87
+ # Create a chat completion
88
+ if disable_json_mode:
89
+ response = client.chat.completions.create(model=model_name, messages=messages)
90
+ else:
91
+ response = client.chat.completions.create(
92
+ model=model_name, response_format={"type": "json_object"}, messages=messages
93
+ )
94
+
95
+ logger(f"askgpt: response {response}")
96
+
97
+ # Extract the assistant's reply
98
+ assistant_reply = response.choices[0].message.content
99
+ logger(f"askgpt: extracted reply {assistant_reply}")
100
+ return assistant_reply
101
+
102
+
103
+ def response_to_action(msg):
104
+ """
105
+ Converts a response from ChatGPT to an action.
106
+
107
+ Args:
108
+ msg (str): The response from ChatGPT.
109
+
110
+ Returns:
111
+ str: The action to take.
112
+ """
113
+ text = json.loads(msg)
114
+
115
+ codes = text["codes"]
116
+
117
+ for section in codes:
118
+ file = section["file"]
119
+ code = section["code"]
120
+
121
+ paths = file.split("/")
122
+
123
+ # Join the list elements to form a path
124
+ path = os.path.join(*paths)
125
+
126
+ # Get the directory path and the file name
127
+ dir_path, file_name = os.path.split(path)
128
+
129
+ # Create directories, if they don't exist
130
+ try:
131
+ os.makedirs(dir_path, exist_ok=True)
132
+ except FileNotFoundError:
133
+ pass
134
+
135
+ # Create the file
136
+ with open(path, "w") as f:
137
+ f.write(code) # Write an empty string to the file
138
+
139
+
140
+ def mixed_decode(text: str):
141
+ """
142
+ Decode a mixed text containing both normal text and a byte sequence.
143
+
144
+ Args:
145
+ text (str): The mixed text to be decoded.
146
+
147
+ Returns:
148
+ str: The decoded text, where the byte sequence has been converted to its corresponding characters.
149
+
150
+ """
151
+ # Split the normal text and the byte sequence
152
+ # Assuming the byte sequence is everything after the last colon and space ": "
153
+ try:
154
+ normal_text, byte_text = text.rsplit(": ", 1)
155
+ except (TypeError, ValueError):
156
+ # The text only contains normal text
157
+ return text
158
+
159
+ # Convert the byte sequence to actual bytes
160
+ byte_sequence = byte_text.encode(
161
+ "latin1"
162
+ ) # latin1 encoding maps byte values directly to unicode code points
163
+
164
+ # Detect the encoding of the byte sequence
165
+ detected_encoding = chardet.detect(byte_sequence)
166
+ encoding = detected_encoding["encoding"]
167
+
168
+ # Decode the byte sequence
169
+ decoded_text = byte_sequence.decode(encoding)
170
+
171
+ # Combine the normal text with the decoded byte sequence
172
+ final_text = normal_text + ": " + decoded_text
173
+ return final_text
174
+
175
+
176
+ if __name__ == "__main__":
177
+ print("This script is not meant to be run directly. Please run console.py instead.")
cube_qgui/__init__.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Author: Acer Zhang
2
+ # Edit: CubeGPT Team
3
+ # Original Version Datetime: 2021/9/16
4
+ # Edited Version Datetime: 2024/5/31
5
+ # Copyright belongs to the author.
6
+ # Please indicate the source for reprinting.
7
+
8
+ import cube_qgui.base_tools
9
+ import cube_qgui.factory
10
+ # import qgui.notebook_tools
11
+ # import qgui.banner_tools
12
+
13
+
14
+ from cube_qgui.factory import CreateQGUI
15
+
16
+ from cube_qgui.manager import *
17
+
18
+ from cube_qgui.base_tools import ArgInfo
cube_qgui/__main__.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+
3
+ # 导入CreateQGUI模块
4
+ from qgui import CreateQGUI, MessageBox
5
+ # 【可选】导入自定义导航栏按钮模块、GitHub导航栏模块
6
+ from qgui.banner_tools import BaseBarTool, GitHub, AIStudio
7
+ # 【可选】一次性导入所有的主界面工具模块
8
+ from qgui.notebook_tools import *
9
+ # 【可选】导入占位符
10
+ from qgui.manager import QStyle, HORIZONTAL
11
+
12
+
13
+ def click(args: dict):
14
+ MessageBox.info("要开始啦~")
15
+ # 证明一下自己被点到了
16
+ print("你点到我啦~")
17
+ # 通过ChooseFileTextButton(name="文件选择")中预先设置的name参数,使用get方法即可获取对应的输入框信息
18
+ print("你选择的文件是:", args["文件选择"].get())
19
+ # 当然也可以通过name参数来设置对应的内容,使用set方法即可完成设置
20
+ print("保存位置修改为“快看,我被修改啦”", args["保存位置"].set("快看,我被修改啦"))
21
+ # 即使没有指定name,我们照样可以拿到所有的小工具情况
22
+ for arg, v_fun in args.items():
23
+ print("自定义组件Name:", arg, "状态:", v_fun.get())
24
+
25
+ # 若我们绑定了进度条,那么每当需要设置进度的时候,通过args["进度条"].set(当前进度)来进行设置吧,倒吸进度条也是可以哒
26
+ for i in range(1, 101):
27
+ time.sleep(0.01)
28
+ args["进度条"].set(i)
29
+ # 增加打印间隔
30
+ if i % 20 == 0:
31
+ print("当前进度", i)
32
+ MessageBox.warning(text="给个评价吧亲~")
33
+ # 也可以在终端中打印组件,顺便绑定用户调研函数
34
+ q_gui.print_tool(RadioButton(["满意", "一般", "你好垃圾啊"], title="体验如何?", name="feedback", bind_func=feedback))
35
+ # 甚至打印图片
36
+ from qgui import RESOURCES_PATH
37
+ q_gui.print_image(os.path.join(RESOURCES_PATH, "demo/panda.jpg"))
38
+
39
+
40
+ def feedback(args: dict):
41
+ # 用户调研Callback
42
+ info = args["feedback"].get()
43
+ if info == "满意":
44
+ print("么么哒")
45
+ elif info == "一般":
46
+ print("啊啊啊,告诉GT哪里没做好吧")
47
+ else:
48
+ print("以后漂流瓶见吧,拜拜!")
49
+
50
+
51
+ def bind_dir(args: dict):
52
+ # 获取所选择文件所在的文件夹路径
53
+ path = os.path.dirname(args["文件选择"].get())
54
+ # 可以通过name参数来设置对应的内容,使用set方法即可完成设置
55
+ args["保存位置"].set(path)
56
+ print("保存位置已自动修改为:", path)
57
+
58
+
59
+ def go_to_first_page(args: dict):
60
+ args["QGUI-BaseNoteBook"].set(0)
61
+
62
+
63
+ # 创建主界面
64
+ q_gui = CreateQGUI(title="一个新应用", # 界面标题
65
+ tab_names=["主控制台", "选择按钮", "其他小工具"], # 界面中心部分的分页标题 - 可不填
66
+ style=QStyle.default) # 皮肤
67
+
68
+ # 在界面最上方添加一个按钮,链接到GitHub主页
69
+ q_gui.add_banner_tool(GitHub(url="https://github.com/QPT-Family/QGUI"))
70
+ # 也可以是AI Studio
71
+ q_gui.add_banner_tool(AIStudio(url="https://aistudio.baidu.com/aistudio/personalcenter/thirdview/29724"))
72
+ # 要不试试自定义Banner按钮,在大家点击它时触发刚刚定义的click函数,并向它传递其他组件的情况
73
+ q_gui.add_banner_tool(BaseBarTool(bind_func=click, name="一个新组件"))
74
+
75
+ # 在主界面部分添加一个文件选择工具吧,并在选择文件后自动变为文件所在的路径
76
+ q_gui.add_notebook_tool(ChooseFileTextButton(name="文件选择", bind_func=bind_dir))
77
+ # 再加个文件夹选择工具
78
+ q_gui.add_notebook_tool(ChooseDirTextButton(name="保存位置"))
79
+ # 当然也可以来个输入框
80
+ q_gui.add_notebook_tool(InputBox(name="我是个木有感情的输入框"))
81
+ # 想要加一个 进度条 和 运行按钮 而且俩要水平方向排列该如何做?
82
+ # 试试HorizontalToolsCombine,它可以接受一组工具并将其进行水平排列
83
+ # 这里我们也为RunButton绑定click函数
84
+ run_menu = HorizontalToolsCombine([Progressbar(name="进度条"),
85
+ RunButton(bind_func=click)],
86
+ text="试试HorizontalToolsCombine,它可以接受一组工具并将其进行水平排列")
87
+ q_gui.add_notebook_tool(run_menu)
88
+
89
+ # 第二页 - 复选框和单选框
90
+ # 使用VerticalFrameCombine可以将他们在垂直方向快速组合,它们会从左到右按顺序排列
91
+ combine_left = VerticalFrameCombine([CheckButton(options=[("选择1", 0), ("选择2", 1), ("选择3", 0)]),
92
+ CheckToolButton(options=[("选择1", 0), ("选择2", 1), ("选择3", 0)]),
93
+ CheckObviousToolButton(options=[("选择1", 0), ("选择2", 1), ("选择3", 0)]),
94
+ ToggleButton(options=("开", 1))],
95
+ tab_index=1,
96
+ text="使用VerticalFrameCombine可以将他们在垂直方向快速组合,它们会从左到右按顺序排列")
97
+ q_gui.add_notebook_tool(combine_left)
98
+ # 设置title参数��会为其增加标题
99
+ combine_right = VerticalFrameCombine([RadioButton(["选择1", "选择2", "选择3"], tab_index=1),
100
+ RadioToolButton(["选择1", "选择2", "选择3"], tab_index=1),
101
+ RadioObviousToolButton(["选择1", "选择2", "选择3"], tab_index=1)],
102
+ title="右侧的复选框")
103
+ q_gui.add_notebook_tool(combine_right)
104
+
105
+ # 第三页
106
+ q_gui.add_notebook_tool(Label(text="这只是个简单的Label组件", alignment=RIGHT + TOP, tab_index=2))
107
+ q_gui.add_notebook_tool(Slider(default=4, tab_index=2))
108
+ q_gui.add_notebook_tool(Combobox(options=["选择1", "选择2", "选择3"], tab_index=2))
109
+ q_gui.add_notebook_tool(BaseButton(bind_func=go_to_first_page, text="回到首页", tab_index=2))
110
+
111
+ # 左侧信息栏
112
+ # 简单加个简介
113
+ q_gui.set_navigation_about(author="GT",
114
+ version="0.0.1",
115
+ github_url="https://github.com/QPT-Family/QGUI",
116
+ other_info=["欢迎加入QPT!"])
117
+ # 也可以加一下其他信息
118
+ q_gui.set_navigation_info(title="随便写段话", info="除了QGUI,你还可以试试例如AgentQGUI这样同样简单的GUI框架")
119
+ print("小Tips:占位符可以被Print,不信你看HORIZONTAL的描述被打印了出来->", HORIZONTAL)
120
+
121
+ # 跑起来~切记!一定要放在程序末尾
122
+ q_gui.run()
cube_qgui/banner_tools.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Author: Acer Zhang
2
+ # Datetime: 2021/9/16
3
+ # Copyright belongs to the author.
4
+ # Please indicate the source for reprinting.
5
+ import os
6
+ import webbrowser
7
+
8
+ import tkinter
9
+ from tkinter import ttk
10
+ from cube_qgui.manager import ICON_PATH, ConcurrencyModeFlag
11
+ from cube_qgui.base_tools import ArgInfo, BaseTool
12
+
13
+ RUN_ICON = os.path.join(ICON_PATH, "play_w.png")
14
+ GITHUB_ICON = os.path.join(ICON_PATH, "github.png")
15
+ AI_STUDIO_ICON = os.path.join(ICON_PATH, "up_cloud.png")
16
+
17
+
18
+ class BaseBarTool(BaseTool):
19
+ """
20
+ 基础Banner工具集
21
+ 需注意的是,如需增加异步等操作,请为函数添加_callback
22
+ """
23
+
24
+ def __init__(self,
25
+ bind_func,
26
+ name="Unnamed Tool",
27
+ icon=None,
28
+ style=None,
29
+ async_run: bool = True,
30
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG):
31
+ super().__init__(bind_func=bind_func,
32
+ name=name,
33
+ style=style,
34
+ async_run=async_run,
35
+ concurrency_mode=concurrency_mode)
36
+
37
+ if icon and not os.path.exists(icon):
38
+ raise f"Please check if {os.path.abspath(icon)} exists."
39
+ if not icon:
40
+ icon = RUN_ICON
41
+ self.icon = icon
42
+
43
+ def build(self, *args, **kwargs):
44
+ super().build(*args, **kwargs)
45
+ self.img = tkinter.PhotoImage(file=self.icon)
46
+
47
+ btn = ttk.Button(self.master,
48
+ text=self.name,
49
+ image=self.img,
50
+ compound="left",
51
+ command=self._callback(self.bind_func) if self.async_run else self.bind_func,
52
+ style=self.style + "TButton")
53
+
54
+ btn.pack(side="left", ipadx=5, ipady=5, padx=0, pady=1)
55
+
56
+
57
+ class RunTool(BaseBarTool):
58
+ def __init__(self,
59
+ bind_func,
60
+ name="Start Processing",
61
+ icon=None,
62
+ style="success",
63
+ async_run: bool = True,
64
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG):
65
+ if not icon:
66
+ icon = RUN_ICON
67
+ super(RunTool, self).__init__(bind_func,
68
+ name=name,
69
+ icon=icon,
70
+ style=style,
71
+ async_run=async_run,
72
+ concurrency_mode=concurrency_mode)
73
+
74
+
75
+ class GitHub(BaseBarTool):
76
+ def __init__(self,
77
+ url,
78
+ name="View on GitHub",
79
+ style="primary"):
80
+ icon = GITHUB_ICON
81
+ bind_func = self.github_callback
82
+ super().__init__(bind_func,
83
+ name=name,
84
+ icon=icon,
85
+ style=style)
86
+ self.github_url = url
87
+
88
+ def github_callback(self, args):
89
+ webbrowser.open_new(self.github_url)
90
+
91
+
92
+ class AIStudio(BaseBarTool):
93
+ def __init__(self,
94
+ url,
95
+ name="Use on AI Studio",
96
+ style="primary"):
97
+ icon = AI_STUDIO_ICON
98
+ bind_func = self.ai_studio_callback
99
+ super().__init__(bind_func,
100
+ name=name,
101
+ icon=icon,
102
+ style=style)
103
+ self.ai_studio_url = url
104
+
105
+ def ai_studio_callback(self, args):
106
+ webbrowser.open_new(self.ai_studio_url)
cube_qgui/base_frame.py ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Author: Acer Zhang
2
+ # Datetime: 2021/9/14
3
+ # Copyright belongs to the author.
4
+ # Please indicate the source for reprinting.
5
+
6
+ import sys
7
+ import webbrowser
8
+ import time
9
+ from typing import List
10
+
11
+ import tkinter
12
+ from tkinter import ttk
13
+ from tkinter.scrolledtext import ScrolledText
14
+
15
+ from cube_qgui.manager import BLACK, FONT
16
+ from cube_qgui.banner_tools import BaseBarTool
17
+ from cube_qgui.third_party.collapsing_frame import CollapsingFrame
18
+ from cube_qgui.notebook_tools import BaseNotebookTool
19
+ from cube_qgui.os_tools import StdOutWrapper, DataCache
20
+ from cube_qgui.base_tools import ArgInfo
21
+
22
+ TITLE_BG_COLOR = BLACK
23
+
24
+
25
+ # ToDo 主题部分可考虑通过增加warmup来解决
26
+
27
+ class _Backbone:
28
+ """
29
+ 整个界面的基础,存放共有的变量
30
+ """
31
+
32
+ def __init__(self, f_style="primary"):
33
+ """
34
+ 请务必检查self.frame是否做了pack等定位操作,无操作将不会被显示
35
+ :param f_style:
36
+ """
37
+ # 统一用place
38
+ self.style = f_style
39
+
40
+ # 全局变量
41
+ self.global_info = ArgInfo()
42
+
43
+ def build(self, master, global_info):
44
+ self.frame = ttk.Frame(master, style=self.style + ".TFrame")
45
+ self.global_info = global_info
46
+
47
+
48
+ class BaseNavigation(_Backbone):
49
+ """
50
+ 左侧导航栏基本框架
51
+ """
52
+
53
+ def __init__(self, style="primary"):
54
+ super(BaseNavigation, self).__init__(f_style=style)
55
+ self.tabs = dict()
56
+
57
+ def add_about(self,
58
+ author: str = "未知作者",
59
+ version: str = "0.0.1",
60
+ github_url: str = None,
61
+ bilibili_url: str = None,
62
+ blog_url: str = None,
63
+ other_info: List[str] = None):
64
+ bus_cf = CollapsingFrame(self.frame)
65
+ bus_cf.pack(fill='x', pady=0)
66
+
67
+ bus_frm = ttk.Frame(bus_cf, padding=5)
68
+ bus_frm.columnconfigure(1, weight=1)
69
+ bus_cf.add(bus_frm, title="Info", style='secondary.TButton')
70
+
71
+ ttk.Label(bus_frm, text=f"Author:\t{author}", style="TLabel", justify="left", wraplength=160).pack(anchor="nw")
72
+ ttk.Label(bus_frm, text=f"Version:\t{version}", style="TLabel", justify="left", wraplength=160).pack(anchor="nw")
73
+
74
+ if other_info:
75
+ for line in other_info:
76
+ ttk.Label(bus_frm, text=line, style="TLabel").pack(anchor="nw")
77
+
78
+ if github_url:
79
+ def github_callback(event):
80
+ webbrowser.open_new(github_url)
81
+
82
+ github_label = ttk.Label(bus_frm, text=f"> View on GitHub", style="info.TLabel", justify="left")
83
+ github_label.pack(anchor="nw")
84
+ github_label.bind("<Button-1>", github_callback)
85
+
86
+ if bilibili_url:
87
+ def bilibili_callback(event):
88
+ webbrowser.open_new(bilibili_url)
89
+
90
+ bilibili_label = ttk.Label(bus_frm, text=f"> View on bilibili", style="info.TLabel", justify="left")
91
+ bilibili_label.pack(anchor="nw")
92
+ bilibili_label.bind("<Button-1>", bilibili_callback)
93
+
94
+ if blog_url:
95
+ def blog_callback(event):
96
+ webbrowser.open_new(blog_url)
97
+
98
+ blog_label = ttk.Label(bus_frm, text=f"> View on blog", style="info.TLabel", justify="left")
99
+ blog_label.pack(anchor="nw")
100
+ blog_label.bind("<Button-1>", blog_callback)
101
+
102
+ def add_info(self,
103
+ title: str,
104
+ info: str):
105
+ bus_cf = CollapsingFrame(self.frame)
106
+ bus_cf.pack(fill='x', pady=0)
107
+
108
+ bus_frm = ttk.Frame(bus_cf, padding=5)
109
+ bus_frm.columnconfigure(1, weight=1)
110
+ bus_cf.add(bus_frm, title=title, style='secondary.TButton', justify="left")
111
+
112
+ ttk.Label(bus_frm, text=info, style="TLabel", wraplength=160).pack(anchor="nw")
113
+
114
+ # def add_homepage(self, tool):
115
+ # btn = ttk.Button(self.frame,
116
+ # text=tool.name,
117
+ # image=tool.name,
118
+ # compound='left',
119
+ # command=tool.bind_func)
120
+ # btn.pack(side='left', ipadx=5, ipady=5, padx=0, pady=1)
121
+ def build(self, master, global_info):
122
+ super(BaseNavigation, self).build(master, global_info)
123
+ self.frame.place(x=0, y=50, width=180, height=470)
124
+
125
+
126
+ class BaseNoteBook(_Backbone):
127
+ """
128
+ 中间Notebook部分框架
129
+ """
130
+
131
+ def __init__(self,
132
+ style="primary",
133
+ tab_names: List[str] = None,
134
+ stdout=None):
135
+ super(BaseNoteBook, self).__init__(f_style=style)
136
+ self.tab_names = tab_names
137
+ self.nb_frames = list()
138
+
139
+ # 初始化总输出行数
140
+ self.line_len = 2
141
+ if not stdout:
142
+ stdout = sys.stdout
143
+ self.stdout = stdout
144
+
145
+ sys.stdout = StdOutWrapper(self.stdout, callback=self._write_log_callback)
146
+ sys.stderr = StdOutWrapper(self.stdout, callback=self._write_log_callback)
147
+
148
+ self.image_cache = DataCache()
149
+
150
+ def add_tool(self, tool: BaseNotebookTool, to_notebook=True):
151
+
152
+ if tool.tab_index >= len(self.nb_frames):
153
+ raise ValueError(f"设置的index大小越界,当前页面数量为{len(self.nb_frames)},分别为:{self.nb_frames},而"
154
+ f"您设置的index为{tool.tab_index},超过了当前页面数量。")
155
+ if to_notebook:
156
+ frame = self.nb_frames[tool.tab_index]
157
+ tool_frame = tool.build(master=frame, global_info=self.global_info)
158
+ else:
159
+ tool_frame = tool.build(global_info=self.global_info)
160
+ tool_info = tool.get_arg_info()
161
+ self.global_info += tool_info
162
+ return tool_frame
163
+
164
+ def build(self, master, global_info):
165
+ super(BaseNoteBook, self).build(master, global_info)
166
+ self.frame.place(x=182, y=55, width=750, height=460)
167
+ self.nb = ttk.Notebook(self.frame)
168
+ self.nb.pack(side="top", fill="both")
169
+
170
+ if self.tab_names:
171
+ for tab_name in self.tab_names:
172
+ sub_frame = ttk.Frame(self.nb)
173
+ sub_frame.pack(anchor="nw", expand="yes")
174
+ self.nb_frames.append(sub_frame)
175
+ self.nb.add(sub_frame, text=tab_name)
176
+ else:
177
+ sub_frame = ttk.Frame(self.nb)
178
+ sub_frame.pack(anchor="nw", expand="yes")
179
+ self.nb_frames.append(sub_frame)
180
+ self.nb.add(sub_frame, text="Generate")
181
+ self.global_info += ArgInfo(name="QGUI-BaseNoteBook",
182
+ set_func=self._select_notebook_callback,
183
+ get_func=lambda: print("BaseNoteBook不支持get"))
184
+
185
+ # 增加OutPut
186
+ self.console_frame = ttk.Frame(self.frame,
187
+ style=self.style + ".TFrame")
188
+ self.console_frame.pack(side="top", fill='both', expand="yes")
189
+
190
+ # 标题
191
+ self.title = ttk.Label(self.console_frame,
192
+ font=(FONT, 15),
193
+ style=self.style + ".Inverse.TLabel",
194
+ text="Console Log",
195
+ justify="left")
196
+ self.title.pack(side="top", fill="x", padx=10, pady=5)
197
+
198
+ # 文本
199
+ self.text_area = ScrolledText(self.console_frame,
200
+ highlightcolor=master.style.colors.primary,
201
+ highlightbackground=master.style.colors.border,
202
+ highlightthickness=1)
203
+
204
+ self.text_area.pack(fill="both", expand="yes")
205
+
206
+ self.text_area.insert("end", "Console Connected\n")
207
+ self.text_area.configure(state="disable")
208
+
209
+ def print_tool(self, tool: BaseNotebookTool):
210
+ self.text_area.configure(state="normal")
211
+ self.text_area.window_create("end", window=self.add_tool(tool, to_notebook=False))
212
+ self.text_area.configure(state="disable")
213
+ print("")
214
+
215
+ def print_image(self, image):
216
+ from PIL import Image, ImageTk
217
+ if isinstance(image, str):
218
+ image = Image.open(image)
219
+ w, h = image.size
220
+ scale = 128 / max(w, h)
221
+ w *= scale
222
+ h *= scale
223
+ image = image.resize((int(w), int(h)))
224
+ image = ImageTk.PhotoImage(image)
225
+ self.image_cache += image
226
+ self.text_area.configure(state="normal")
227
+ self.text_area.image_create("end", image=image)
228
+ self.text_area.configure(state="disable")
229
+ print("")
230
+
231
+ def _select_notebook_callback(self, index):
232
+ self.nb.select(index)
233
+
234
+ def _write_log_callback(self, text):
235
+ self.text_area.configure(state="normal")
236
+
237
+ # 对print形式的进度条进行适配
238
+ if "\r" in text:
239
+ self.text_area.delete(str(self.line_len) + ".0", str(self.line_len) + ".end")
240
+ self.line_len -= 1
241
+ text = text[text.index("\r") + 1:] + " "
242
+
243
+ if len(text) > 0 and text != "\n":
244
+ text = time.strftime("%H:%M:%S", time.localtime()) + "\t" + text
245
+
246
+ self.text_area.insert("end", text)
247
+ self.line_len += 1
248
+ self.text_area.configure(state="disable")
249
+ self.text_area.see("end")
250
+
251
+
252
+ class BaseBanner(_Backbone):
253
+ def __init__(self,
254
+ title: str = "QGUI Tesing Program",
255
+ style="primary"):
256
+ super(BaseBanner, self).__init__(f_style=style)
257
+ self.img_info = dict()
258
+ self.title = title
259
+
260
+ def add_tool(self, tool: BaseBarTool):
261
+ """
262
+ 添加小工具组件
263
+ :param
264
+ """
265
+ tool.build(master=self.frame, global_info=self.global_info)
266
+ tool_info = tool.get_arg_info()
267
+ self.global_info += tool_info
268
+
269
+ def build(self, master, global_info):
270
+ super(BaseBanner, self).build(master, global_info)
271
+ self.frame.place(x=0, y=0, width=940, height=50)
272
+ # 占位标题
273
+ black = tkinter.Frame(self.frame,
274
+ height=10,
275
+ bg=TITLE_BG_COLOR)
276
+ black.pack(side="right", anchor="se")
277
+ # 主标题
278
+ title = ttk.Label(self.frame,
279
+ font=(FONT, 22),
280
+ text=self.title,
281
+ style=self.style + ".Inverse.TLabel")
282
+ title.pack(side="right", anchor="se", padx=5, pady=3)
283
+
284
+
285
+ if __name__ == '__main__':
286
+ pass
cube_qgui/base_tools.py ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Author: Acer Zhang
2
+ # Datetime:2021/9/21
3
+ # Copyright belongs to the author.
4
+ # Please indicate the source for reprinting.
5
+ import threading
6
+ import traceback
7
+ import sys
8
+ from typing import Dict
9
+
10
+ import tkinter
11
+
12
+ from cube_qgui.manager import *
13
+
14
+ from log_writer import logger
15
+
16
+
17
+ def check_callable(bind_func):
18
+ if bind_func and not hasattr(bind_func, "__call__"):
19
+ if hasattr(bind_func, "__name__"):
20
+ name = bind_func.__name__
21
+ else:
22
+ name = bind_func
23
+ raise Exception(f"{name}的bind_func不能被调用,其至少需要具备__call__方法,建议在此传入函数/方法或自行构建具备__call__方法的对象。\n"
24
+ f"Example:\n"
25
+ f" def xxx():\n"
26
+ f" Do sth\n"
27
+ f" MakeThisTool(bind_func=xxx)\n"
28
+ f"Error example:\n"
29
+ f" def xxx():\n"
30
+ f" Do sth\n"
31
+ f" MakeThisTool(bind_func=xxx())")
32
+
33
+
34
+ def make_anchor(anchor):
35
+ if anchor:
36
+ r_anchor = str()
37
+ if TOP in anchor:
38
+ r_anchor = "n"
39
+ if BOTTOM in anchor:
40
+ r_anchor = "s"
41
+ if LEFT in anchor:
42
+ r_anchor += "w"
43
+ if RIGHT in anchor:
44
+ r_anchor += "e"
45
+ return r_anchor
46
+ else:
47
+ return None
48
+
49
+
50
+ def make_side(side):
51
+ if side:
52
+ if side == TOP:
53
+ side = "top"
54
+ elif side == BOTTOM:
55
+ side = "bottom"
56
+ elif side == LEFT:
57
+ side = "left"
58
+ else:
59
+ side = "right"
60
+ return side
61
+ else:
62
+ return None
63
+
64
+
65
+ class ArgInfo:
66
+ def __init__(self, name=None, set_func=None, get_func=None):
67
+ if not name and (set_func or get_func):
68
+ raise Exception(f"请设置{self.__class__.__name__}的name")
69
+ if name:
70
+ self.all_info = {name: self}
71
+ else:
72
+ self.all_info = dict()
73
+
74
+ check_callable(set_func)
75
+ check_callable(get_func)
76
+ self.set_func = set_func
77
+ self.get_func = get_func
78
+
79
+ def set(self, *args, **kwargs):
80
+ return self.set_func(*args, **kwargs)
81
+
82
+ def get(self, *args, **kwargs):
83
+ return self.get_func(*args, **kwargs)
84
+
85
+ def get_info(self):
86
+ return self.all_info
87
+
88
+ def __add__(self, other):
89
+ other_info = other.all_info
90
+ if other_info:
91
+ for info_name in other_info:
92
+ if info_name in self.all_info:
93
+ self.all_info[f"{info_name}-QGUI-Conflict-Field-{len(self.all_info)}"] = other_info[info_name]
94
+ else:
95
+ self.all_info[info_name] = other_info[info_name]
96
+ return self
97
+
98
+ def __getitem__(self, item):
99
+ return self.all_info[item]
100
+
101
+
102
+ def select_var_dtype(dtype):
103
+ if issubclass(dtype, int):
104
+ return tkinter.IntVar
105
+ elif issubclass(dtype, float):
106
+ return tkinter.DoubleVar
107
+ elif issubclass(dtype, str):
108
+ return tkinter.StringVar
109
+ elif issubclass(dtype, bool):
110
+ return tkinter.BooleanVar
111
+
112
+
113
+ class BaseTool:
114
+ """
115
+ 基础工具集,提供基础异步Callback
116
+ 1. 写Build,记得继承才会有self.master,继承时候传**kwargs
117
+ 2. 若需返回信息,请重写get_info方法->ArgInfo
118
+ 3. 如绑定func,需要封装Callback
119
+ """
120
+
121
+ def __init__(self,
122
+ bind_func=None,
123
+ name: str = None,
124
+ style: str = "primary",
125
+ async_run: bool = False,
126
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG):
127
+ check_callable(bind_func)
128
+ self.bind_func = bind_func
129
+ self.name = name
130
+ self.style = style + "." if style else ""
131
+ self.async_run = async_run
132
+ # 控制并发模式
133
+ self.concurrency_mode = concurrency_mode
134
+
135
+ # 占位符
136
+ self.global_info = None
137
+ self.master = None
138
+
139
+ # 重复点击的Flag
140
+ self.async_run_event = threading.Event()
141
+ self.thread_pool = list()
142
+
143
+ def _callback(self, func, start_func=None, end_func=None):
144
+ """
145
+ 支持同步和异步的Callback
146
+ :param func: 函数对象
147
+ :param start_func: 开始前的函数对象
148
+ :param end_func: 结束后的函数对象
149
+ """
150
+ if func:
151
+ if not self.async_run:
152
+ def render():
153
+ if start_func:
154
+ start_func()
155
+ func(self.global_info.get_info())
156
+ if end_func:
157
+ end_func()
158
+ else:
159
+ def render():
160
+ # 若不允许并发则在启动时加Flag
161
+ if self.async_run_event.is_set():
162
+ if self.concurrency_mode == ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG:
163
+ return lambda: print("��前设置为禁止并发,请勿重复点击,因为点了也没用")
164
+ else:
165
+ self.async_run_event.set()
166
+
167
+ if start_func:
168
+ start_func()
169
+
170
+ def new_func(obj):
171
+ try:
172
+ func(obj)
173
+ except Exception as e:
174
+ print("-----ERROR MSG START-----")
175
+ print(traceback.print_exc())
176
+ print("-----ERROR MSG END-----")
177
+
178
+ # Record the error message to the log
179
+ logger(f"Error: {e}")
180
+ if end_func:
181
+ end_func()
182
+ # 清除Flag,此时按钮可以再次点击
183
+ self.async_run_event.clear()
184
+
185
+ t = threading.Thread(target=new_func, args=(self.global_info.get_info(),))
186
+ t.setDaemon(True)
187
+ t.start()
188
+
189
+ self.thread_pool.append(t)
190
+ return render
191
+ else:
192
+ def none():
193
+ pass
194
+
195
+ return none
196
+
197
+ def build(self, *args, **kwargs) -> tkinter.Frame:
198
+ self.global_info = kwargs.get("global_info")
199
+ self.master = kwargs.get("master")
200
+
201
+ def get_arg_info(self) -> ArgInfo:
202
+ return ArgInfo()
203
+
204
+
205
+ if __name__ == '__main__':
206
+ n = ArgInfo(set_func=lambda: print("a"))
207
+ a = ArgInfo("A", None, lambda: print("a"))
208
+ b = ArgInfo("B", None, lambda: print("b"))
209
+ c = ArgInfo("A", None, lambda: print("a"))
210
+ n += a + b + c
211
+ a.get()
212
+ pass
cube_qgui/factory.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Author: Acer Zhang
2
+ # Datetime: 2021/8/31
3
+ # Copyright belongs to the author.
4
+ # Please indicate the source for reprinting.
5
+ from typing import List
6
+
7
+ import tkinter
8
+ import tkinter.font
9
+ from ttkbootstrap import Style
10
+
11
+ from cube_qgui.manager import QStyle, FONT
12
+ from cube_qgui.base_frame import BaseNoteBook, BaseBanner, BaseNavigation
13
+ from cube_qgui.banner_tools import BaseBarTool
14
+ from cube_qgui.notebook_tools import BaseNotebookTool
15
+ from cube_qgui.base_tools import check_callable
16
+
17
+
18
+ class CreateQGUI:
19
+ """
20
+ 创建最基础的QGUI程序
21
+
22
+ :param title: 主程序标题
23
+ :param style: 皮肤,需通过QStyle来确定
24
+ :param stout: 标准输出流
25
+ :param tab_names: List[str] 功能区Tab页面,默认为“主程序控制台”
26
+ :param banner: QGUI的Banner对象
27
+ :param navigation: QGUI的navigation对象
28
+ :param notebook: QGUI的notebook对象
29
+ :param bind_func: 全局事件绑定
30
+ """
31
+
32
+ def __init__(self,
33
+ title="Unnamed",
34
+ style: dict = None,
35
+ stout=None,
36
+ tab_names: List[str] = None,
37
+ banner: BaseBanner = None,
38
+ navigation: BaseNavigation = None,
39
+ notebook: BaseNoteBook = None,
40
+ bind_func=None):
41
+ super().__init__()
42
+ self.title = title
43
+ self.style = style
44
+
45
+ self.root = tkinter.Tk()
46
+ if bind_func:
47
+ check_callable(bind_func=bind_func)
48
+ self.root.bind_all("<1>", bind_func)
49
+ if self.style:
50
+ self.root.style = Style(**self.style)
51
+ else:
52
+ self.root.style = Style(**QStyle.default)
53
+ self.root.style.configure('bg.TFrame', background=self.root.style.colors.inputbg)
54
+ self.root.style.configure('bg.TLabel', background=self.root.style.colors.inputbg)
55
+ default_font = tkinter.font.nametofont("TkDefaultFont")
56
+ default_font.configure(family=FONT, size=10)
57
+ self.root.option_add("*Font", "TkDefaultFont")
58
+ self.root.geometry("940x520")
59
+ self.root.wm_resizable(False, False)
60
+ self.root.title(self.title)
61
+
62
+ # 初始化组件
63
+ self.banner = banner if banner else BaseBanner(title=self.title)
64
+ self.navigation = navigation if navigation else BaseNavigation()
65
+ self.notebook = notebook if notebook else BaseNoteBook(tab_names=tab_names, stdout=stout)
66
+
67
+ self.banner.build(self.root, self.get_global_info)
68
+ self.navigation.build(self.root, self.get_global_info)
69
+ self.notebook.build(self.root, self.get_global_info)
70
+
71
+ @property
72
+ def get_global_info(self):
73
+ # ToDo 做个 global_info管理器,目前信息只从Notebook中流出
74
+ return self.notebook.global_info
75
+
76
+ def add_banner_tool(self, tool: BaseBarTool):
77
+ """
78
+ 在程序最上方添加小组件
79
+ :param tool: 继承于BaseBarTool的组件对象
80
+
81
+ Example
82
+ from qgui.banner_tools import GitHub
83
+ q_gui = CreateQGUI()
84
+ q_gui.add_banner_tool(GitHub())
85
+ """
86
+ self.banner.add_tool(tool)
87
+
88
+ abt = add_banner_tool
89
+
90
+ def add_notebook_tool(self, tool: BaseNotebookTool):
91
+ """
92
+ 在程序中央功能区添加小组件
93
+ :param tool: 继承于BaseNotebookTool的组件对象
94
+
95
+ Example
96
+ from qgui.notebook_tools import RunButton
97
+ q_gui.add_notebook_tool(RunButton())
98
+ """
99
+ self.notebook.add_tool(tool)
100
+
101
+ ant = add_notebook_tool
102
+
103
+ def set_navigation_about(self,
104
+ author: str = "Unknow Author",
105
+ version: str = "N/A",
106
+ github_url: str = None,
107
+ bilibili_url: str = None,
108
+ blog_url: str = None,
109
+ other_info: List[str] = None):
110
+ """
111
+ 设置左侧导航栏的程序基本信息
112
+ :param author: 作者
113
+ :param version: 版本号
114
+ :param github_url: GitHub链接
115
+ :param bilibili_url: bilibili链接
116
+ :param blog_url: blog链接
117
+ """
118
+ self.navigation.add_about(author=author,
119
+ version=version,
120
+ github_url=github_url,
121
+ bilibili_url=bilibili_url,
122
+ blog_url=blog_url,
123
+ other_info=other_info)
124
+
125
+ sna = set_navigation_about
126
+
127
+ def set_navigation_info(self,
128
+ title: str,
129
+ info: str):
130
+ """
131
+ 设置左侧导航栏其他信息
132
+ :param title: 标题
133
+ :param info: 信息
134
+ """
135
+ self.navigation.add_info(title=title, info=info)
136
+
137
+ sni = set_navigation_info
138
+
139
+ def print_tool(self, tool: BaseNotebookTool):
140
+ """
141
+ 在终端中打印组件
142
+ :param tool: 继承于BaseNotebookTool的���件对象
143
+ """
144
+ self.notebook.print_tool(tool)
145
+
146
+ def print_image(self, image):
147
+ """
148
+ 在终端中打印图像
149
+ :param image: 图像所在路径 or pillow图片对象
150
+ """
151
+ self.notebook.print_image(image)
152
+
153
+ def run(self):
154
+ """
155
+ 展示GUI界面
156
+ """
157
+ self.root.mainloop()
158
+
159
+
160
+ if __name__ == '__main__':
161
+ from qgui.banner_tools import BaseBarTool
162
+ from qgui.notebook_tools import BaseChooseFileTextButton
163
+
164
+ _tmp = CreateQGUI()
165
+ _tmp.add_banner_tool(BaseBarTool(lambda: print(0)))
166
+ _tmp.add_notebook_tool(BaseChooseFileTextButton(lambda: print(1)))
167
+ _tmp.set_navigation_about()
168
+ _tmp.run()
cube_qgui/manager.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Author: Acer Zhang
2
+ # Datetime: 2021/9/14
3
+ # Copyright belongs to the author.
4
+ # Please indicate the source for reprinting.
5
+
6
+ import os
7
+ import platform
8
+
9
+ from tkinter import messagebox
10
+ from ttkbootstrap import Style
11
+
12
+ import cube_qgui as cqgui
13
+
14
+ # 资源部分
15
+ QGUI_BASE_PATH = os.path.dirname(cqgui.__file__)
16
+ RESOURCES_PATH = os.path.join(QGUI_BASE_PATH, "resources")
17
+ ICON_PATH = os.path.join(RESOURCES_PATH, "icon")
18
+ THEME_PATH = os.path.join(QGUI_BASE_PATH, "theme/ttkbootstrap_themes.json")
19
+
20
+ HORIZONTAL = "Horizontal水平方向"
21
+ VERTICAL = "Vertical垂直方向"
22
+ LEFT = "左侧"
23
+ RIGHT = "右侧"
24
+ TOP = "顶端"
25
+ BOTTOM = "底部"
26
+
27
+
28
+ # Tools部分
29
+ class ConcurrencyModeFlag:
30
+ # QUEUE_ = "触发后相关事件会以队列的形式执行"
31
+ SAFE_CONCURRENCY_MODE_FLAG = "不允许并发,禁止触发下一个事件"
32
+ # FORCE_CONCURRENCY_MODE_FLAG = "不允许并发,下一个事件被触发时结束上一个事件"
33
+
34
+
35
+ class QStyle:
36
+ default = {"theme": "qgui", "themes_file": THEME_PATH}
37
+
38
+ lumen = {"theme": "lumen"}
39
+
40
+ paddle = {"theme": "paddlelight", "themes_file": THEME_PATH}
41
+
42
+ paddle_dark = {"theme": "paddledark", "themes_file": THEME_PATH}
43
+
44
+ pytorch = {"theme": "pytorch", "themes_file": THEME_PATH}
45
+
46
+ tensorflow = {"theme": "tensorflow", "themes_file": THEME_PATH}
47
+
48
+
49
+ class MessageBox:
50
+ @staticmethod
51
+ def info(text: str, title: str = "Info - QGUI"):
52
+ messagebox.showinfo(title, text)
53
+
54
+ @staticmethod
55
+ def warning(text: str, title: str = "Warning - QGUI"):
56
+ messagebox.showwarning(title, text)
57
+
58
+ @staticmethod
59
+ def error(text: str, title: str = "Error - QGUI"):
60
+ messagebox.showerror(title, text)
61
+
62
+
63
+ def show_file_or_path(path, return_func=True):
64
+ def render(*args, **kwargs):
65
+ if platform.system().lower() == "darwin":
66
+ import subprocess
67
+ subprocess.call(["open", path])
68
+ else:
69
+ os.startfile(path)
70
+
71
+ if return_func:
72
+ return render
73
+ else:
74
+ return render()
75
+
76
+
77
+ BLACK = "#24262d"
78
+ GRAY = "#e3e3e3"
79
+ GREEN = "#76b67e"
80
+ FONT = "黑体"
cube_qgui/notebook_tools.py ADDED
@@ -0,0 +1,952 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Author: Acer Zhang
2
+ # Datetime: 2021/9/16
3
+ # Copyright belongs to the author.
4
+ # Please indicate the source for reprinting.
5
+
6
+ from typing import List, Dict, Tuple
7
+ from collections import OrderedDict
8
+
9
+ import tkinter
10
+ from tkinter import ttk
11
+ from tkinter import filedialog
12
+
13
+ from cube_qgui.manager import *
14
+ from cube_qgui.base_tools import ConcurrencyModeFlag, check_callable, ArgInfo, select_var_dtype, BaseTool, make_anchor, \
15
+ make_side
16
+
17
+ RUN_ICON = os.path.join(ICON_PATH, "play_w.png")
18
+
19
+ LEFT_PAD_LEN = 10
20
+ LABEL_WIDTH = 12
21
+ INPUT_BOX_LEN = 70
22
+ DEFAULT_PAD = 5
23
+
24
+
25
+ class BaseNotebookTool(BaseTool):
26
+ """
27
+ 基础Notebook工具集,提供基础异步Callback
28
+ 1. 写Build,记得继承才会有self.master,继承时候传**kwargs
29
+ 2. 若需返回信息,请重写get_info方法->ArgInfo
30
+ 3. 如绑定func,需要封装Callback
31
+ """
32
+
33
+ def __init__(self,
34
+ bind_func=None,
35
+ name: str = None,
36
+ style: str = "primary",
37
+ tab_index: int = 0,
38
+ async_run: bool = False,
39
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG,
40
+ frame: tkinter.Frame = None):
41
+ super().__init__(bind_func=bind_func,
42
+ name=name,
43
+ style=style,
44
+ async_run=async_run,
45
+ concurrency_mode=concurrency_mode)
46
+ self.tab_index = tab_index
47
+ self.frame = frame
48
+
49
+
50
+ class BaseChooseFileTextButton(BaseNotebookTool):
51
+ def __init__(self,
52
+ bind_func=None,
53
+ name: str = None,
54
+ label_info: str = "Target File Path",
55
+ entry_info: str = "Please select file path",
56
+ button_info: str = "Select File",
57
+ style: str = "primary",
58
+ tab_index: int = 0,
59
+ async_run: bool = False,
60
+ mode="file",
61
+ frame: tkinter.Frame = None):
62
+ super().__init__(bind_func, name=name, style=style, tab_index=tab_index, async_run=async_run, frame=frame)
63
+
64
+ self.label_info = label_info
65
+ self.button_info = button_info
66
+ self.name = name
67
+ self.mode = mode
68
+
69
+ self.entry_var = tkinter.StringVar(value=entry_info)
70
+
71
+ def build(self, **kwargs) -> tkinter.Frame:
72
+ super().build(**kwargs)
73
+ if self.frame:
74
+ frame = self.frame
75
+ else:
76
+ frame = ttk.Frame(self.master, style="TFrame")
77
+ frame.pack(side="top", fill="x", padx=5, pady=2)
78
+ label = ttk.Label(frame,
79
+ text=self.label_info,
80
+ style="TLabel",
81
+ width=LABEL_WIDTH)
82
+ label.pack(side="left")
83
+ entry = ttk.Entry(frame,
84
+ style=self.style + "info.TEntry",
85
+ textvariable=self.entry_var)
86
+ entry.pack(side="left", fill="x", expand="yes", padx=5, pady=2)
87
+
88
+ if self.mode == "file":
89
+ if not hasattr(self, "filetypes"):
90
+ self.filetypes = [('All Files', '*')]
91
+
92
+ def render():
93
+ file_path = filedialog.askopenfilename(title="Select File",
94
+ filetypes=self.filetypes)
95
+ if file_path:
96
+ self.entry_var.set(file_path)
97
+
98
+ else:
99
+ def render():
100
+ file_path = filedialog.askdirectory(title="Select Directory")
101
+ if file_path:
102
+ self.entry_var.set(file_path)
103
+
104
+ command = self._callback(self.bind_func, start_func=render) if self.bind_func else render
105
+ button = ttk.Button(frame,
106
+ text=self.button_info,
107
+ style=self.style + "TButton",
108
+ command=command,
109
+ width=12)
110
+ button.pack(side="right")
111
+ return frame
112
+
113
+ def get_arg_info(self) -> ArgInfo:
114
+ field = self.name if self.name else self.__class__.__name__
115
+ arg_info = ArgInfo(name=field, set_func=self.entry_var.set, get_func=self.entry_var.get)
116
+
117
+ return arg_info
118
+
119
+
120
+ class ChooseFileTextButton(BaseChooseFileTextButton):
121
+ def __init__(self,
122
+ bind_func=None,
123
+ name: str = None,
124
+ label_info: str = "Target File Path",
125
+ entry_info: str = "Please select file path",
126
+ button_info: str = "Select File",
127
+ filetypes: bool = None,
128
+ style: str = "primary",
129
+ tab_index: int = 0,
130
+ async_run: bool = False,
131
+ frame: tkinter.Frame = None):
132
+ self.filetypes = [('All Files', '*')] if filetypes is None else filetypes
133
+
134
+ super().__init__(bind_func=bind_func,
135
+ name=name,
136
+ label_info=label_info,
137
+ entry_info=entry_info,
138
+ button_info=button_info,
139
+ style=style,
140
+ tab_index=tab_index,
141
+ async_run=async_run,
142
+ frame=frame)
143
+
144
+
145
+ class ChooseDirTextButton(BaseChooseFileTextButton):
146
+ def __init__(self,
147
+ bind_func=None,
148
+ name=None,
149
+ label_info: str = "Target Directory Path",
150
+ entry_info: str = "Please select directory path",
151
+ button_info: str = "Select Directory",
152
+ style: str = "primary",
153
+ tab_index: int = 0,
154
+ async_run: bool = False,
155
+ frame: tkinter.Frame = None):
156
+ super().__init__(bind_func=bind_func,
157
+ name=name,
158
+ label_info=label_info,
159
+ entry_info=entry_info,
160
+ button_info=button_info,
161
+ style=style,
162
+ tab_index=tab_index,
163
+ async_run=async_run,
164
+ mode="dir",
165
+ frame=frame)
166
+
167
+
168
+ class BaseButton(BaseNotebookTool):
169
+ def __init__(self,
170
+ bind_func,
171
+ name: str = None,
172
+ text: str = "Start",
173
+ icon: str = None,
174
+ checked_text: str = None,
175
+ async_run: bool = True,
176
+ style: str = "primary",
177
+ tab_index: int = 0,
178
+ concurrency_mode: bool = False,
179
+ side: str = RIGHT,
180
+ add_width=8,
181
+ frame: tkinter.Frame = None):
182
+ super().__init__(bind_func,
183
+ name=name,
184
+ style=style,
185
+ tab_index=tab_index,
186
+ async_run=async_run,
187
+ concurrency_mode=concurrency_mode,
188
+ frame=frame)
189
+ self.text = text
190
+ self.checked_text = checked_text
191
+ self.add_width = add_width
192
+ self.side = side
193
+
194
+ self.icon = icon
195
+
196
+ def build(self, **kwargs) -> tkinter.Frame:
197
+ super().build(**kwargs)
198
+ if self.frame:
199
+ frame = self.frame
200
+ else:
201
+ frame = ttk.Frame(self.master, style="TFrame")
202
+ frame.pack(side="top", fill="x", padx=5, pady=5)
203
+ if self.icon:
204
+ self.icon = tkinter.PhotoImage(file=self.icon)
205
+ else:
206
+ self.icon = None
207
+
208
+ self.text_var = tkinter.StringVar(frame, value=self.text)
209
+
210
+ def click_btn():
211
+ self.btn.configure(style=self.style + "TButton")
212
+ self.btn.configure(state="disable")
213
+ if self.checked_text:
214
+ self.text_var.set(self.checked_text)
215
+
216
+ def done_btn():
217
+ self.btn.configure(style=self.style + "TButton")
218
+ self.btn.configure(state="normal")
219
+ self.text_var.set(self.text)
220
+
221
+ if not self.bind_func:
222
+ # 不知道为啥必须要有,不然文字不会显示,会头Debug一下
223
+ self.bind_func = lambda x: None
224
+ self.btn = ttk.Button(frame,
225
+ textvariable=self.text_var,
226
+ image=self.icon,
227
+ width=len(self.text) + self.add_width,
228
+ compound='left',
229
+ command=self._callback(self.bind_func, click_btn, done_btn),
230
+ style=self.style + "TButton")
231
+
232
+ self.btn.pack(side=make_side(self.side), padx=5, pady=5)
233
+ return frame
234
+
235
+
236
+ class RunButton(BaseButton):
237
+ def __init__(self,
238
+ bind_func,
239
+ name: str = None,
240
+ text: str = "Start Processing",
241
+ checked_text: str = "Processing...",
242
+ async_run: bool = True,
243
+ style: str = "success",
244
+ tab_index: int = 0,
245
+ concurrency_mode: bool = False,
246
+ side: str = RIGHT,
247
+ frame: tkinter.Frame = None):
248
+ super().__init__(bind_func=bind_func,
249
+ name=name,
250
+ text=text,
251
+ checked_text=checked_text,
252
+ async_run=async_run,
253
+ style=style,
254
+ tab_index=tab_index,
255
+ concurrency_mode=concurrency_mode,
256
+ add_width=6,
257
+ icon=RUN_ICON,
258
+ side=side,
259
+ frame=frame)
260
+
261
+
262
+ class InputBox(BaseNotebookTool):
263
+ def __init__(self,
264
+ name: str = None,
265
+ default: str = "Please input here...",
266
+ label_info: str = "InputBox",
267
+ style: str = "primary",
268
+ tab_index=0,
269
+ frame: tkinter.Frame = None):
270
+ super().__init__(name=name,
271
+ style=style,
272
+ tab_index=tab_index,
273
+ frame=frame)
274
+ self.input_vars = tkinter.StringVar(value=default)
275
+ self.label_info = label_info
276
+
277
+ def build(self, **kwargs):
278
+ super().build(**kwargs)
279
+ if self.frame:
280
+ frame = self.frame
281
+ else:
282
+ frame = ttk.Frame(self.master, style="TFrame")
283
+ frame.pack(side="top", fill="x", padx=5, pady=5)
284
+ label = ttk.Label(frame,
285
+ text=self.label_info,
286
+ style="TLabel",
287
+ width=LABEL_WIDTH)
288
+ label.pack(side="left")
289
+
290
+ entry = ttk.Entry(frame,
291
+ style=self.style + "info.TEntry",
292
+ textvariable=self.input_vars,
293
+ width=INPUT_BOX_LEN)
294
+ entry.pack(side="left", fill="x", padx=5, pady=2)
295
+ return frame
296
+
297
+ def get_arg_info(self) -> ArgInfo:
298
+ field = self.name if self.name else self.__class__.__name__
299
+ arg_info = ArgInfo(name=field, set_func=self.input_vars.set, get_func=self.input_vars.get)
300
+
301
+ return arg_info
302
+
303
+
304
+ class Combobox(BaseNotebookTool):
305
+ def __init__(self,
306
+ bind_func=None,
307
+ name=None,
308
+ title: str = "Please select",
309
+ options: List[str] = None,
310
+ style="custom",
311
+ tab_index=0,
312
+ frame: tkinter.Frame = None):
313
+ super().__init__(bind_func=bind_func,
314
+ name=name,
315
+ style=style,
316
+ tab_index=tab_index,
317
+ frame=frame)
318
+ self.title = title
319
+ self.options = options
320
+
321
+ self.options = options if options else ["--请选择--"]
322
+
323
+ def build(self, **kwargs):
324
+ super().build(**kwargs)
325
+ if self.frame:
326
+ frame = self.frame
327
+ else:
328
+ frame = ttk.Frame(self.master, style="TFrame")
329
+ frame.pack(side="top", fill="x", padx=5, pady=5)
330
+ label = ttk.Label(frame,
331
+ text=self.title,
332
+ style="TLabel",
333
+ width=LABEL_WIDTH)
334
+ label.pack(side="left")
335
+ self.comb = ttk.Combobox(frame,
336
+ style=self.style + "TCombobox",
337
+ values=self.options)
338
+ self.comb.current(0)
339
+ if self.bind_func:
340
+ self.comb.bind('<<ComboboxSelected>>', self._callback(self.bind_func))
341
+ self.comb.pack(side="left", padx=5, pady=2)
342
+
343
+ return frame
344
+
345
+ def get_arg_info(self) -> ArgInfo:
346
+ field = self.name if self.name else self.__class__.__name__
347
+ arg_info = ArgInfo(name=field, set_func=self.comb.set, get_func=self.comb.get)
348
+
349
+ return arg_info
350
+
351
+
352
+ class Slider(BaseNotebookTool):
353
+ def __init__(self,
354
+ name=None,
355
+ title: str = "Please slide",
356
+ default: int = 0,
357
+ min_size: int = 0,
358
+ max_size: int = 100,
359
+ dtype=int,
360
+ style: str = "primary",
361
+ tab_index: int = 0,
362
+ frame: tkinter.Frame = None):
363
+ super().__init__(name=name,
364
+ style=style,
365
+ tab_index=tab_index,
366
+ frame=frame)
367
+ self.title = title
368
+ self.default = default
369
+ self.min_size = min_size
370
+ self.max_size = max_size
371
+ self.dtype = dtype
372
+
373
+ def slider_var_trace(self, *args):
374
+ v = self.scale.get()
375
+ self.value_var.set(f"Current: {self.dtype(v)}")
376
+
377
+ def build(self, **kwargs):
378
+ super().build(**kwargs)
379
+ if self.frame:
380
+ frame = self.frame
381
+ else:
382
+ frame = ttk.Frame(self.master, style="TFrame")
383
+ frame.pack(side="top", fill="x", padx=5, pady=5)
384
+
385
+ self.slider_var = select_var_dtype(self.dtype)(frame, value=self.default)
386
+ self.value_var = tkinter.StringVar(frame, value=f"Current: {self.default}")
387
+ self.slider_var.trace("w", self.slider_var_trace)
388
+
389
+ label = ttk.Label(frame,
390
+ text=self.title,
391
+ style="TLabel",
392
+ width=LABEL_WIDTH)
393
+ label.pack(side="left")
394
+ self.scale = ttk.Scale(frame,
395
+ from_=self.min_size,
396
+ to=self.max_size,
397
+ value=self.default,
398
+ variable=self.slider_var)
399
+ # ToDo ttk 的Bug
400
+ # self.scale.configure(style="info.TSlider")
401
+ self.scale.pack(side="left", padx=5, fill="x", expand="yes")
402
+ self.value = ttk.Label(frame,
403
+ textvariable=self.value_var,
404
+ style="TLabel",
405
+ width=LABEL_WIDTH)
406
+ self.value.pack(side="right")
407
+ return frame
408
+
409
+ def get_arg_info(self) -> ArgInfo:
410
+ field = self.name if self.name else self.__class__.__name__
411
+ arg_info = ArgInfo(name=field, set_func=self.scale.set, get_func=self.scale.get)
412
+
413
+ return arg_info
414
+
415
+
416
+ class BaseCheckButton(BaseNotebookTool):
417
+ def __init__(self,
418
+ options: str or Tuple[str, bool] or List[Tuple[str, bool]],
419
+ bind_func=None,
420
+ name=None,
421
+ title="Please select",
422
+ style="primary",
423
+ button_style="TCheckbutton",
424
+ tab_index=0,
425
+ async_run=False,
426
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG,
427
+ mode=None,
428
+ frame: tkinter.Frame = None):
429
+ super().__init__(bind_func=bind_func,
430
+ name=name,
431
+ style=style,
432
+ tab_index=tab_index,
433
+ async_run=async_run,
434
+ concurrency_mode=concurrency_mode,
435
+ frame=frame)
436
+ self.title = title
437
+ self.mode = mode
438
+ if isinstance(options, str):
439
+ self.options = {options: 0}
440
+ if isinstance(options, tuple):
441
+ self.options = {options[0]: 1 if options[1] else 0}
442
+ if isinstance(options, list):
443
+ self.options = OrderedDict()
444
+ if len(options[0]) != 2:
445
+ raise TypeError(f"The 'options' arg of {self.__class__.__name__} should be str or List[Tuple[str, bool]] format\n"
446
+ f"Example:\n"
447
+ f"'选择框1' or [('选择1', 0), ('选择2', 1), ('选择3', 0)]")
448
+ for option in options:
449
+ self.options[option[0]] = 1 if option[1] else 0
450
+ self.button_style = button_style
451
+
452
+ def build(self, *args, **kwargs):
453
+ super().build(*args, **kwargs)
454
+ if self.frame:
455
+ frame = self.frame
456
+ else:
457
+ frame = ttk.Frame(self.master, style="TFrame")
458
+ frame.pack(side="top", fill="x", padx=5, pady=5)
459
+ label = ttk.Label(frame,
460
+ text=self.title,
461
+ style="TLabel",
462
+ width=LABEL_WIDTH)
463
+ label.pack(side="left")
464
+
465
+ self.value_vars = dict()
466
+ for option in self.options:
467
+ self.value_vars[option] = tkinter.StringVar(frame, value=self.options[option])
468
+ if self.mode == "ToolButton":
469
+ pad_x = 0
470
+ else:
471
+ pad_x = 5
472
+ ttk.Checkbutton(frame,
473
+ text=option,
474
+ style=self.style + self.button_style,
475
+ variable=self.value_vars[option],
476
+ command=self._callback(self.bind_func)).pack(side="left", padx=pad_x)
477
+ return frame
478
+
479
+ def get_arg_info(self) -> ArgInfo:
480
+ field = self.name if self.name else self.__class__.__name__
481
+ arg_info = ArgInfo()
482
+ for v in self.value_vars:
483
+ arg_info += ArgInfo(name=field + "-" + v, set_func=self.value_vars[v].set, get_func=self.value_vars[v].get)
484
+
485
+ return arg_info
486
+
487
+
488
+ class CheckButton(BaseCheckButton):
489
+ def __init__(self,
490
+ options: str or Tuple[str] or List[Tuple[str, bool]],
491
+ bind_func=None,
492
+ name=None,
493
+ title="Please select",
494
+ style="primary",
495
+ tab_index=0,
496
+ async_run=False,
497
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG,
498
+ frame: tkinter.Frame = None):
499
+ super().__init__(options=options,
500
+ bind_func=bind_func,
501
+ name=name,
502
+ title=title,
503
+ style=style,
504
+ button_style="TCheckbutton",
505
+ tab_index=tab_index,
506
+ async_run=async_run,
507
+ concurrency_mode=concurrency_mode,
508
+ frame=frame)
509
+
510
+
511
+ class CheckToolButton(BaseCheckButton):
512
+ def __init__(self,
513
+ options: str or Tuple[str] or List[Tuple[str, bool]],
514
+ bind_func=None,
515
+ name=None,
516
+ title="Please select",
517
+ style="info",
518
+ tab_index=0,
519
+ async_run=False,
520
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG,
521
+ frame: tkinter.Frame = None):
522
+ super().__init__(options=options,
523
+ bind_func=bind_func,
524
+ name=name,
525
+ title=title,
526
+ style=style,
527
+ button_style="Toolbutton",
528
+ tab_index=tab_index,
529
+ async_run=async_run,
530
+ concurrency_mode=concurrency_mode,
531
+ mode="ToolButton",
532
+ frame=frame)
533
+
534
+
535
+ class CheckObviousToolButton(BaseCheckButton):
536
+ def __init__(self,
537
+ options: str or Tuple[str] or List[Tuple[str, bool]],
538
+ bind_func=None,
539
+ name=None,
540
+ title="Please select",
541
+ style="primary",
542
+ tab_index=0,
543
+ async_run=False,
544
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG,
545
+ frame: tkinter.Frame = None):
546
+ super().__init__(options=options,
547
+ bind_func=bind_func,
548
+ name=name,
549
+ title=title,
550
+ style=style,
551
+ button_style="Outline.Toolbutton",
552
+ tab_index=tab_index,
553
+ async_run=async_run,
554
+ concurrency_mode=concurrency_mode,
555
+ mode="ToolButton",
556
+ frame=frame)
557
+
558
+
559
+ class ToggleButton(BaseCheckButton):
560
+ def __init__(self,
561
+ options: str or Tuple[str],
562
+ bind_func=None,
563
+ name=None,
564
+ title="Please select",
565
+ style="primary",
566
+ tab_index=0,
567
+ async_run=False,
568
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG,
569
+ frame: tkinter.Frame = None):
570
+ assert not isinstance(options, list), "There should be only one option for ToggleButton"
571
+ super().__init__(options=options,
572
+ bind_func=bind_func,
573
+ name=name,
574
+ title=title,
575
+ style=style,
576
+ button_style="Roundtoggle.Toolbutton",
577
+ tab_index=tab_index,
578
+ async_run=async_run,
579
+ concurrency_mode=concurrency_mode,
580
+ frame=frame)
581
+
582
+
583
+ class BaseRadioButton(BaseNotebookTool):
584
+ def __init__(self,
585
+ options: str or List[str],
586
+ default: str = None,
587
+ bind_func=None,
588
+ name=None,
589
+ title="Please select",
590
+ style="primary",
591
+ button_style="TRadiobutton",
592
+ tab_index=0,
593
+ async_run=False,
594
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG,
595
+ mode=None,
596
+ frame: tkinter.Frame = None):
597
+ super().__init__(bind_func=bind_func,
598
+ name=name,
599
+ style=style,
600
+ tab_index=tab_index,
601
+ async_run=async_run,
602
+ concurrency_mode=concurrency_mode,
603
+ frame=frame)
604
+ self.title = title
605
+ self.mode = mode
606
+ self.options = [options] if isinstance(options, str) else options
607
+ self.default = default if default else options[0]
608
+ self.button_style = button_style
609
+
610
+ def build(self, *args, **kwargs):
611
+ super().build(*args, **kwargs)
612
+ if self.frame:
613
+ frame = self.frame
614
+ else:
615
+ frame = ttk.Frame(self.master, style="TFrame")
616
+ frame.pack(side="top", fill="x", padx=5, pady=5)
617
+
618
+ label = ttk.Label(frame,
619
+ text=self.title,
620
+ style="TLabel",
621
+ width=LABEL_WIDTH)
622
+ label.pack(side="left")
623
+
624
+ self.value_var = tkinter.StringVar(frame, value=self.options[0])
625
+ for option in self.options:
626
+ if self.mode == "ToolButton":
627
+ pad_x = 0
628
+ else:
629
+ pad_x = 5
630
+ ttk.Radiobutton(frame,
631
+ text=option,
632
+ style=self.style + self.button_style,
633
+ variable=self.value_var,
634
+ value=option,
635
+ command=self._callback(self.bind_func)).pack(side="left", padx=pad_x)
636
+ return frame
637
+
638
+ def get_arg_info(self) -> ArgInfo:
639
+ field = self.name if self.name else self.__class__.__name__
640
+ arg_info = ArgInfo(name=field, set_func=self.value_var.set, get_func=self.value_var.get)
641
+
642
+ return arg_info
643
+
644
+
645
+ class RadioButton(BaseRadioButton):
646
+ def __init__(self,
647
+ options: str or List[str],
648
+ default: str = None,
649
+ bind_func=None,
650
+ name=None,
651
+ title="Please select",
652
+ style="primary",
653
+ tab_index=0,
654
+ async_run=False,
655
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG,
656
+ frame: tkinter.Frame = None):
657
+ super().__init__(options=options,
658
+ default=default,
659
+ bind_func=bind_func,
660
+ name=name,
661
+ title=title,
662
+ style=style,
663
+ button_style="TRadiobutton",
664
+ tab_index=tab_index,
665
+ async_run=async_run,
666
+ concurrency_mode=concurrency_mode,
667
+ mode=None,
668
+ frame=frame)
669
+
670
+
671
+ class RadioToolButton(BaseRadioButton):
672
+ def __init__(self,
673
+ options: str or List[str],
674
+ default: str = None,
675
+ bind_func=None,
676
+ name=None,
677
+ title="Please select",
678
+ style="info",
679
+ tab_index=0,
680
+ async_run=False,
681
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG,
682
+ frame: tkinter.Frame = None):
683
+ super().__init__(options=options,
684
+ default=default,
685
+ bind_func=bind_func,
686
+ name=name,
687
+ title=title,
688
+ style=style,
689
+ button_style="Toolbutton",
690
+ tab_index=tab_index,
691
+ async_run=async_run,
692
+ concurrency_mode=concurrency_mode,
693
+ mode="ToolButton",
694
+ frame=frame)
695
+
696
+
697
+ class RadioObviousToolButton(BaseRadioButton):
698
+ def __init__(self,
699
+ options: str or List[str],
700
+ default: str = None,
701
+ bind_func=None,
702
+ name=None,
703
+ title="Please select",
704
+ style="primary",
705
+ tab_index=0,
706
+ async_run=False,
707
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG,
708
+ frame: tkinter.Frame = None):
709
+ super().__init__(options=options,
710
+ default=default,
711
+ bind_func=bind_func,
712
+ name=name,
713
+ title=title,
714
+ style=style,
715
+ button_style="Outline.Toolbutton",
716
+ tab_index=tab_index,
717
+ async_run=async_run,
718
+ concurrency_mode=concurrency_mode,
719
+ mode="ToolButton",
720
+ frame=frame)
721
+
722
+
723
+ class Progressbar(BaseNotebookTool):
724
+ def __init__(self,
725
+ title: str = "Progressbar",
726
+ default: int = 0,
727
+ max_size: int = 100,
728
+ name: str = None,
729
+ style: str = "primary",
730
+ tab_index: int = 0,
731
+ async_run: bool = False,
732
+ concurrency_mode=ConcurrencyModeFlag.SAFE_CONCURRENCY_MODE_FLAG,
733
+ frame: tkinter.Frame = None):
734
+ super().__init__(name=name,
735
+ style=style,
736
+ tab_index=tab_index,
737
+ async_run=async_run,
738
+ concurrency_mode=concurrency_mode,
739
+ frame=frame)
740
+ self.title = title
741
+ self.default_value = default
742
+ self.max_size = max_size
743
+
744
+ def progressbar_var_trace(self, *args):
745
+ v = self.progressbar_var.get()
746
+ self.value_var.set(f"Progress {v:.2f}%")
747
+
748
+ def build(self, *args, **kwargs):
749
+ super().build(*args, **kwargs)
750
+ if self.frame:
751
+ frame = self.frame
752
+ else:
753
+ frame = ttk.Frame(self.master, style="TFrame")
754
+ frame.pack(side="top", fill="x", padx=5, pady=5, expand="yes")
755
+
756
+ self.progressbar_var = tkinter.IntVar(frame, value=self.default_value)
757
+ self.value_var = tkinter.StringVar(frame, value=f"Progress: {self.default_value:.2f}%")
758
+ self.progressbar_var.trace("w", self.progressbar_var_trace)
759
+
760
+ label = ttk.Label(frame,
761
+ text=self.title,
762
+ style="TLabel",
763
+ width=LABEL_WIDTH)
764
+ label.pack(side="left")
765
+
766
+ progressbar = ttk.Progressbar(frame,
767
+ variable=self.progressbar_var,
768
+ style=self.style + "Striped.Horizontal.TProgressbar")
769
+ progressbar.pack(side="left", fill="x", expand="yes", padx=5, pady=2)
770
+
771
+ self.value = ttk.Label(frame,
772
+ textvariable=self.value_var,
773
+ style="TLabel",
774
+ width=LABEL_WIDTH)
775
+ self.value.pack(side="left")
776
+ return frame
777
+
778
+ def get_arg_info(self) -> ArgInfo:
779
+ field = self.name if self.name else self.__class__.__name__
780
+ arg_info = ArgInfo(name=field, set_func=self.progressbar_var.set, get_func=self.progressbar_var.get)
781
+
782
+ return arg_info
783
+
784
+
785
+ class BaseCombine(BaseNotebookTool):
786
+ def __init__(self,
787
+ tools: BaseNotebookTool or List[BaseNotebookTool],
788
+ side=HORIZONTAL,
789
+ title: str = None,
790
+ text: str = None,
791
+ style: str = None,
792
+ tab_index: int = None,
793
+ frame: tkinter.Frame = None):
794
+ super().__init__(tab_index=tab_index, style=style, frame=frame)
795
+ self.side = "top" if side == HORIZONTAL else "left"
796
+ self.title = title
797
+ self.text = text
798
+
799
+ self.tools = tools if isinstance(tools, list) else [tools]
800
+
801
+ self.tab_index = tab_index if tab_index else self.tools[0].tab_index
802
+
803
+ for tool_id in range(len(self.tools)):
804
+ self.tools[tool_id].tab_index = self.tab_index
805
+
806
+ def get_arg_info(self) -> ArgInfo:
807
+ local_info = ArgInfo()
808
+ for tool_id in range(len(self.tools)):
809
+ local_info += self.tools[tool_id].get_arg_info()
810
+ return local_info
811
+
812
+
813
+ class BaseFrameCombine(BaseCombine):
814
+ def build(self, *args, **kwargs):
815
+ super().build(self, *args, **kwargs)
816
+
817
+ if self.frame:
818
+ frame = self.frame
819
+ else:
820
+ style_mode = "TLabelframe" if self.title else "TFrame"
821
+ if self.title:
822
+ frame = ttk.LabelFrame(self.master, text=self.title, style=self.style + style_mode)
823
+ else:
824
+ frame = ttk.Frame(self.master, text=self.title, style=self.style + style_mode)
825
+ frame.pack(side="left", anchor="nw", fill="both", expand="yes", padx=DEFAULT_PAD, pady=DEFAULT_PAD)
826
+ if self.text:
827
+ label = ttk.Label(frame,
828
+ text=self.text,
829
+ style="TLabel")
830
+ label.pack(side="top", anchor="nw", padx=5)
831
+ for tool in self.tools:
832
+ kwargs["master"] = frame
833
+ tool.build(*args, **kwargs)
834
+ return frame
835
+
836
+
837
+ class HorizontalFrameCombine(BaseFrameCombine):
838
+ def __init__(self,
839
+ tools: BaseNotebookTool or List[BaseNotebookTool],
840
+ title=None,
841
+ style: str = None,
842
+ text: str = None,
843
+ tab_index: int = 0,
844
+ frame: tkinter.Frame = None):
845
+ super().__init__(tools=tools,
846
+ side=HORIZONTAL,
847
+ title=title,
848
+ style=style,
849
+ text=text,
850
+ tab_index=tab_index,
851
+ frame=frame)
852
+
853
+
854
+ class VerticalFrameCombine(BaseFrameCombine):
855
+ def __init__(self,
856
+ tools: BaseNotebookTool or List[BaseNotebookTool],
857
+ title=None,
858
+ style: str = None,
859
+ text: str = None,
860
+ tab_index: int = 0,
861
+ frame: tkinter.Frame = None):
862
+ super().__init__(tools=tools,
863
+ side=VERTICAL,
864
+ title=title,
865
+ style=style,
866
+ text=text,
867
+ tab_index=tab_index,
868
+ frame=frame)
869
+
870
+
871
+ class HorizontalToolsCombine(BaseCombine):
872
+ def __init__(self,
873
+ tools: BaseNotebookTool or List[BaseNotebookTool],
874
+ title=None,
875
+ style: str = None,
876
+ text: str = None,
877
+ tab_index: int = None,
878
+ frame: tkinter.Frame = None):
879
+ super().__init__(tools=tools,
880
+ side=HORIZONTAL,
881
+ title=title,
882
+ style=style,
883
+ text=text,
884
+ tab_index=tab_index,
885
+ frame=frame)
886
+
887
+ def build(self, *args, **kwargs):
888
+ super().build(self, *args, **kwargs)
889
+
890
+ style_mode = "TLabelframe" if self.title else "TFrame"
891
+ if self.title:
892
+ frame = ttk.LabelFrame(self.master, text=self.title, style=self.style + style_mode)
893
+ else:
894
+ frame = ttk.Frame(self.master, style=self.style + style_mode)
895
+ frame.pack(side="top", fill="x", padx=DEFAULT_PAD, pady=DEFAULT_PAD)
896
+ if self.text:
897
+ label = ttk.Label(frame,
898
+ text=self.text,
899
+ style="TLabel")
900
+ label.pack(side="top", anchor="nw", padx=DEFAULT_PAD)
901
+ for tool in self.tools:
902
+ kwargs["master"] = self.frame
903
+ tool.frame = frame
904
+ tool.build(*args, **kwargs)
905
+ return frame
906
+
907
+
908
+ class Label(BaseNotebookTool):
909
+ def __init__(self,
910
+ name: str = None,
911
+ text: str = None,
912
+ title: str = None,
913
+ alignment: str = LEFT + TOP,
914
+ style: str = "primary",
915
+ tab_index: int = 0,
916
+ frame: tkinter.Frame = None):
917
+ super(Label, self).__init__(name=name,
918
+ style=style,
919
+ tab_index=tab_index,
920
+ frame=frame)
921
+ self.text = text
922
+ self.title = title
923
+ self.alignment = alignment
924
+
925
+ self.label_var = tkinter.StringVar(value=self.text)
926
+
927
+ def build(self, *args, **kwargs) -> tkinter.Frame:
928
+ super(Label, self).build(*args, **kwargs)
929
+ if self.frame:
930
+ frame = self.frame
931
+ else:
932
+ frame = ttk.Frame(self.master)
933
+ frame.pack(side="top", fill="both", padx=DEFAULT_PAD, pady=DEFAULT_PAD)
934
+
935
+ title = ttk.Label(frame,
936
+ text=self.title,
937
+ style="TLabel",
938
+ width=LABEL_WIDTH)
939
+ title.pack(side="left")
940
+
941
+ label = ttk.Label(frame,
942
+ text=self.text,
943
+ textvariable=self.label_var,
944
+ style="TLabel")
945
+ # make_anchor(self.alignment)
946
+ label.pack(anchor=make_anchor(self.alignment), padx=DEFAULT_PAD)
947
+ return frame
948
+
949
+ def get_arg_info(self) -> ArgInfo:
950
+ field = self.name if self.name else self.__class__.__name__
951
+ local_info = ArgInfo(field, set_func=self.label_var.set, get_func=self.label_var.get)
952
+ return local_info
cube_qgui/os_tools.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Author: Acer Zhang
2
+ # Datetime: 2021/9/17
3
+ # Copyright belongs to the author.
4
+ # Please indicate the source for reprinting.
5
+ import sys
6
+
7
+
8
+ class StdOutWrapper:
9
+ def __init__(self, stdout, callback=None, do_print=True):
10
+ self.buff = ""
11
+ self.stdout = stdout
12
+ self.callback = callback
13
+ self.do_print = do_print
14
+
15
+ def write(self, output_stream):
16
+ self.buff += output_stream
17
+ if self.do_print:
18
+ self.stdout.write(output_stream)
19
+ if self.callback and ("\n" in self.buff or "\r" in output_stream):
20
+ self.callback(self.buff)
21
+ self.buff = ""
22
+
23
+ def flush(self):
24
+ self.buff = ""
25
+
26
+ def __del__(self):
27
+ sys.stdout = self.stdout
28
+
29
+
30
+ class DataCache:
31
+ def __init__(self, seq_len=10, cache=7):
32
+ assert seq_len >= cache, "请设置seq_len的值低于cache"
33
+ self.seq_len = seq_len
34
+ self.cache = cache
35
+ self.seq = list()
36
+
37
+ def add(self, item):
38
+ if len(self.seq) == self.seq_len:
39
+ for i in range(self.seq_len - self.cache):
40
+ self.seq.pop(0)
41
+ self.seq.append(item)
42
+
43
+ def __add__(self, other):
44
+ self.add(other)
45
+ return self
cube_qgui/resources/demo/panda.jpg ADDED
cube_qgui/resources/icon/double_down.png ADDED
cube_qgui/resources/icon/double_up.png ADDED
cube_qgui/resources/icon/github.png ADDED
cube_qgui/resources/icon/play_w.png ADDED
cube_qgui/resources/icon/up_cloud.png ADDED
cube_qgui/theme/ttkbootstrap_themes.json ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "themes": [
3
+ {
4
+ "name": "paddlelight",
5
+ "font": "Helvetica 10",
6
+ "type": "light",
7
+ "colors": {
8
+ "primary": "#2932e1",
9
+ "secondary": "#4e9bf8",
10
+ "success": "#18bc9c",
11
+ "info": "#3498db",
12
+ "warning": "#f39c12",
13
+ "danger": "#e74c3c",
14
+ "bg": "#ffffff",
15
+ "fg": "#212529",
16
+ "selectbg": "#95a5a6",
17
+ "selectfg": "#ffffff",
18
+ "border": "#ced4da",
19
+ "inputfg": "#212529",
20
+ "inputbg": "#ecf0f1"
21
+ }
22
+ },
23
+ {
24
+ "name": "paddledark",
25
+ "font": "Helvetica 10",
26
+ "type": "dark",
27
+ "colors": {
28
+ "primary": "#2932e1",
29
+ "secondary": "#4e9bf8",
30
+ "success": "#00bc8c",
31
+ "info": "#3498db",
32
+ "warning": "#f39c12",
33
+ "danger": "#e74c3c",
34
+ "bg": "#666666",
35
+ "fg": "#ffffff",
36
+ "selectbg": "#444444",
37
+ "selectfg": "#ffffff",
38
+ "border": "#222222",
39
+ "inputfg": "#333333",
40
+ "inputbg": "#adb5bd"
41
+ }
42
+ },
43
+ {
44
+ "name": "pytorch",
45
+ "font": "Helvetica 10",
46
+ "type": "light",
47
+ "colors": {
48
+ "primary": "#ee4c2c",
49
+ "secondary": "#db593a",
50
+ "success": "#18bc9c",
51
+ "info": "#3498db",
52
+ "warning": "#f39c12",
53
+ "danger": "#e74c3c",
54
+ "bg": "#ffffff",
55
+ "fg": "#212529",
56
+ "selectbg": "#321e5d",
57
+ "selectfg": "#ffffff",
58
+ "border": "#ced4da",
59
+ "inputfg": "#212529",
60
+ "inputbg": "#ecf0f1"
61
+ }
62
+ },
63
+ {
64
+ "name": "tensorflow",
65
+ "font": "Helvetica 10",
66
+ "type": "light",
67
+ "colors": {
68
+ "primary": "#ed722f",
69
+ "secondary": "#95a5a6",
70
+ "success": "#18bc9c",
71
+ "info": "#3498db",
72
+ "warning": "#f39c12",
73
+ "danger": "#e74c3c",
74
+ "bg": "#ffffff",
75
+ "fg": "#212529",
76
+ "selectbg": "#95a5a6",
77
+ "selectfg": "#ffffff",
78
+ "border": "#ced4da",
79
+ "inputfg": "#212529",
80
+ "inputbg": "#ecf0f1"
81
+ }
82
+ },
83
+ {
84
+ "name": "qgui",
85
+ "font": "Helvetica 10",
86
+ "type": "light",
87
+ "colors": {
88
+ "primary": "#2c3e50",
89
+ "secondary": "#4e9bf8",
90
+ "success": "#18bc9c",
91
+ "info": "#3498db",
92
+ "warning": "#f39c12",
93
+ "danger": "#e74c3c",
94
+ "bg": "#ffffff",
95
+ "fg": "#212529",
96
+ "selectbg": "#95a5a6",
97
+ "selectfg": "#ffffff",
98
+ "border": "#ced4da",
99
+ "inputfg": "#212529",
100
+ "inputbg": "#ecf0f1"
101
+ }
102
+ }
103
+ ]
104
+ }
cube_qgui/third_party/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # Author: Acer Zhang
2
+ # Datetime: 2021/9/17
3
+ # Copyright belongs to the author.
4
+ # Please indicate the source for reprinting.