pycforge-sdk 0.6.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (559) hide show
  1. pycforge_sdk/__init__.py +6 -0
  2. pycforge_sdk/__main__.py +3 -0
  3. pycforge_sdk/catalogue.py +287 -0
  4. pycforge_sdk/cli.py +114 -0
  5. pycforge_sdk/connection.py +136 -0
  6. pycforge_sdk/discovery.py +227 -0
  7. pycforge_sdk/editing.py +84 -0
  8. pycforge_sdk/engine_launch.py +45 -0
  9. pycforge_sdk/engine_worker.py +53 -0
  10. pycforge_sdk/gui/__init__.py +1 -0
  11. pycforge_sdk/gui/__main__.py +3 -0
  12. pycforge_sdk/gui/app.py +36 -0
  13. pycforge_sdk/gui/dialogs.py +310 -0
  14. pycforge_sdk/gui/editor.py +412 -0
  15. pycforge_sdk/gui/help/index.html +9 -0
  16. pycforge_sdk/gui/identity.py +139 -0
  17. pycforge_sdk/gui/jobs.py +146 -0
  18. pycforge_sdk/gui/reference.py +39 -0
  19. pycforge_sdk/gui/resources/sdk-mark.png +0 -0
  20. pycforge_sdk/gui/scanner.py +134 -0
  21. pycforge_sdk/gui/startup.py +118 -0
  22. pycforge_sdk/gui/visual/__init__.py +1 -0
  23. pycforge_sdk/gui/visual/action_contract.py +550 -0
  24. pycforge_sdk/gui/visual/icons.py +117 -0
  25. pycforge_sdk/gui/visual/qt_actions.py +501 -0
  26. pycforge_sdk/gui/visual/qt_branding.py +47 -0
  27. pycforge_sdk/gui/visual/qt_dialog_chrome.py +337 -0
  28. pycforge_sdk/gui/visual/qt_file_icons.py +130 -0
  29. pycforge_sdk/gui/visual/qt_icons.py +80 -0
  30. pycforge_sdk/gui/visual/qt_screen_geometry.py +166 -0
  31. pycforge_sdk/gui/visual/qt_title_controls.py +333 -0
  32. pycforge_sdk/gui/visual/qt_window_chrome.py +314 -0
  33. pycforge_sdk/gui/visual/qt_window_resize.py +93 -0
  34. pycforge_sdk/gui/visual/qt_workspace_widgets.py +448 -0
  35. pycforge_sdk/gui/visual/resources/icons/128/add-document.png +0 -0
  36. pycforge_sdk/gui/visual/resources/icons/128/brand-mark.png +0 -0
  37. pycforge_sdk/gui/visual/resources/icons/128/bundle-search.png +0 -0
  38. pycforge_sdk/gui/visual/resources/icons/128/cancel.png +0 -0
  39. pycforge_sdk/gui/visual/resources/icons/128/check.png +0 -0
  40. pycforge_sdk/gui/visual/resources/icons/128/chevron-right.png +0 -0
  41. pycforge_sdk/gui/visual/resources/icons/128/close.png +0 -0
  42. pycforge_sdk/gui/visual/resources/icons/128/collapse-all.png +0 -0
  43. pycforge_sdk/gui/visual/resources/icons/128/command-palette.png +0 -0
  44. pycforge_sdk/gui/visual/resources/icons/128/convert.png +0 -0
  45. pycforge_sdk/gui/visual/resources/icons/128/copy.png +0 -0
  46. pycforge_sdk/gui/visual/resources/icons/128/cut.png +0 -0
  47. pycforge_sdk/gui/visual/resources/icons/128/decision-trace.png +0 -0
  48. pycforge_sdk/gui/visual/resources/icons/128/details.png +0 -0
  49. pycforge_sdk/gui/visual/resources/icons/128/diagnostics.png +0 -0
  50. pycforge_sdk/gui/visual/resources/icons/128/duplicate-line.png +0 -0
  51. pycforge_sdk/gui/visual/resources/icons/128/exit.png +0 -0
  52. pycforge_sdk/gui/visual/resources/icons/128/expand-all.png +0 -0
  53. pycforge_sdk/gui/visual/resources/icons/128/export.png +0 -0
  54. pycforge_sdk/gui/visual/resources/icons/128/find.png +0 -0
  55. pycforge_sdk/gui/visual/resources/icons/128/go-to-line.png +0 -0
  56. pycforge_sdk/gui/visual/resources/icons/128/go-to-output.png +0 -0
  57. pycforge_sdk/gui/visual/resources/icons/128/go-to-source.png +0 -0
  58. pycforge_sdk/gui/visual/resources/icons/128/help.png +0 -0
  59. pycforge_sdk/gui/visual/resources/icons/128/history.png +0 -0
  60. pycforge_sdk/gui/visual/resources/icons/128/indent.png +0 -0
  61. pycforge_sdk/gui/visual/resources/icons/128/link-c.png +0 -0
  62. pycforge_sdk/gui/visual/resources/icons/128/mappings.png +0 -0
  63. pycforge_sdk/gui/visual/resources/icons/128/module.png +0 -0
  64. pycforge_sdk/gui/visual/resources/icons/128/move-down.png +0 -0
  65. pycforge_sdk/gui/visual/resources/icons/128/move-line-down.png +0 -0
  66. pycforge_sdk/gui/visual/resources/icons/128/move-line-up.png +0 -0
  67. pycforge_sdk/gui/visual/resources/icons/128/move-up.png +0 -0
  68. pycforge_sdk/gui/visual/resources/icons/128/next.png +0 -0
  69. pycforge_sdk/gui/visual/resources/icons/128/open.png +0 -0
  70. pycforge_sdk/gui/visual/resources/icons/128/outdent.png +0 -0
  71. pycforge_sdk/gui/visual/resources/icons/128/outline.png +0 -0
  72. pycforge_sdk/gui/visual/resources/icons/128/paste.png +0 -0
  73. pycforge_sdk/gui/visual/resources/icons/128/previous.png +0 -0
  74. pycforge_sdk/gui/visual/resources/icons/128/primary-module.png +0 -0
  75. pycforge_sdk/gui/visual/resources/icons/128/redo.png +0 -0
  76. pycforge_sdk/gui/visual/resources/icons/128/remove-document.png +0 -0
  77. pycforge_sdk/gui/visual/resources/icons/128/replace.png +0 -0
  78. pycforge_sdk/gui/visual/resources/icons/128/save-as.png +0 -0
  79. pycforge_sdk/gui/visual/resources/icons/128/save.png +0 -0
  80. pycforge_sdk/gui/visual/resources/icons/128/select-all.png +0 -0
  81. pycforge_sdk/gui/visual/resources/icons/128/settings.png +0 -0
  82. pycforge_sdk/gui/visual/resources/icons/128/show-c.png +0 -0
  83. pycforge_sdk/gui/visual/resources/icons/128/split-view.png +0 -0
  84. pycforge_sdk/gui/visual/resources/icons/128/summary.png +0 -0
  85. pycforge_sdk/gui/visual/resources/icons/128/telemetry.png +0 -0
  86. pycforge_sdk/gui/visual/resources/icons/128/toggle-comment.png +0 -0
  87. pycforge_sdk/gui/visual/resources/icons/128/toggle-fold.png +0 -0
  88. pycforge_sdk/gui/visual/resources/icons/128/tools.png +0 -0
  89. pycforge_sdk/gui/visual/resources/icons/128/undo.png +0 -0
  90. pycforge_sdk/gui/visual/resources/icons/128/whitespace.png +0 -0
  91. pycforge_sdk/gui/visual/resources/icons/16/add-document.png +0 -0
  92. pycforge_sdk/gui/visual/resources/icons/16/brand-mark.png +0 -0
  93. pycforge_sdk/gui/visual/resources/icons/16/bundle-search.png +0 -0
  94. pycforge_sdk/gui/visual/resources/icons/16/cancel.png +0 -0
  95. pycforge_sdk/gui/visual/resources/icons/16/check.png +0 -0
  96. pycforge_sdk/gui/visual/resources/icons/16/chevron-right.png +0 -0
  97. pycforge_sdk/gui/visual/resources/icons/16/close.png +0 -0
  98. pycforge_sdk/gui/visual/resources/icons/16/collapse-all.png +0 -0
  99. pycforge_sdk/gui/visual/resources/icons/16/command-palette.png +0 -0
  100. pycforge_sdk/gui/visual/resources/icons/16/convert.png +0 -0
  101. pycforge_sdk/gui/visual/resources/icons/16/copy.png +0 -0
  102. pycforge_sdk/gui/visual/resources/icons/16/cut.png +0 -0
  103. pycforge_sdk/gui/visual/resources/icons/16/decision-trace.png +0 -0
  104. pycforge_sdk/gui/visual/resources/icons/16/details.png +0 -0
  105. pycforge_sdk/gui/visual/resources/icons/16/diagnostics.png +0 -0
  106. pycforge_sdk/gui/visual/resources/icons/16/duplicate-line.png +0 -0
  107. pycforge_sdk/gui/visual/resources/icons/16/exit.png +0 -0
  108. pycforge_sdk/gui/visual/resources/icons/16/expand-all.png +0 -0
  109. pycforge_sdk/gui/visual/resources/icons/16/export.png +0 -0
  110. pycforge_sdk/gui/visual/resources/icons/16/find.png +0 -0
  111. pycforge_sdk/gui/visual/resources/icons/16/go-to-line.png +0 -0
  112. pycforge_sdk/gui/visual/resources/icons/16/go-to-output.png +0 -0
  113. pycforge_sdk/gui/visual/resources/icons/16/go-to-source.png +0 -0
  114. pycforge_sdk/gui/visual/resources/icons/16/help.png +0 -0
  115. pycforge_sdk/gui/visual/resources/icons/16/history.png +0 -0
  116. pycforge_sdk/gui/visual/resources/icons/16/indent.png +0 -0
  117. pycforge_sdk/gui/visual/resources/icons/16/link-c.png +0 -0
  118. pycforge_sdk/gui/visual/resources/icons/16/mappings.png +0 -0
  119. pycforge_sdk/gui/visual/resources/icons/16/module.png +0 -0
  120. pycforge_sdk/gui/visual/resources/icons/16/move-down.png +0 -0
  121. pycforge_sdk/gui/visual/resources/icons/16/move-line-down.png +0 -0
  122. pycforge_sdk/gui/visual/resources/icons/16/move-line-up.png +0 -0
  123. pycforge_sdk/gui/visual/resources/icons/16/move-up.png +0 -0
  124. pycforge_sdk/gui/visual/resources/icons/16/next.png +0 -0
  125. pycforge_sdk/gui/visual/resources/icons/16/open.png +0 -0
  126. pycforge_sdk/gui/visual/resources/icons/16/outdent.png +0 -0
  127. pycforge_sdk/gui/visual/resources/icons/16/outline.png +0 -0
  128. pycforge_sdk/gui/visual/resources/icons/16/paste.png +0 -0
  129. pycforge_sdk/gui/visual/resources/icons/16/previous.png +0 -0
  130. pycforge_sdk/gui/visual/resources/icons/16/primary-module.png +0 -0
  131. pycforge_sdk/gui/visual/resources/icons/16/redo.png +0 -0
  132. pycforge_sdk/gui/visual/resources/icons/16/remove-document.png +0 -0
  133. pycforge_sdk/gui/visual/resources/icons/16/replace.png +0 -0
  134. pycforge_sdk/gui/visual/resources/icons/16/save-as.png +0 -0
  135. pycforge_sdk/gui/visual/resources/icons/16/save.png +0 -0
  136. pycforge_sdk/gui/visual/resources/icons/16/select-all.png +0 -0
  137. pycforge_sdk/gui/visual/resources/icons/16/settings.png +0 -0
  138. pycforge_sdk/gui/visual/resources/icons/16/show-c.png +0 -0
  139. pycforge_sdk/gui/visual/resources/icons/16/split-view.png +0 -0
  140. pycforge_sdk/gui/visual/resources/icons/16/summary.png +0 -0
  141. pycforge_sdk/gui/visual/resources/icons/16/telemetry.png +0 -0
  142. pycforge_sdk/gui/visual/resources/icons/16/toggle-comment.png +0 -0
  143. pycforge_sdk/gui/visual/resources/icons/16/toggle-fold.png +0 -0
  144. pycforge_sdk/gui/visual/resources/icons/16/tools.png +0 -0
  145. pycforge_sdk/gui/visual/resources/icons/16/undo.png +0 -0
  146. pycforge_sdk/gui/visual/resources/icons/16/whitespace.png +0 -0
  147. pycforge_sdk/gui/visual/resources/icons/20/add-document.png +0 -0
  148. pycforge_sdk/gui/visual/resources/icons/20/brand-mark.png +0 -0
  149. pycforge_sdk/gui/visual/resources/icons/20/bundle-search.png +0 -0
  150. pycforge_sdk/gui/visual/resources/icons/20/cancel.png +0 -0
  151. pycforge_sdk/gui/visual/resources/icons/20/check.png +0 -0
  152. pycforge_sdk/gui/visual/resources/icons/20/chevron-right.png +0 -0
  153. pycforge_sdk/gui/visual/resources/icons/20/close.png +0 -0
  154. pycforge_sdk/gui/visual/resources/icons/20/collapse-all.png +0 -0
  155. pycforge_sdk/gui/visual/resources/icons/20/command-palette.png +0 -0
  156. pycforge_sdk/gui/visual/resources/icons/20/convert.png +0 -0
  157. pycforge_sdk/gui/visual/resources/icons/20/copy.png +0 -0
  158. pycforge_sdk/gui/visual/resources/icons/20/cut.png +0 -0
  159. pycforge_sdk/gui/visual/resources/icons/20/decision-trace.png +0 -0
  160. pycforge_sdk/gui/visual/resources/icons/20/details.png +0 -0
  161. pycforge_sdk/gui/visual/resources/icons/20/diagnostics.png +0 -0
  162. pycforge_sdk/gui/visual/resources/icons/20/duplicate-line.png +0 -0
  163. pycforge_sdk/gui/visual/resources/icons/20/exit.png +0 -0
  164. pycforge_sdk/gui/visual/resources/icons/20/expand-all.png +0 -0
  165. pycforge_sdk/gui/visual/resources/icons/20/export.png +0 -0
  166. pycforge_sdk/gui/visual/resources/icons/20/find.png +0 -0
  167. pycforge_sdk/gui/visual/resources/icons/20/go-to-line.png +0 -0
  168. pycforge_sdk/gui/visual/resources/icons/20/go-to-output.png +0 -0
  169. pycforge_sdk/gui/visual/resources/icons/20/go-to-source.png +0 -0
  170. pycforge_sdk/gui/visual/resources/icons/20/help.png +0 -0
  171. pycforge_sdk/gui/visual/resources/icons/20/history.png +0 -0
  172. pycforge_sdk/gui/visual/resources/icons/20/indent.png +0 -0
  173. pycforge_sdk/gui/visual/resources/icons/20/link-c.png +0 -0
  174. pycforge_sdk/gui/visual/resources/icons/20/mappings.png +0 -0
  175. pycforge_sdk/gui/visual/resources/icons/20/module.png +0 -0
  176. pycforge_sdk/gui/visual/resources/icons/20/move-down.png +0 -0
  177. pycforge_sdk/gui/visual/resources/icons/20/move-line-down.png +0 -0
  178. pycforge_sdk/gui/visual/resources/icons/20/move-line-up.png +0 -0
  179. pycforge_sdk/gui/visual/resources/icons/20/move-up.png +0 -0
  180. pycforge_sdk/gui/visual/resources/icons/20/next.png +0 -0
  181. pycforge_sdk/gui/visual/resources/icons/20/open.png +0 -0
  182. pycforge_sdk/gui/visual/resources/icons/20/outdent.png +0 -0
  183. pycforge_sdk/gui/visual/resources/icons/20/outline.png +0 -0
  184. pycforge_sdk/gui/visual/resources/icons/20/paste.png +0 -0
  185. pycforge_sdk/gui/visual/resources/icons/20/previous.png +0 -0
  186. pycforge_sdk/gui/visual/resources/icons/20/primary-module.png +0 -0
  187. pycforge_sdk/gui/visual/resources/icons/20/redo.png +0 -0
  188. pycforge_sdk/gui/visual/resources/icons/20/remove-document.png +0 -0
  189. pycforge_sdk/gui/visual/resources/icons/20/replace.png +0 -0
  190. pycforge_sdk/gui/visual/resources/icons/20/save-as.png +0 -0
  191. pycforge_sdk/gui/visual/resources/icons/20/save.png +0 -0
  192. pycforge_sdk/gui/visual/resources/icons/20/select-all.png +0 -0
  193. pycforge_sdk/gui/visual/resources/icons/20/settings.png +0 -0
  194. pycforge_sdk/gui/visual/resources/icons/20/show-c.png +0 -0
  195. pycforge_sdk/gui/visual/resources/icons/20/split-view.png +0 -0
  196. pycforge_sdk/gui/visual/resources/icons/20/summary.png +0 -0
  197. pycforge_sdk/gui/visual/resources/icons/20/telemetry.png +0 -0
  198. pycforge_sdk/gui/visual/resources/icons/20/toggle-comment.png +0 -0
  199. pycforge_sdk/gui/visual/resources/icons/20/toggle-fold.png +0 -0
  200. pycforge_sdk/gui/visual/resources/icons/20/tools.png +0 -0
  201. pycforge_sdk/gui/visual/resources/icons/20/undo.png +0 -0
  202. pycforge_sdk/gui/visual/resources/icons/20/whitespace.png +0 -0
  203. pycforge_sdk/gui/visual/resources/icons/24/add-document.png +0 -0
  204. pycforge_sdk/gui/visual/resources/icons/24/brand-mark.png +0 -0
  205. pycforge_sdk/gui/visual/resources/icons/24/bundle-search.png +0 -0
  206. pycforge_sdk/gui/visual/resources/icons/24/cancel.png +0 -0
  207. pycforge_sdk/gui/visual/resources/icons/24/check.png +0 -0
  208. pycforge_sdk/gui/visual/resources/icons/24/chevron-right.png +0 -0
  209. pycforge_sdk/gui/visual/resources/icons/24/close.png +0 -0
  210. pycforge_sdk/gui/visual/resources/icons/24/collapse-all.png +0 -0
  211. pycforge_sdk/gui/visual/resources/icons/24/command-palette.png +0 -0
  212. pycforge_sdk/gui/visual/resources/icons/24/convert.png +0 -0
  213. pycforge_sdk/gui/visual/resources/icons/24/copy.png +0 -0
  214. pycforge_sdk/gui/visual/resources/icons/24/cut.png +0 -0
  215. pycforge_sdk/gui/visual/resources/icons/24/decision-trace.png +0 -0
  216. pycforge_sdk/gui/visual/resources/icons/24/details.png +0 -0
  217. pycforge_sdk/gui/visual/resources/icons/24/diagnostics.png +0 -0
  218. pycforge_sdk/gui/visual/resources/icons/24/duplicate-line.png +0 -0
  219. pycforge_sdk/gui/visual/resources/icons/24/exit.png +0 -0
  220. pycforge_sdk/gui/visual/resources/icons/24/expand-all.png +0 -0
  221. pycforge_sdk/gui/visual/resources/icons/24/export.png +0 -0
  222. pycforge_sdk/gui/visual/resources/icons/24/find.png +0 -0
  223. pycforge_sdk/gui/visual/resources/icons/24/go-to-line.png +0 -0
  224. pycforge_sdk/gui/visual/resources/icons/24/go-to-output.png +0 -0
  225. pycforge_sdk/gui/visual/resources/icons/24/go-to-source.png +0 -0
  226. pycforge_sdk/gui/visual/resources/icons/24/help.png +0 -0
  227. pycforge_sdk/gui/visual/resources/icons/24/history.png +0 -0
  228. pycforge_sdk/gui/visual/resources/icons/24/indent.png +0 -0
  229. pycforge_sdk/gui/visual/resources/icons/24/link-c.png +0 -0
  230. pycforge_sdk/gui/visual/resources/icons/24/mappings.png +0 -0
  231. pycforge_sdk/gui/visual/resources/icons/24/module.png +0 -0
  232. pycforge_sdk/gui/visual/resources/icons/24/move-down.png +0 -0
  233. pycforge_sdk/gui/visual/resources/icons/24/move-line-down.png +0 -0
  234. pycforge_sdk/gui/visual/resources/icons/24/move-line-up.png +0 -0
  235. pycforge_sdk/gui/visual/resources/icons/24/move-up.png +0 -0
  236. pycforge_sdk/gui/visual/resources/icons/24/next.png +0 -0
  237. pycforge_sdk/gui/visual/resources/icons/24/open.png +0 -0
  238. pycforge_sdk/gui/visual/resources/icons/24/outdent.png +0 -0
  239. pycforge_sdk/gui/visual/resources/icons/24/outline.png +0 -0
  240. pycforge_sdk/gui/visual/resources/icons/24/paste.png +0 -0
  241. pycforge_sdk/gui/visual/resources/icons/24/previous.png +0 -0
  242. pycforge_sdk/gui/visual/resources/icons/24/primary-module.png +0 -0
  243. pycforge_sdk/gui/visual/resources/icons/24/redo.png +0 -0
  244. pycforge_sdk/gui/visual/resources/icons/24/remove-document.png +0 -0
  245. pycforge_sdk/gui/visual/resources/icons/24/replace.png +0 -0
  246. pycforge_sdk/gui/visual/resources/icons/24/save-as.png +0 -0
  247. pycforge_sdk/gui/visual/resources/icons/24/save.png +0 -0
  248. pycforge_sdk/gui/visual/resources/icons/24/select-all.png +0 -0
  249. pycforge_sdk/gui/visual/resources/icons/24/settings.png +0 -0
  250. pycforge_sdk/gui/visual/resources/icons/24/show-c.png +0 -0
  251. pycforge_sdk/gui/visual/resources/icons/24/split-view.png +0 -0
  252. pycforge_sdk/gui/visual/resources/icons/24/summary.png +0 -0
  253. pycforge_sdk/gui/visual/resources/icons/24/telemetry.png +0 -0
  254. pycforge_sdk/gui/visual/resources/icons/24/toggle-comment.png +0 -0
  255. pycforge_sdk/gui/visual/resources/icons/24/toggle-fold.png +0 -0
  256. pycforge_sdk/gui/visual/resources/icons/24/tools.png +0 -0
  257. pycforge_sdk/gui/visual/resources/icons/24/undo.png +0 -0
  258. pycforge_sdk/gui/visual/resources/icons/24/whitespace.png +0 -0
  259. pycforge_sdk/gui/visual/resources/icons/256/add-document.png +0 -0
  260. pycforge_sdk/gui/visual/resources/icons/256/brand-mark.png +0 -0
  261. pycforge_sdk/gui/visual/resources/icons/256/bundle-search.png +0 -0
  262. pycforge_sdk/gui/visual/resources/icons/256/cancel.png +0 -0
  263. pycforge_sdk/gui/visual/resources/icons/256/check.png +0 -0
  264. pycforge_sdk/gui/visual/resources/icons/256/chevron-right.png +0 -0
  265. pycforge_sdk/gui/visual/resources/icons/256/close.png +0 -0
  266. pycforge_sdk/gui/visual/resources/icons/256/collapse-all.png +0 -0
  267. pycforge_sdk/gui/visual/resources/icons/256/command-palette.png +0 -0
  268. pycforge_sdk/gui/visual/resources/icons/256/convert.png +0 -0
  269. pycforge_sdk/gui/visual/resources/icons/256/copy.png +0 -0
  270. pycforge_sdk/gui/visual/resources/icons/256/cut.png +0 -0
  271. pycforge_sdk/gui/visual/resources/icons/256/decision-trace.png +0 -0
  272. pycforge_sdk/gui/visual/resources/icons/256/details.png +0 -0
  273. pycforge_sdk/gui/visual/resources/icons/256/diagnostics.png +0 -0
  274. pycforge_sdk/gui/visual/resources/icons/256/duplicate-line.png +0 -0
  275. pycforge_sdk/gui/visual/resources/icons/256/exit.png +0 -0
  276. pycforge_sdk/gui/visual/resources/icons/256/expand-all.png +0 -0
  277. pycforge_sdk/gui/visual/resources/icons/256/export.png +0 -0
  278. pycforge_sdk/gui/visual/resources/icons/256/find.png +0 -0
  279. pycforge_sdk/gui/visual/resources/icons/256/go-to-line.png +0 -0
  280. pycforge_sdk/gui/visual/resources/icons/256/go-to-output.png +0 -0
  281. pycforge_sdk/gui/visual/resources/icons/256/go-to-source.png +0 -0
  282. pycforge_sdk/gui/visual/resources/icons/256/help.png +0 -0
  283. pycforge_sdk/gui/visual/resources/icons/256/history.png +0 -0
  284. pycforge_sdk/gui/visual/resources/icons/256/indent.png +0 -0
  285. pycforge_sdk/gui/visual/resources/icons/256/link-c.png +0 -0
  286. pycforge_sdk/gui/visual/resources/icons/256/mappings.png +0 -0
  287. pycforge_sdk/gui/visual/resources/icons/256/module.png +0 -0
  288. pycforge_sdk/gui/visual/resources/icons/256/move-down.png +0 -0
  289. pycforge_sdk/gui/visual/resources/icons/256/move-line-down.png +0 -0
  290. pycforge_sdk/gui/visual/resources/icons/256/move-line-up.png +0 -0
  291. pycforge_sdk/gui/visual/resources/icons/256/move-up.png +0 -0
  292. pycforge_sdk/gui/visual/resources/icons/256/next.png +0 -0
  293. pycforge_sdk/gui/visual/resources/icons/256/open.png +0 -0
  294. pycforge_sdk/gui/visual/resources/icons/256/outdent.png +0 -0
  295. pycforge_sdk/gui/visual/resources/icons/256/outline.png +0 -0
  296. pycforge_sdk/gui/visual/resources/icons/256/paste.png +0 -0
  297. pycforge_sdk/gui/visual/resources/icons/256/previous.png +0 -0
  298. pycforge_sdk/gui/visual/resources/icons/256/primary-module.png +0 -0
  299. pycforge_sdk/gui/visual/resources/icons/256/redo.png +0 -0
  300. pycforge_sdk/gui/visual/resources/icons/256/remove-document.png +0 -0
  301. pycforge_sdk/gui/visual/resources/icons/256/replace.png +0 -0
  302. pycforge_sdk/gui/visual/resources/icons/256/save-as.png +0 -0
  303. pycforge_sdk/gui/visual/resources/icons/256/save.png +0 -0
  304. pycforge_sdk/gui/visual/resources/icons/256/select-all.png +0 -0
  305. pycforge_sdk/gui/visual/resources/icons/256/settings.png +0 -0
  306. pycforge_sdk/gui/visual/resources/icons/256/show-c.png +0 -0
  307. pycforge_sdk/gui/visual/resources/icons/256/split-view.png +0 -0
  308. pycforge_sdk/gui/visual/resources/icons/256/summary.png +0 -0
  309. pycforge_sdk/gui/visual/resources/icons/256/telemetry.png +0 -0
  310. pycforge_sdk/gui/visual/resources/icons/256/toggle-comment.png +0 -0
  311. pycforge_sdk/gui/visual/resources/icons/256/toggle-fold.png +0 -0
  312. pycforge_sdk/gui/visual/resources/icons/256/tools.png +0 -0
  313. pycforge_sdk/gui/visual/resources/icons/256/undo.png +0 -0
  314. pycforge_sdk/gui/visual/resources/icons/256/whitespace.png +0 -0
  315. pycforge_sdk/gui/visual/resources/icons/32/add-document.png +0 -0
  316. pycforge_sdk/gui/visual/resources/icons/32/brand-mark.png +0 -0
  317. pycforge_sdk/gui/visual/resources/icons/32/bundle-search.png +0 -0
  318. pycforge_sdk/gui/visual/resources/icons/32/cancel.png +0 -0
  319. pycforge_sdk/gui/visual/resources/icons/32/check.png +0 -0
  320. pycforge_sdk/gui/visual/resources/icons/32/chevron-right.png +0 -0
  321. pycforge_sdk/gui/visual/resources/icons/32/close.png +0 -0
  322. pycforge_sdk/gui/visual/resources/icons/32/collapse-all.png +0 -0
  323. pycforge_sdk/gui/visual/resources/icons/32/command-palette.png +0 -0
  324. pycforge_sdk/gui/visual/resources/icons/32/convert.png +0 -0
  325. pycforge_sdk/gui/visual/resources/icons/32/copy.png +0 -0
  326. pycforge_sdk/gui/visual/resources/icons/32/cut.png +0 -0
  327. pycforge_sdk/gui/visual/resources/icons/32/decision-trace.png +0 -0
  328. pycforge_sdk/gui/visual/resources/icons/32/details.png +0 -0
  329. pycforge_sdk/gui/visual/resources/icons/32/diagnostics.png +0 -0
  330. pycforge_sdk/gui/visual/resources/icons/32/duplicate-line.png +0 -0
  331. pycforge_sdk/gui/visual/resources/icons/32/exit.png +0 -0
  332. pycforge_sdk/gui/visual/resources/icons/32/expand-all.png +0 -0
  333. pycforge_sdk/gui/visual/resources/icons/32/export.png +0 -0
  334. pycforge_sdk/gui/visual/resources/icons/32/find.png +0 -0
  335. pycforge_sdk/gui/visual/resources/icons/32/go-to-line.png +0 -0
  336. pycforge_sdk/gui/visual/resources/icons/32/go-to-output.png +0 -0
  337. pycforge_sdk/gui/visual/resources/icons/32/go-to-source.png +0 -0
  338. pycforge_sdk/gui/visual/resources/icons/32/help.png +0 -0
  339. pycforge_sdk/gui/visual/resources/icons/32/history.png +0 -0
  340. pycforge_sdk/gui/visual/resources/icons/32/indent.png +0 -0
  341. pycforge_sdk/gui/visual/resources/icons/32/link-c.png +0 -0
  342. pycforge_sdk/gui/visual/resources/icons/32/mappings.png +0 -0
  343. pycforge_sdk/gui/visual/resources/icons/32/module.png +0 -0
  344. pycforge_sdk/gui/visual/resources/icons/32/move-down.png +0 -0
  345. pycforge_sdk/gui/visual/resources/icons/32/move-line-down.png +0 -0
  346. pycforge_sdk/gui/visual/resources/icons/32/move-line-up.png +0 -0
  347. pycforge_sdk/gui/visual/resources/icons/32/move-up.png +0 -0
  348. pycforge_sdk/gui/visual/resources/icons/32/next.png +0 -0
  349. pycforge_sdk/gui/visual/resources/icons/32/open.png +0 -0
  350. pycforge_sdk/gui/visual/resources/icons/32/outdent.png +0 -0
  351. pycforge_sdk/gui/visual/resources/icons/32/outline.png +0 -0
  352. pycforge_sdk/gui/visual/resources/icons/32/paste.png +0 -0
  353. pycforge_sdk/gui/visual/resources/icons/32/previous.png +0 -0
  354. pycforge_sdk/gui/visual/resources/icons/32/primary-module.png +0 -0
  355. pycforge_sdk/gui/visual/resources/icons/32/redo.png +0 -0
  356. pycforge_sdk/gui/visual/resources/icons/32/remove-document.png +0 -0
  357. pycforge_sdk/gui/visual/resources/icons/32/replace.png +0 -0
  358. pycforge_sdk/gui/visual/resources/icons/32/save-as.png +0 -0
  359. pycforge_sdk/gui/visual/resources/icons/32/save.png +0 -0
  360. pycforge_sdk/gui/visual/resources/icons/32/select-all.png +0 -0
  361. pycforge_sdk/gui/visual/resources/icons/32/settings.png +0 -0
  362. pycforge_sdk/gui/visual/resources/icons/32/show-c.png +0 -0
  363. pycforge_sdk/gui/visual/resources/icons/32/split-view.png +0 -0
  364. pycforge_sdk/gui/visual/resources/icons/32/summary.png +0 -0
  365. pycforge_sdk/gui/visual/resources/icons/32/telemetry.png +0 -0
  366. pycforge_sdk/gui/visual/resources/icons/32/toggle-comment.png +0 -0
  367. pycforge_sdk/gui/visual/resources/icons/32/toggle-fold.png +0 -0
  368. pycforge_sdk/gui/visual/resources/icons/32/tools.png +0 -0
  369. pycforge_sdk/gui/visual/resources/icons/32/undo.png +0 -0
  370. pycforge_sdk/gui/visual/resources/icons/32/whitespace.png +0 -0
  371. pycforge_sdk/gui/visual/resources/icons/48/add-document.png +0 -0
  372. pycforge_sdk/gui/visual/resources/icons/48/brand-mark.png +0 -0
  373. pycforge_sdk/gui/visual/resources/icons/48/bundle-search.png +0 -0
  374. pycforge_sdk/gui/visual/resources/icons/48/cancel.png +0 -0
  375. pycforge_sdk/gui/visual/resources/icons/48/check.png +0 -0
  376. pycforge_sdk/gui/visual/resources/icons/48/chevron-right.png +0 -0
  377. pycforge_sdk/gui/visual/resources/icons/48/close.png +0 -0
  378. pycforge_sdk/gui/visual/resources/icons/48/collapse-all.png +0 -0
  379. pycforge_sdk/gui/visual/resources/icons/48/command-palette.png +0 -0
  380. pycforge_sdk/gui/visual/resources/icons/48/convert.png +0 -0
  381. pycforge_sdk/gui/visual/resources/icons/48/copy.png +0 -0
  382. pycforge_sdk/gui/visual/resources/icons/48/cut.png +0 -0
  383. pycforge_sdk/gui/visual/resources/icons/48/decision-trace.png +0 -0
  384. pycforge_sdk/gui/visual/resources/icons/48/details.png +0 -0
  385. pycforge_sdk/gui/visual/resources/icons/48/diagnostics.png +0 -0
  386. pycforge_sdk/gui/visual/resources/icons/48/duplicate-line.png +0 -0
  387. pycforge_sdk/gui/visual/resources/icons/48/exit.png +0 -0
  388. pycforge_sdk/gui/visual/resources/icons/48/expand-all.png +0 -0
  389. pycforge_sdk/gui/visual/resources/icons/48/export.png +0 -0
  390. pycforge_sdk/gui/visual/resources/icons/48/find.png +0 -0
  391. pycforge_sdk/gui/visual/resources/icons/48/go-to-line.png +0 -0
  392. pycforge_sdk/gui/visual/resources/icons/48/go-to-output.png +0 -0
  393. pycforge_sdk/gui/visual/resources/icons/48/go-to-source.png +0 -0
  394. pycforge_sdk/gui/visual/resources/icons/48/help.png +0 -0
  395. pycforge_sdk/gui/visual/resources/icons/48/history.png +0 -0
  396. pycforge_sdk/gui/visual/resources/icons/48/indent.png +0 -0
  397. pycforge_sdk/gui/visual/resources/icons/48/link-c.png +0 -0
  398. pycforge_sdk/gui/visual/resources/icons/48/mappings.png +0 -0
  399. pycforge_sdk/gui/visual/resources/icons/48/module.png +0 -0
  400. pycforge_sdk/gui/visual/resources/icons/48/move-down.png +0 -0
  401. pycforge_sdk/gui/visual/resources/icons/48/move-line-down.png +0 -0
  402. pycforge_sdk/gui/visual/resources/icons/48/move-line-up.png +0 -0
  403. pycforge_sdk/gui/visual/resources/icons/48/move-up.png +0 -0
  404. pycforge_sdk/gui/visual/resources/icons/48/next.png +0 -0
  405. pycforge_sdk/gui/visual/resources/icons/48/open.png +0 -0
  406. pycforge_sdk/gui/visual/resources/icons/48/outdent.png +0 -0
  407. pycforge_sdk/gui/visual/resources/icons/48/outline.png +0 -0
  408. pycforge_sdk/gui/visual/resources/icons/48/paste.png +0 -0
  409. pycforge_sdk/gui/visual/resources/icons/48/previous.png +0 -0
  410. pycforge_sdk/gui/visual/resources/icons/48/primary-module.png +0 -0
  411. pycforge_sdk/gui/visual/resources/icons/48/redo.png +0 -0
  412. pycforge_sdk/gui/visual/resources/icons/48/remove-document.png +0 -0
  413. pycforge_sdk/gui/visual/resources/icons/48/replace.png +0 -0
  414. pycforge_sdk/gui/visual/resources/icons/48/save-as.png +0 -0
  415. pycforge_sdk/gui/visual/resources/icons/48/save.png +0 -0
  416. pycforge_sdk/gui/visual/resources/icons/48/select-all.png +0 -0
  417. pycforge_sdk/gui/visual/resources/icons/48/settings.png +0 -0
  418. pycforge_sdk/gui/visual/resources/icons/48/show-c.png +0 -0
  419. pycforge_sdk/gui/visual/resources/icons/48/split-view.png +0 -0
  420. pycforge_sdk/gui/visual/resources/icons/48/summary.png +0 -0
  421. pycforge_sdk/gui/visual/resources/icons/48/telemetry.png +0 -0
  422. pycforge_sdk/gui/visual/resources/icons/48/toggle-comment.png +0 -0
  423. pycforge_sdk/gui/visual/resources/icons/48/toggle-fold.png +0 -0
  424. pycforge_sdk/gui/visual/resources/icons/48/tools.png +0 -0
  425. pycforge_sdk/gui/visual/resources/icons/48/undo.png +0 -0
  426. pycforge_sdk/gui/visual/resources/icons/48/whitespace.png +0 -0
  427. pycforge_sdk/gui/visual/resources/icons/64/add-document.png +0 -0
  428. pycforge_sdk/gui/visual/resources/icons/64/brand-mark.png +0 -0
  429. pycforge_sdk/gui/visual/resources/icons/64/bundle-search.png +0 -0
  430. pycforge_sdk/gui/visual/resources/icons/64/cancel.png +0 -0
  431. pycforge_sdk/gui/visual/resources/icons/64/check.png +0 -0
  432. pycforge_sdk/gui/visual/resources/icons/64/chevron-right.png +0 -0
  433. pycforge_sdk/gui/visual/resources/icons/64/close.png +0 -0
  434. pycforge_sdk/gui/visual/resources/icons/64/collapse-all.png +0 -0
  435. pycforge_sdk/gui/visual/resources/icons/64/command-palette.png +0 -0
  436. pycforge_sdk/gui/visual/resources/icons/64/convert.png +0 -0
  437. pycforge_sdk/gui/visual/resources/icons/64/copy.png +0 -0
  438. pycforge_sdk/gui/visual/resources/icons/64/cut.png +0 -0
  439. pycforge_sdk/gui/visual/resources/icons/64/decision-trace.png +0 -0
  440. pycforge_sdk/gui/visual/resources/icons/64/details.png +0 -0
  441. pycforge_sdk/gui/visual/resources/icons/64/diagnostics.png +0 -0
  442. pycforge_sdk/gui/visual/resources/icons/64/duplicate-line.png +0 -0
  443. pycforge_sdk/gui/visual/resources/icons/64/exit.png +0 -0
  444. pycforge_sdk/gui/visual/resources/icons/64/expand-all.png +0 -0
  445. pycforge_sdk/gui/visual/resources/icons/64/export.png +0 -0
  446. pycforge_sdk/gui/visual/resources/icons/64/find.png +0 -0
  447. pycforge_sdk/gui/visual/resources/icons/64/go-to-line.png +0 -0
  448. pycforge_sdk/gui/visual/resources/icons/64/go-to-output.png +0 -0
  449. pycforge_sdk/gui/visual/resources/icons/64/go-to-source.png +0 -0
  450. pycforge_sdk/gui/visual/resources/icons/64/help.png +0 -0
  451. pycforge_sdk/gui/visual/resources/icons/64/history.png +0 -0
  452. pycforge_sdk/gui/visual/resources/icons/64/indent.png +0 -0
  453. pycforge_sdk/gui/visual/resources/icons/64/link-c.png +0 -0
  454. pycforge_sdk/gui/visual/resources/icons/64/mappings.png +0 -0
  455. pycforge_sdk/gui/visual/resources/icons/64/module.png +0 -0
  456. pycforge_sdk/gui/visual/resources/icons/64/move-down.png +0 -0
  457. pycforge_sdk/gui/visual/resources/icons/64/move-line-down.png +0 -0
  458. pycforge_sdk/gui/visual/resources/icons/64/move-line-up.png +0 -0
  459. pycforge_sdk/gui/visual/resources/icons/64/move-up.png +0 -0
  460. pycforge_sdk/gui/visual/resources/icons/64/next.png +0 -0
  461. pycforge_sdk/gui/visual/resources/icons/64/open.png +0 -0
  462. pycforge_sdk/gui/visual/resources/icons/64/outdent.png +0 -0
  463. pycforge_sdk/gui/visual/resources/icons/64/outline.png +0 -0
  464. pycforge_sdk/gui/visual/resources/icons/64/paste.png +0 -0
  465. pycforge_sdk/gui/visual/resources/icons/64/previous.png +0 -0
  466. pycforge_sdk/gui/visual/resources/icons/64/primary-module.png +0 -0
  467. pycforge_sdk/gui/visual/resources/icons/64/redo.png +0 -0
  468. pycforge_sdk/gui/visual/resources/icons/64/remove-document.png +0 -0
  469. pycforge_sdk/gui/visual/resources/icons/64/replace.png +0 -0
  470. pycforge_sdk/gui/visual/resources/icons/64/save-as.png +0 -0
  471. pycforge_sdk/gui/visual/resources/icons/64/save.png +0 -0
  472. pycforge_sdk/gui/visual/resources/icons/64/select-all.png +0 -0
  473. pycforge_sdk/gui/visual/resources/icons/64/settings.png +0 -0
  474. pycforge_sdk/gui/visual/resources/icons/64/show-c.png +0 -0
  475. pycforge_sdk/gui/visual/resources/icons/64/split-view.png +0 -0
  476. pycforge_sdk/gui/visual/resources/icons/64/summary.png +0 -0
  477. pycforge_sdk/gui/visual/resources/icons/64/telemetry.png +0 -0
  478. pycforge_sdk/gui/visual/resources/icons/64/toggle-comment.png +0 -0
  479. pycforge_sdk/gui/visual/resources/icons/64/toggle-fold.png +0 -0
  480. pycforge_sdk/gui/visual/resources/icons/64/tools.png +0 -0
  481. pycforge_sdk/gui/visual/resources/icons/64/undo.png +0 -0
  482. pycforge_sdk/gui/visual/resources/icons/64/whitespace.png +0 -0
  483. pycforge_sdk/gui/visual/resources/icons/96/add-document.png +0 -0
  484. pycforge_sdk/gui/visual/resources/icons/96/brand-mark.png +0 -0
  485. pycforge_sdk/gui/visual/resources/icons/96/bundle-search.png +0 -0
  486. pycforge_sdk/gui/visual/resources/icons/96/cancel.png +0 -0
  487. pycforge_sdk/gui/visual/resources/icons/96/check.png +0 -0
  488. pycforge_sdk/gui/visual/resources/icons/96/chevron-right.png +0 -0
  489. pycforge_sdk/gui/visual/resources/icons/96/close.png +0 -0
  490. pycforge_sdk/gui/visual/resources/icons/96/collapse-all.png +0 -0
  491. pycforge_sdk/gui/visual/resources/icons/96/command-palette.png +0 -0
  492. pycforge_sdk/gui/visual/resources/icons/96/convert.png +0 -0
  493. pycforge_sdk/gui/visual/resources/icons/96/copy.png +0 -0
  494. pycforge_sdk/gui/visual/resources/icons/96/cut.png +0 -0
  495. pycforge_sdk/gui/visual/resources/icons/96/decision-trace.png +0 -0
  496. pycforge_sdk/gui/visual/resources/icons/96/details.png +0 -0
  497. pycforge_sdk/gui/visual/resources/icons/96/diagnostics.png +0 -0
  498. pycforge_sdk/gui/visual/resources/icons/96/duplicate-line.png +0 -0
  499. pycforge_sdk/gui/visual/resources/icons/96/exit.png +0 -0
  500. pycforge_sdk/gui/visual/resources/icons/96/expand-all.png +0 -0
  501. pycforge_sdk/gui/visual/resources/icons/96/export.png +0 -0
  502. pycforge_sdk/gui/visual/resources/icons/96/find.png +0 -0
  503. pycforge_sdk/gui/visual/resources/icons/96/go-to-line.png +0 -0
  504. pycforge_sdk/gui/visual/resources/icons/96/go-to-output.png +0 -0
  505. pycforge_sdk/gui/visual/resources/icons/96/go-to-source.png +0 -0
  506. pycforge_sdk/gui/visual/resources/icons/96/help.png +0 -0
  507. pycforge_sdk/gui/visual/resources/icons/96/history.png +0 -0
  508. pycforge_sdk/gui/visual/resources/icons/96/indent.png +0 -0
  509. pycforge_sdk/gui/visual/resources/icons/96/link-c.png +0 -0
  510. pycforge_sdk/gui/visual/resources/icons/96/mappings.png +0 -0
  511. pycforge_sdk/gui/visual/resources/icons/96/module.png +0 -0
  512. pycforge_sdk/gui/visual/resources/icons/96/move-down.png +0 -0
  513. pycforge_sdk/gui/visual/resources/icons/96/move-line-down.png +0 -0
  514. pycforge_sdk/gui/visual/resources/icons/96/move-line-up.png +0 -0
  515. pycforge_sdk/gui/visual/resources/icons/96/move-up.png +0 -0
  516. pycforge_sdk/gui/visual/resources/icons/96/next.png +0 -0
  517. pycforge_sdk/gui/visual/resources/icons/96/open.png +0 -0
  518. pycforge_sdk/gui/visual/resources/icons/96/outdent.png +0 -0
  519. pycforge_sdk/gui/visual/resources/icons/96/outline.png +0 -0
  520. pycforge_sdk/gui/visual/resources/icons/96/paste.png +0 -0
  521. pycforge_sdk/gui/visual/resources/icons/96/previous.png +0 -0
  522. pycforge_sdk/gui/visual/resources/icons/96/primary-module.png +0 -0
  523. pycforge_sdk/gui/visual/resources/icons/96/redo.png +0 -0
  524. pycforge_sdk/gui/visual/resources/icons/96/remove-document.png +0 -0
  525. pycforge_sdk/gui/visual/resources/icons/96/replace.png +0 -0
  526. pycforge_sdk/gui/visual/resources/icons/96/save-as.png +0 -0
  527. pycforge_sdk/gui/visual/resources/icons/96/save.png +0 -0
  528. pycforge_sdk/gui/visual/resources/icons/96/select-all.png +0 -0
  529. pycforge_sdk/gui/visual/resources/icons/96/settings.png +0 -0
  530. pycforge_sdk/gui/visual/resources/icons/96/show-c.png +0 -0
  531. pycforge_sdk/gui/visual/resources/icons/96/split-view.png +0 -0
  532. pycforge_sdk/gui/visual/resources/icons/96/summary.png +0 -0
  533. pycforge_sdk/gui/visual/resources/icons/96/telemetry.png +0 -0
  534. pycforge_sdk/gui/visual/resources/icons/96/toggle-comment.png +0 -0
  535. pycforge_sdk/gui/visual/resources/icons/96/toggle-fold.png +0 -0
  536. pycforge_sdk/gui/visual/resources/icons/96/tools.png +0 -0
  537. pycforge_sdk/gui/visual/resources/icons/96/undo.png +0 -0
  538. pycforge_sdk/gui/visual/resources/icons/96/whitespace.png +0 -0
  539. pycforge_sdk/gui/visual/theme.py +204 -0
  540. pycforge_sdk/gui/visual/theme_steel_stylesheet.py +901 -0
  541. pycforge_sdk/gui/visual/theme_stylesheet.py +597 -0
  542. pycforge_sdk/gui/visual/theme_workspace_stylesheet.py +169 -0
  543. pycforge_sdk/gui/visual/visual_tokens.py +146 -0
  544. pycforge_sdk/gui/widgets.py +68 -0
  545. pycforge_sdk/gui/window.py +559 -0
  546. pycforge_sdk/native.py +42 -0
  547. pycforge_sdk/package_metadata.py +21 -0
  548. pycforge_sdk/process.py +58 -0
  549. pycforge_sdk/project.py +143 -0
  550. pycforge_sdk/readiness.py +106 -0
  551. pycforge_sdk/results.py +45 -0
  552. pycforge_sdk/service.py +454 -0
  553. pycforge_sdk/workbench.py +88 -0
  554. pycforge_sdk-0.6.3.dist-info/METADATA +221 -0
  555. pycforge_sdk-0.6.3.dist-info/RECORD +559 -0
  556. pycforge_sdk-0.6.3.dist-info/WHEEL +5 -0
  557. pycforge_sdk-0.6.3.dist-info/entry_points.txt +5 -0
  558. pycforge_sdk-0.6.3.dist-info/licenses/LICENSE +674 -0
  559. pycforge_sdk-0.6.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,412 @@
1
+ """Explained project forms. Engine reference data supplies operation choices."""
2
+ import copy
3
+ import json
4
+ from PySide6.QtCore import Signal, Qt
5
+ from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QFormLayout,
6
+ QTabWidget, QScrollArea, QLineEdit, QPlainTextEdit, QComboBox, QSpinBox,
7
+ QGroupBox, QListWidget, QSplitter, QDialog, QCheckBox)
8
+ from ..project import parse
9
+ from ..results import SDKError
10
+ from .widgets import label, button
11
+ from .dialogs import Dialog
12
+ from .jobs import JobRunner
13
+
14
+
15
+ class DraftDialog(Dialog):
16
+ close_pending = False
17
+ def reject(self):
18
+ if self.runner.busy:
19
+ self.close_pending = True
20
+ self.runner.cancel()
21
+ self.problem.setText("Canceling draft validation…")
22
+ return
23
+ super().reject()
24
+
25
+ def closeEvent(self, event):
26
+ event.ignore(); self.reject()
27
+
28
+
29
+ def pointer(parts):
30
+ return "/" + "/".join(str(p).replace("~", "~0").replace("/", "~1") for p in parts)
31
+
32
+
33
+ class ProjectEditor(QWidget):
34
+ changed = Signal()
35
+ source_requested = Signal(str)
36
+
37
+ def __init__(self, parent=None):
38
+ super().__init__(parent)
39
+ self.layout = QVBoxLayout(self)
40
+ self.layout.setContentsMargins(0, 0, 0, 0)
41
+ self.tabs = QTabWidget()
42
+ self.layout.addWidget(self.tabs)
43
+ self.fields = {}
44
+ self.draft = None
45
+ self.methods, self.operations = [], []
46
+ self.workbench = None
47
+
48
+ def load(self, document, *, methods=(), operations=(), workbench=None):
49
+ self.draft = copy.deepcopy(document)
50
+ self.methods, self.operations = methods, operations
51
+ self.workbench = workbench
52
+ self.fields = {}
53
+ while self.tabs.count():
54
+ page = self.tabs.widget(0); self.tabs.removeTab(0); page.deleteLater()
55
+ self.project_page()
56
+ self.function_page()
57
+ self.help_page()
58
+ self.fixtures_page()
59
+
60
+ def page(self, title, description):
61
+ body = QWidget(); layout = QVBoxLayout(body)
62
+ layout.addWidget(label(description, muted=True))
63
+ scroll = QScrollArea(); scroll.setWidgetResizable(True); scroll.setWidget(body)
64
+ self.tabs.addTab(scroll, title)
65
+ return layout, scroll
66
+
67
+ def get(self, parts):
68
+ value = self.draft
69
+ for part in parts: value = value[part]
70
+ return value
71
+
72
+ def put(self, parts, value):
73
+ target = self.draft
74
+ for part in parts[:-1]: target = target[part]
75
+ target[parts[-1]] = value
76
+ self.changed.emit()
77
+
78
+ def field(self, form, title, parts, description="", *, choices=None, multiline=False, page=None):
79
+ value = self.get(parts)
80
+ if choices:
81
+ edit = QComboBox()
82
+ for choice in choices: edit.addItem(str(choice), choice)
83
+ index = next((i for i in range(edit.count()) if type(edit.itemData(i)) is type(value) and edit.itemData(i) == value), -1)
84
+ if index < 0: edit.addItem(str(value), value); index = edit.count()-1
85
+ edit.setCurrentIndex(index)
86
+ edit.currentIndexChanged.connect(lambda _i: self.put(parts, edit.currentData()))
87
+ elif type(value) is int:
88
+ edit = QSpinBox(); edit.setRange(-2147483647, 2147483647); edit.setValue(value)
89
+ edit.valueChanged.connect(lambda v: self.put(parts, v))
90
+ elif multiline:
91
+ edit = QPlainTextEdit(str(value)); edit.setMinimumHeight(86); edit.setMaximumHeight(150)
92
+ edit.textChanged.connect(lambda: self.put(parts, edit.toPlainText()))
93
+ else:
94
+ edit = QLineEdit(str(value))
95
+ edit.textChanged.connect(lambda v: self.put(parts, v))
96
+ edit.setAccessibleName(title)
97
+ edit.setAccessibleDescription(description)
98
+ edit.setToolTip(description)
99
+ caption = label(title); caption.setBuddy(edit)
100
+ form.addRow(caption, edit)
101
+ if description:
102
+ hint = label(description, muted=True)
103
+ form.addRow("", hint)
104
+ self.fields[pointer(parts)] = (edit, page)
105
+ return edit
106
+
107
+ def reference(self, name):
108
+ return next((e for e in self.methods if e["id"].endswith("." + name)), {})
109
+
110
+ def profile(self):
111
+ schema = self.draft.get("declaration", {}).get("schema")
112
+ return next((p for p in (self.workbench or {}).get("profiles", []) if p["declaration_schema"] == schema), None)
113
+
114
+ def engine_field(self, form, definition, parts, page):
115
+ """Render inert field metadata; never import a renderer from the engine."""
116
+ title, kind = definition["title"], definition["kind"]
117
+ description = definition.get("description", "")
118
+ value = self.get(parts)
119
+ if kind == "boolean" and type(value) is bool:
120
+ control = QCheckBox(title); control.setChecked(value)
121
+ control.toggled.connect(lambda checked: self.put(parts, checked))
122
+ form.addRow(control)
123
+ elif kind == "json" or (kind != "choice" and type(value) is not str):
124
+ control = button("Edit value…", "details", lambda: self.edit_value(parts, title, control))
125
+ control.setToolTip(json.dumps(value, ensure_ascii=False))
126
+ form.addRow(label(title), control)
127
+ else:
128
+ options = definition.get("options", [])
129
+ control = self.field(form, title, parts, description,
130
+ choices=[o["value"] for o in options] if options else None,
131
+ multiline=kind == "multiline", page=page)
132
+ if isinstance(control, QComboBox):
133
+ for row in range(control.count()):
134
+ option = next((o for o in options if o["value"] == control.itemData(row)), None)
135
+ if option:
136
+ control.setItemText(row, option["title"])
137
+ control.setItemData(row, option.get("description", ""), Qt.ItemDataRole.ToolTipRole)
138
+ return control
139
+ control.setAccessibleName(title); control.setAccessibleDescription(description)
140
+ if description: form.addRow("", label(description, muted=True))
141
+ self.fields[pointer(parts)] = (control, page)
142
+ return control
143
+
144
+ def edit_value(self, parts, title, control):
145
+ dlg = Dialog(title, self)
146
+ dlg.body.addWidget(label("Edit this value as JSON. The connected engine validates its conversion meaning when you scan."))
147
+ source = QPlainTextEdit(json.dumps(self.get(parts), indent=2)); source.setAccessibleName(title)
148
+ dlg.body.addWidget(source, 1); problem = label(""); dlg.body.addWidget(problem)
149
+ def apply():
150
+ try:
151
+ if len(source.toPlainText().encode('utf-8')) > 256 * 1024:
152
+ raise SDKError("SDK_LIMIT", "The value exceeds the editor size budget.")
153
+ value = parse(source.toPlainText())
154
+ except SDKError as exc:
155
+ problem.setText(str(exc)); return
156
+ self.put(parts, value); control.setToolTip(json.dumps(value, ensure_ascii=False)); dlg.accept()
157
+ row = QHBoxLayout(); row.addWidget(button("Apply", "check", apply)); row.addWidget(button("Cancel", "cancel", dlg.reject))
158
+ dlg.body.addLayout(row); dlg.resize(650, 440); dlg.exec()
159
+
160
+ def project_page(self):
161
+ layout, page = self.page("Project", "Give this conversion extension a clear identity. Changing any saved field requires fresh verification.")
162
+ form = QFormLayout(); layout.addLayout(form)
163
+ descriptions = {
164
+ "package_id": "Stable package identity, for example org.example.vectors.",
165
+ "namespace": "The name used in the editor after *import.",
166
+ "version": "The version you intend to package. Publishing remains your separate decision.",
167
+ "author": "The person or organization responsible for this extension.",
168
+ "description": "A short explanation of what this extension provides.",
169
+ "created": "Creation date recorded in the package metadata.", "license": "The license for your extension."}
170
+ profile = self.profile()
171
+ if profile:
172
+ for definition in profile["fields"]:
173
+ key = definition["name"]
174
+ if key in self.draft.get("declaration", {}):
175
+ self.engine_field(form, definition, ["declaration", key], page)
176
+ else:
177
+ for key in ("package_id", "namespace", "version"):
178
+ if key in self.draft.get("declaration", {}):
179
+ self.field(form, key.replace("_", " ").title(), ["declaration", key], descriptions[key], page=page)
180
+ for key in ("author", "description", "created", "license"):
181
+ self.field(form, key.title(), ["metadata", key], descriptions[key], multiline=key=="description", page=page)
182
+ layout.addWidget(button("Advanced project data…", "details", self.advanced,
183
+ "Edit the complete JSON project. Keep normal work in the explained forms."))
184
+ layout.addStretch()
185
+
186
+ def function_page(self):
187
+ layout, page = self.page("Functions", "Choose a function to explain its conversion contract. The connected engine defines the available operations.")
188
+ self.function_choice = QComboBox()
189
+ for f in self.draft.get("declaration", {}).get("functions", []):
190
+ self.function_choice.addItem(f.get("export", "Unnamed function"))
191
+ self.function_choice.setAccessibleName("Function")
192
+ layout.addWidget(self.function_choice)
193
+ self.function_holder = QWidget(); self.function_layout = QVBoxLayout(self.function_holder)
194
+ self.function_layout.setContentsMargins(0, 0, 0, 0)
195
+ layout.addWidget(self.function_holder); layout.addStretch()
196
+ self.function_tab = page
197
+ self.function_choice.currentIndexChanged.connect(self.show_function)
198
+ self.show_function(0)
199
+
200
+ def clear(self, layout, prefix):
201
+ for key in list(self.fields):
202
+ if key.startswith(prefix): del self.fields[key]
203
+ while layout.count():
204
+ item = layout.takeAt(0)
205
+ if item.widget(): item.widget().hide(); item.widget().deleteLater()
206
+
207
+ def show_function(self, index):
208
+ self.clear(self.function_layout, "/declaration/functions/")
209
+ functions = self.draft.get("declaration", {}).get("functions", [])
210
+ if not 0 <= index < len(functions): return
211
+ function = functions[index]
212
+ if self.workbench is not None:
213
+ self.show_engine_function(index, function)
214
+ return
215
+ array = self.draft["declaration"].get("schema", "").startswith("crucible.array-")
216
+ ref = self.reference("ArrayFunction" if array else "ScalarFunction")
217
+ params = {p["name"]: p for p in ref.get("parameters", [])}
218
+ body = QWidget(); form = QFormLayout(body); self.function_layout.addWidget(body)
219
+ for key in ("operation_id", "export", "operation", "summary") if array else ("operation_id", "export", "native_symbol", "summary"):
220
+ if key not in function: continue
221
+ choices = [o["id"] for o in self.operations] if key == "operation" else None
222
+ control = self.field(form, {"operation_id": "Stable identity", "export": "Editor name", "operation": "Operation", "native_symbol": "Native symbol", "summary": "Summary"}[key],
223
+ ["declaration", "functions", index, key], params.get(key, {}).get("description", ""),
224
+ choices=choices, multiline=key=="summary", page=self.function_tab)
225
+ if key == "summary": control.setMaximumHeight(96)
226
+ if key == "operation" and isinstance(control, QComboBox):
227
+ for row in range(control.count()):
228
+ choice = next((o for o in self.operations if o["id"] == control.itemData(row)), None)
229
+ if choice: control.setItemText(row, choice["title"])
230
+ if array:
231
+ self.contract = label("")
232
+ self.function_layout.addWidget(self.contract)
233
+ def explain():
234
+ value = function.get("operation")
235
+ operation = next((o for o in self.operations if o["id"] == value), {})
236
+ signature = operation.get("signature", "").replace("function(", function.get("export", "function") + "(", 1)
237
+ self.contract.setText(signature + "\n" + operation.get("description", "") +
238
+ "\nThe engine owns array type, storage and cleanup.")
239
+ field = self.fields.get(pointer(["declaration", "functions", index, "operation"]))
240
+ if field and isinstance(field[0], QComboBox): field[0].currentIndexChanged.connect(explain)
241
+ explain()
242
+ else:
243
+ advanced = QGroupBox("More contract settings")
244
+ advanced.setCheckable(True); advanced.setChecked(False)
245
+ outer = QVBoxLayout(advanced); details = QWidget(); detail_form = QFormLayout(details)
246
+ outer.addWidget(details); details.setVisible(False); advanced.toggled.connect(details.setVisible)
247
+ for key, value in function.items():
248
+ if key in ("operation_id", "export", "native_symbol", "summary"): continue
249
+ if isinstance(value, (dict, list)):
250
+ detail_form.addRow(label(key.title() + ": " + json.dumps(value)),
251
+ button("Edit data…", "details", self.advanced))
252
+ else:
253
+ self.field(detail_form, key.replace("_", " ").title(), ["declaration", "functions", index, key],
254
+ params.get(key, {}).get("description", ""), choices=params.get(key, {}).get("choices"), page=self.function_tab)
255
+ self.function_layout.addWidget(advanced)
256
+
257
+ def show_engine_function(self, index, function):
258
+ profile = self.profile()
259
+ if profile is None:
260
+ self.function_layout.addWidget(label("The engine does not advertise a form for this declaration. Use Advanced project data, then Scan to check it."))
261
+ return
262
+ self.function_layout.addWidget(label(profile.get("description", ""), muted=True))
263
+ body = QWidget(); form = QFormLayout(body); self.function_layout.addWidget(body)
264
+ advanced = QGroupBox("More contract settings"); advanced.setCheckable(True); advanced.setChecked(False)
265
+ outer = QVBoxLayout(advanced); details = QWidget(); detail_form = QFormLayout(details)
266
+ outer.addWidget(details); details.hide(); advanced.toggled.connect(details.setVisible)
267
+ has_advanced = False
268
+ for definition in profile["function_fields"]:
269
+ key = definition["name"]
270
+ if key not in function: continue
271
+ is_advanced = definition.get("advanced", False)
272
+ has_advanced |= is_advanced
273
+ self.engine_field(detail_form if is_advanced else form, definition,
274
+ ["declaration", "functions", index, key], self.function_tab)
275
+ if has_advanced: self.function_layout.addWidget(advanced)
276
+ else: advanced.deleteLater()
277
+ self.contract = label(""); self.function_layout.addWidget(self.contract)
278
+ operation_field = profile.get("operation_field", "")
279
+ definition = next((f for f in profile["function_fields"] if f["name"] == operation_field), {})
280
+ def explain():
281
+ option = next((o for o in definition.get("options", []) if o["value"] == function.get(operation_field)), {})
282
+ signature = option.get("signature", "").replace("function(", function.get("export", "function") + "(", 1)
283
+ self.contract.setText("\n".join(part for part in (signature, option.get("description", ""), profile.get("contract_note", "")) if part))
284
+ selected = self.fields.get(pointer(["declaration", "functions", index, operation_field]))
285
+ if selected and isinstance(selected[0], QComboBox): selected[0].currentIndexChanged.connect(explain)
286
+ explain()
287
+
288
+ def help_page(self):
289
+ layout, page = self.page("Help", "Write the offline manual that ships inside the extension. Scanner findings take you directly to unfinished fields.")
290
+ self.help_tab = page
291
+ doc = self.draft.get("documentation")
292
+ if not isinstance(doc, dict):
293
+ layout.addWidget(label("This project needs Help fields. Choose Tools → Add missing Help fields, then fill in your explanations.")); return
294
+ form = QFormLayout(); layout.addLayout(form)
295
+ for key in ("overview", "usage", "limitations", "release_notes"):
296
+ if key in doc:
297
+ self.field(form, key.replace("_", " ").title(), ["documentation", key], multiline=True, page=page)
298
+ self.help_choice = QComboBox()
299
+ for name in doc.get("functions", {}): self.help_choice.addItem(name)
300
+ self.help_choice.setAccessibleName("Documented function")
301
+ layout.addWidget(label("Function explanations")); layout.addWidget(self.help_choice)
302
+ self.help_holder = QWidget(); self.help_layout = QVBoxLayout(self.help_holder)
303
+ self.help_layout.setContentsMargins(0, 0, 0, 0)
304
+ layout.addWidget(self.help_holder)
305
+ self.help_choice.currentTextChanged.connect(self.show_function_help)
306
+ self.show_function_help(self.help_choice.currentText())
307
+ constants = doc.get("constants", {})
308
+ if constants:
309
+ cform = QFormLayout(); layout.addLayout(cform)
310
+ for key in constants:
311
+ self.field(cform, "Constant: " + key, ["documentation", "constants", key], multiline=True, page=page)
312
+ layout.addStretch()
313
+
314
+ def show_function_help(self, name):
315
+ self.clear(self.help_layout, "/documentation/functions/")
316
+ function = self.draft.get("documentation", {}).get("functions", {}).get(name)
317
+ if not isinstance(function, dict): return
318
+ body = QWidget(); form = QFormLayout(body); self.help_layout.addWidget(body)
319
+ prefix = ["documentation", "functions", name]
320
+ for i, value in enumerate(function.get("parameters", [])):
321
+ self.field(form, f"Parameter {i+1}", prefix + ["parameters", i], multiline=True, page=self.help_tab)
322
+ for key in ("returns", "details", "example"):
323
+ if key not in function: continue
324
+ choices = [c["name"] for c in self.draft["cases"] if c["expect"]["kind"] == "run"] if key == "example" else None
325
+ self.field(form, "Native example" if key == "example" else key.title(), prefix+[key],
326
+ "Choose a passing native fixture containing this function." if key=="example" else "",
327
+ choices=choices, multiline=key != "example", page=self.help_tab)
328
+
329
+ def fixtures_page(self):
330
+ layout, page = self.page("Fixtures", "Expected results are your reference. Verify compiles and runs every native fixture, and checks every expected conversion rejection.")
331
+ self.fixture_tab = page
332
+ self.fixture_choice = QComboBox()
333
+ for case in self.draft.get("cases", []): self.fixture_choice.addItem(case["name"])
334
+ self.fixture_choice.setAccessibleName("Fixture")
335
+ layout.addWidget(self.fixture_choice)
336
+ self.fixture_holder = QWidget(); self.fixture_layout = QVBoxLayout(self.fixture_holder)
337
+ self.fixture_layout.setContentsMargins(0, 0, 0, 0)
338
+ layout.addWidget(self.fixture_holder); layout.addStretch()
339
+ self.fixture_choice.currentIndexChanged.connect(self.show_fixture)
340
+ self.show_fixture(0)
341
+
342
+ def show_fixture(self, index):
343
+ self.clear(self.fixture_layout, "/cases/")
344
+ cases = self.draft.get("cases", [])
345
+ if not 0 <= index < len(cases): return
346
+ case = cases[index]
347
+ body = QWidget(); form = QFormLayout(body); self.fixture_layout.addWidget(body)
348
+ self.fixture_layout.addWidget(label("Source: " + case["file"] + "\nExpected kind: " + case["expect"]["kind"]))
349
+ self.fixture_layout.addWidget(button("Edit fixture source…", "go-to-source", lambda: self.source_requested.emit(case["file"])))
350
+ for key in case["expect"]:
351
+ if key == "kind": continue
352
+ self.field(form, "Expected " + key.replace("_", " "), ["cases", index, "expect", key],
353
+ multiline=key in ("stdout", "stderr"), page=self.fixture_tab)
354
+
355
+ def focus_path(self, path):
356
+ parts = [p.replace("~1", "/").replace("~0", "~") for p in path.split("/")[1:]]
357
+ if len(parts) >= 3 and parts[:2] == ["documentation", "functions"] and hasattr(self, "help_choice"):
358
+ self.help_choice.setCurrentText(parts[2])
359
+ if len(parts) >= 3 and parts[:2] == ["declaration", "functions"] and parts[2].isdigit():
360
+ self.function_choice.setCurrentIndex(int(parts[2]))
361
+ if len(parts) >= 2 and parts[0] == "cases" and parts[1].isdigit():
362
+ self.fixture_choice.setCurrentIndex(int(parts[1]))
363
+ target = self.fields.get(path)
364
+ if target:
365
+ widget, page = target
366
+ self.tabs.setCurrentWidget(page)
367
+ ancestor = widget.parentWidget()
368
+ while ancestor and ancestor is not page:
369
+ if isinstance(ancestor, QGroupBox) and ancestor.isCheckable(): ancestor.setChecked(True)
370
+ ancestor = ancestor.parentWidget()
371
+ widget.setFocus(); page.ensureWidgetVisible(widget)
372
+ return True
373
+ if parts and parts[0] == "cases":
374
+ self.tabs.setCurrentWidget(self.fixture_tab); self.fixture_choice.setFocus(); return True
375
+ if parts[:2] == ["declaration", "functions"]:
376
+ self.tabs.setCurrentWidget(self.function_tab); self.function_choice.setFocus(); return True
377
+ if parts and parts[0] == "documentation":
378
+ self.tabs.setCurrentWidget(self.help_tab); return True
379
+ if parts and parts[0] == "metadata":
380
+ self.tabs.setCurrentIndex(0); return True
381
+ return False
382
+
383
+ def advanced(self):
384
+ dlg = DraftDialog("Advanced project data", self)
385
+ dlg.body.addWidget(label("Edit declaration details or fixture definitions as JSON. The scanner checks the saved result through the selected engine. New fixture files must already exist in the project."))
386
+ source = QPlainTextEdit(json.dumps(self.draft, indent=2)); source.setAccessibleName("Project JSON")
387
+ dlg.body.addWidget(source, 1)
388
+ problem = label(""); dlg.problem = problem; dlg.body.addWidget(problem)
389
+ dlg.runner = JobRunner(dlg)
390
+ # Validate JSON before accepting. Engine validation remains in Scan.
391
+ def apply():
392
+ try:
393
+ draft = parse(source.toPlainText())
394
+ if type(draft) is not dict or not {"declaration", "metadata", "cases"} <= draft.keys():
395
+ raise SDKError("SDK_PROJECT", "Keep the project declaration, metadata and cases.")
396
+ except (SDKError, TypeError, ValueError) as exc:
397
+ problem.setText(str(exc)); return
398
+ source.setReadOnly(True); apply_button.setEnabled(False)
399
+ dlg.runner.start(self.configuration, "validate_project", (self.directory, draft),
400
+ {"expected_sha256": self.expected_sha256})
401
+ def validated(method, result, revision):
402
+ source.setReadOnly(False); apply_button.setEnabled(True)
403
+ if dlg.close_pending:
404
+ dlg.reject(); return
405
+ if result["status"] != "succeeded":
406
+ problem.setText("\n".join(d["message"] for d in result["diagnostics"])); return
407
+ self.load(result["data"]["document"], methods=self.methods, operations=self.operations, workbench=self.workbench)
408
+ self.changed.emit(); dlg.accept()
409
+ dlg.runner.finished.connect(validated)
410
+ row = QHBoxLayout(); apply_button = button("Apply draft", "check", apply)
411
+ row.addWidget(apply_button); row.addWidget(button("Cancel", "cancel", dlg.reject))
412
+ dlg.body.addLayout(row); dlg.resize(900, 650); dlg.exec()
@@ -0,0 +1,9 @@
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"><title>PyCForge SDK — Getting started</title></head><body>
2
+ <h1>PyCForge SDK</h1><p>Create conversion extensions using the installed PyCForge engine. This short guide is available before an engine is connected.</p>
3
+ <h2>Find PyCForge</h2><p>The startup panel searches your saved connection and common Python installations. Choose among several engines, or use Locate PyCForge if it cannot be found. Select the installation, Python environment, installed Crucible support folder or Python interpreter. The custom picker has drive shortcuts. A source folder alone needs a working installed engine.</p>
4
+ <p>Continue offline opens local projects and any cached reference. Engine and tools exposes advanced interpreter and compiler settings. This Python selects the SDK interpreter; Refresh checks it. PyCForge’s About → Distribution → SDK Python shows its exact interpreter.</p>
5
+ <h2>Learn from your engine</h2><p>After connection, the Help topic selector offers the SDK guide and conversion-import manuals supplied by PyCForge’s Crucible folder. Authoring forms, operation choices and starter projects also come from that installation. Refresh after updating PyCForge. Cached guides remain readable offline; their engine and connection state are displayed above.</p>
6
+ <h2>Author and check</h2><p>Choose New or Open, edit the declaration and Help, save, then Scan. Verify fixtures explicitly converts, compiles and runs the saved examples. <b>Ready to package</b> means the current saved project matches passing evidence for its declared fixtures and recorded environment. Package and registration are separate actions. Changes to projects or tools require fresh verification.</p>
7
+ <h2>Recovery</h2><p>Activity contains diagnostics. Unsaved edits and outside file changes clear readiness. A failed refresh preserves compatible cached reference; it cannot authorize execution. Closing during work requests cancellation and waits for the worker. Windows direct-process termination does not supervise arbitrary descendant process trees.</p>
8
+ <h2>Keyboard</h2><p>Ctrl+N: New; Ctrl+O: Open; Ctrl+S: Save; F5: Scan; F6: Verify fixtures; Ctrl+B: Package; F1: Help.</p>
9
+ </body></html>
@@ -0,0 +1,139 @@
1
+ """SDK-only copper accents over the preserved PyCForge presentation layer."""
2
+ from pathlib import Path
3
+ from PySide6.QtCore import Qt, QSize
4
+ from PySide6.QtGui import QIcon
5
+ from PySide6.QtWidgets import QFrame, QHBoxLayout, QLabel, QSizePolicy, QVBoxLayout
6
+
7
+
8
+ COPPER = "#D99B6B"
9
+ COPPER_BRIGHT = "#F0BB91"
10
+ COPPER_SURFACE = "#3B3028"
11
+
12
+ # Applied to SDK windows, never to QApplication or the shared visual modules.
13
+ # Brand emphasis is separate from success/warning/error status colors.
14
+ SDK_QSS = """
15
+ QFrame#SDKEngineLink {
16
+ background: #262D34; border: 1px solid #4C5965;
17
+ border-left: 4px solid #D99B6B; border-radius: 6px;
18
+ }
19
+ QLabel#SDKConnectionTitle { color: #E0E5E9; font-size: 15px; font-weight: 700; }
20
+ QLabel#SDKConnectionTag { color: #F0BB91; font-size: 11px; font-weight: 700; }
21
+ QLabel#SDKWelcomeTitle { color: #F0BB91; font-size: 24px; font-weight: 600; }
22
+ QLabel#SDKConnectionPath { color: #A7B4BE; }
23
+ QWidget#SDKConnectionSettings { border: none; }
24
+ QDialog#SDKStartup { background: #1B2127; }
25
+ QFrame#SDKBrand {
26
+ background: #262D34;
27
+ border: 1px solid #4C5965;
28
+ border-top: 2px solid #D99B6B;
29
+ border-radius: 5px;
30
+ }
31
+ QLabel#SDKProductName { color: #E0E5E9; font-size: 16px; font-weight: 700; }
32
+ QLabel#SDKBadge {
33
+ color: #F0BB91; background: #3B3028;
34
+ border: 1px solid #A5714C; border-radius: 4px;
35
+ font-weight: 700; padding: 3px 6px;
36
+ }
37
+ QLabel#SDKBrandCaption { color: #A7B4BE; font-size: 11px; }
38
+ QListWidget#DocumentList:focus { border-color: #D99B6B; border-bottom-color: #D99B6B; }
39
+ QListWidget#DocumentList::item:selected {
40
+ color: #F0BB91; background: #3B3028;
41
+ border: 1px solid #A5714C; border-left: 3px solid #D99B6B;
42
+ }
43
+ QListWidget#DocumentList::item:selected:hover { background: #49382B; }
44
+ QTabBar::tab:selected, QTabBar::tab:hover:enabled {
45
+ border-bottom: 2px solid #D99B6B;
46
+ }
47
+ QMenuBar::item:selected, QMenuBar::item:pressed { border-bottom: 2px solid #D99B6B; }
48
+ QMenu#PyCForgeMenu::item:selected:enabled {
49
+ background: #3B3028; border-left: 3px solid #D99B6B;
50
+ }
51
+ QMenu#PyCForgeMenu::item:pressed:enabled {
52
+ background: #49382B; border-left: 3px solid #D99B6B; border-bottom: 2px solid #D99B6B;
53
+ }
54
+ QPushButton[sdkAccent="true"]:enabled, QToolButton[sdkAccent="true"]:enabled {
55
+ color: #F0BB91; border-bottom: 2px solid #D99B6B;
56
+ }
57
+ QPushButton[sdkAccent="true"]:hover:enabled, QToolButton[sdkAccent="true"]:hover:enabled {
58
+ background: #3B3028; border-color: #D99B6B;
59
+ }
60
+ QPushButton[sdkAccent="true"]:pressed:enabled, QToolButton[sdkAccent="true"]:pressed:enabled {
61
+ background: #49382B; border-color: #F0BB91;
62
+ }
63
+ QPushButton[sdkAccent="true"]:disabled, QToolButton[sdkAccent="true"]:disabled {
64
+ color: #95A1AB; background: #262D34;
65
+ border-color: #4C5965; border-bottom: 1px solid #4C5965;
66
+ }
67
+ QLineEdit:focus, QPlainTextEdit:focus, QComboBox:focus,
68
+ QPushButton[sdkAccent="true"]:focus, QToolButton[sdkAccent="true"]:focus {
69
+ border-color: #D99B6B;
70
+ }
71
+ QFrame#DialogTitleBar { border-bottom: 2px solid #D99B6B; }
72
+ QProgressBar::chunk { background: #87502D; }
73
+ """
74
+
75
+
76
+ class PathLabel(QLabel):
77
+ """An exact path in the tooltip, elided in layouts instead of widening them."""
78
+ def __init__(self, parent=None):
79
+ super().__init__(parent)
80
+ self.full_text = ""
81
+ self.setObjectName("SDKConnectionPath")
82
+ self.setTextFormat(Qt.TextFormat.PlainText)
83
+ self.setMinimumWidth(0)
84
+ self.setSizePolicy(QSizePolicy.Policy.Ignored, QSizePolicy.Policy.Preferred)
85
+
86
+ def setText(self, text):
87
+ self.full_text = text
88
+ self.setToolTip(text)
89
+ self.setAccessibleDescription(text)
90
+ self._elide()
91
+
92
+ def _elide(self):
93
+ super().setText(self.fontMetrics().elidedText(self.full_text, Qt.TextElideMode.ElideMiddle, max(0, self.width())))
94
+
95
+ def resizeEvent(self, event):
96
+ super().resizeEvent(event)
97
+ self._elide()
98
+
99
+ def minimumSizeHint(self):
100
+ return QSize(0, self.fontMetrics().height() + 4)
101
+
102
+
103
+ def sdk_icon():
104
+ """The original code-bracket mark used by the approved SDK banner."""
105
+ return QIcon(str(Path(__file__).with_name("resources") / "sdk-mark.png"))
106
+
107
+
108
+ def sdk_badge(parent=None):
109
+ badge = QLabel("SDK", parent)
110
+ badge.setObjectName("SDKBadge")
111
+ badge.setAccessibleName("PyCForge SDK")
112
+ badge.setAlignment(Qt.AlignmentFlag.AlignCenter)
113
+ badge.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
114
+ return badge
115
+
116
+
117
+ def brand_panel(parent=None):
118
+ panel = QFrame(parent)
119
+ panel.setObjectName("SDKBrand")
120
+ panel.setAccessibleName("PyCForge SDK — conversion extensions")
121
+ layout = QVBoxLayout(panel)
122
+ layout.setContentsMargins(10, 10, 10, 10)
123
+ layout.setSpacing(6)
124
+ row = QHBoxLayout()
125
+ row.setSpacing(6)
126
+ mark = QLabel()
127
+ mark.setFixedSize(28, 28)
128
+ mark.setPixmap(sdk_icon().pixmap(mark.size(), panel.devicePixelRatioF()))
129
+ row.addWidget(mark)
130
+ name = QLabel("PyCForge")
131
+ name.setObjectName("SDKProductName")
132
+ row.addWidget(name)
133
+ row.addWidget(sdk_badge(panel))
134
+ row.addStretch(1)
135
+ layout.addLayout(row)
136
+ caption = QLabel("Conversion extensions")
137
+ caption.setObjectName("SDKBrandCaption")
138
+ layout.addWidget(caption)
139
+ return panel