diff --git a/README.md b/README.md index 599c7a0..17c3ed5 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,9 @@ To learn more/ see upcoming features visit [roadmap](./roadmap.md) ## License -To support open-source and development of this tool and upcoming free open-source tools, consider buying a one-time license. +To support open-source and development of this tool and upcoming free open-source tools and libraries, consider buying a one-time license. -License will give you access to upcoming features, early access and more. +Purchasing License will allow me to focus on this work and give you access to more advance features, early access and more. The discount's will be available for limited time only on pre-orders. diff --git a/package-lock.json b/package-lock.json index 4860fec..b8f3d14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "analogue-time-picker": "^1.0.2", "antd": "^5.20.0", "autoprefixer": "^10.4.20", "dom-to-image-more": "^3.4.5", @@ -4507,15 +4508,6 @@ "@types/json-schema": "*" } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -5354,6 +5346,11 @@ "ajv": "^8.8.2" } }, + "node_modules/analogue-time-picker": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/analogue-time-picker/-/analogue-time-picker-1.0.2.tgz", + "integrity": "sha512-YjF5qZWoiEc5MKk4yi0kxb8IGdOb0D1NERKj8BJCDK9TSmmZzdMh9vJH+Lw2apL+7rb544rja0tKKpKoWoU5NQ==" + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -6148,9 +6145,9 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -6160,7 +6157,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -7816,9 +7813,9 @@ } }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } @@ -8798,36 +8795,36 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -9334,12 +9331,12 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -13781,9 +13778,12 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -13807,9 +13807,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -14594,9 +14594,9 @@ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" }, "node_modules/path-type": { "version": "5.0.0", @@ -16113,11 +16113,11 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -17781,9 +17781,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -17816,6 +17816,14 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -17900,14 +17908,14 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -19746,11 +19754,10 @@ } }, "node_modules/webpack": { - "version": "5.93.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", - "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", "dependencies": { - "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.12.1", "@webassemblyjs/wasm-edit": "^1.12.1", @@ -19759,7 +19766,7 @@ "acorn-import-attributes": "^1.9.5", "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", diff --git a/package.json b/package.json index a0677e3..3e50caa 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "analogue-time-picker": "^1.0.2", "antd": "^5.20.0", "autoprefixer": "^10.4.20", "dom-to-image-more": "^3.4.5", diff --git a/roadmap.md b/roadmap.md index b009f45..cbdbdef 100644 --- a/roadmap.md +++ b/roadmap.md @@ -32,4 +32,5 @@ Any feature that has 👑 beside it, is meant only for [premium users](./readme. ### 3.0.0 +- [ ] Node based System (eg: like blender/ unity node system) - [ ] Support for PySide / PyQt 👑 (commercial license only) \ No newline at end of file diff --git a/src/App.js b/src/App.js index bd8d389..7338698 100644 --- a/src/App.js +++ b/src/App.js @@ -14,7 +14,9 @@ import Widget from './canvas/widgets/base' import { DraggableWidgetCard } from './components/cards' import { DragProvider } from './components/draggable/draggableContext' import { ActiveWidgetProvider } from './canvas/activeWidgetContext' -import TkinterSidebar from './frameworks/tkinter/sidebarWidgets' +import TkinterWidgets from './frameworks/tkinter/sidebarWidgets' +import PluginsContainer from './sidebar/pluginsContainer' +import TkinterPluginWidgets from './frameworks/tkinter/sidebarPlugins' function App() { @@ -31,7 +33,7 @@ function App() { const [dropAnimation, setDropAnimation] = useState(null) - const [sidebarWidgets, setSidebarWidgets] = useState(TkinterSidebar || []) + const [sidebarWidgets, setSidebarWidgets] = useState(TkinterWidgets || []) const [canvasWidgets, setCanvasWidgets] = useState([]) // contains the reference to the widgets inside the canvas const [activeSidebarWidget, setActiveSidebarWidget] = useState(null) // helps with the dnd overlay @@ -44,12 +46,12 @@ function App() { { name: "Widgets", icon: , - content: setSidebarWidgets(widgets)}/> + content: setSidebarWidgets(widgets)}/> }, { name: "Plugins", icon: , - content: <>> + content: }, { name: "Uploads", diff --git a/src/frameworks/tkinter/assets/widgets/Toplevel.png b/src/frameworks/tkinter/assets/widgets/main/Toplevel.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/Toplevel.png rename to src/frameworks/tkinter/assets/widgets/main/Toplevel.png diff --git a/src/frameworks/tkinter/assets/widgets/button.png b/src/frameworks/tkinter/assets/widgets/main/button.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/button.png rename to src/frameworks/tkinter/assets/widgets/main/button.png diff --git a/src/frameworks/tkinter/assets/widgets/check.png b/src/frameworks/tkinter/assets/widgets/main/check.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/check.png rename to src/frameworks/tkinter/assets/widgets/main/check.png diff --git a/src/frameworks/tkinter/assets/widgets/dropdown.png b/src/frameworks/tkinter/assets/widgets/main/dropdown.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/dropdown.png rename to src/frameworks/tkinter/assets/widgets/main/dropdown.png diff --git a/src/frameworks/tkinter/assets/widgets/frame.png b/src/frameworks/tkinter/assets/widgets/main/frame.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/frame.png rename to src/frameworks/tkinter/assets/widgets/main/frame.png diff --git a/src/frameworks/tkinter/assets/widgets/frame2.png b/src/frameworks/tkinter/assets/widgets/main/frame2.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/frame2.png rename to src/frameworks/tkinter/assets/widgets/main/frame2.png diff --git a/src/frameworks/tkinter/assets/widgets/input.png b/src/frameworks/tkinter/assets/widgets/main/input.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/input.png rename to src/frameworks/tkinter/assets/widgets/main/input.png diff --git a/src/frameworks/tkinter/assets/widgets/label.png b/src/frameworks/tkinter/assets/widgets/main/label.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/label.png rename to src/frameworks/tkinter/assets/widgets/main/label.png diff --git a/src/frameworks/tkinter/assets/widgets/mainwindow.jpg b/src/frameworks/tkinter/assets/widgets/main/mainwindow.jpg similarity index 100% rename from src/frameworks/tkinter/assets/widgets/mainwindow.jpg rename to src/frameworks/tkinter/assets/widgets/main/mainwindow.jpg diff --git a/src/frameworks/tkinter/assets/widgets/mainwindow.png b/src/frameworks/tkinter/assets/widgets/main/mainwindow.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/mainwindow.png rename to src/frameworks/tkinter/assets/widgets/main/mainwindow.png diff --git a/src/frameworks/tkinter/assets/widgets/radio.png b/src/frameworks/tkinter/assets/widgets/main/radio.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/radio.png rename to src/frameworks/tkinter/assets/widgets/main/radio.png diff --git a/src/frameworks/tkinter/assets/widgets/slider.png b/src/frameworks/tkinter/assets/widgets/main/slider.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/slider.png rename to src/frameworks/tkinter/assets/widgets/main/slider.png diff --git a/src/frameworks/tkinter/assets/widgets/spinbox.png b/src/frameworks/tkinter/assets/widgets/main/spinbox.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/spinbox.png rename to src/frameworks/tkinter/assets/widgets/main/spinbox.png diff --git a/src/frameworks/tkinter/assets/widgets/textarea.png b/src/frameworks/tkinter/assets/widgets/main/textarea.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/textarea.png rename to src/frameworks/tkinter/assets/widgets/main/textarea.png diff --git a/src/frameworks/tkinter/assets/widgets/widget.png b/src/frameworks/tkinter/assets/widgets/main/widget.png similarity index 100% rename from src/frameworks/tkinter/assets/widgets/widget.png rename to src/frameworks/tkinter/assets/widgets/main/widget.png diff --git a/src/frameworks/tkinter/assets/widgets/plugins/clock.png b/src/frameworks/tkinter/assets/widgets/plugins/clock.png new file mode 100644 index 0000000..f78a281 Binary files /dev/null and b/src/frameworks/tkinter/assets/widgets/plugins/clock.png differ diff --git a/src/frameworks/tkinter/assets/widgets/plugins/map.png b/src/frameworks/tkinter/assets/widgets/plugins/map.png new file mode 100644 index 0000000..66de3f7 Binary files /dev/null and b/src/frameworks/tkinter/assets/widgets/plugins/map.png differ diff --git a/src/frameworks/tkinter/assets/widgets/plugins/tables.png b/src/frameworks/tkinter/assets/widgets/plugins/tables.png new file mode 100644 index 0000000..0b92acb Binary files /dev/null and b/src/frameworks/tkinter/assets/widgets/plugins/tables.png differ diff --git a/src/frameworks/tkinter/assets/widgets/plugins/video.png b/src/frameworks/tkinter/assets/widgets/plugins/video.png new file mode 100644 index 0000000..2a85da9 Binary files /dev/null and b/src/frameworks/tkinter/assets/widgets/plugins/video.png differ diff --git a/src/frameworks/tkinter/plugins/analogTimepicker.js b/src/frameworks/tkinter/plugins/analogTimepicker.js new file mode 100644 index 0000000..c8db18b --- /dev/null +++ b/src/frameworks/tkinter/plugins/analogTimepicker.js @@ -0,0 +1,105 @@ +import React from "react" + +import { timePicker, timePickerInput } from 'analogue-time-picker' + +import Widget from "../../../canvas/widgets/base" +import Tools from "../../../canvas/constants/tools" +import { removeKeyFromObject } from "../../../utils/common" + + +class AnalogTimePicker extends Widget{ + + static widgetType = "analogue_timepicker" + + constructor(props) { + super(props) + + this.droppableTags = null + + const newAttrs = removeKeyFromObject("layout", this.state.attrs) + + this.timePicker = null + + this.timePickerRef = React.createRef() + + this.state = { + ...this.state, + size: { width: 'fit', height: 'fit' }, + attrs: { + ...newAttrs, + styling: { + ...newAttrs.styling, + foregroundColor: { + label: "Foreground Color", + tool: Tools.COLOR_PICKER, // the tool to display, can be either HTML ELement or a constant string + value: "#000", + onChange: (value) => { + this.setWidgetStyling("color", value) + this.setAttrValue("styling.foregroundColor", value) + } + } + }, + buttonLabel: { + label: "Button Label", + tool: Tools.INPUT, // the tool to display, can be either HTML ELement or a constant string + toolProps: {placeholder: "Button label", maxLength: 100}, + value: "Button", + onChange: (value) => this.setAttrValue("buttonLabel", value) + } + + } + } + } + + componentDidMount(){ + super.componentDidMount() + this.setWidgetName("Time picker") + this.setAttrValue("styling.backgroundColor", "#E4E2E2") + + this.timePicker = timePicker({ + element: this.timePickerRef.current, + mode: "12" + }) + + const timePickerBtns = this.timePickerRef.current.getElementsByClassName("atp-clock-btn") + for (let i = 0; i < timePickerBtns.length; i++) { + timePickerBtns[i].remove() + } + } + + componentWillUnmount(){ + this.timePicker.dispose() + } + + getToolbarAttrs(){ + + const toolBarAttrs = super.getToolbarAttrs() + + + return ({ + id: this.__id, + widgetName: toolBarAttrs.widgetName, + buttonLabel: this.state.attrs.buttonLabel, + size: toolBarAttrs.size, + + ...this.state.attrs, + + }) + } + + renderContent(){ + return ( + + + + + + ) + } + +} + + +export default AnalogTimePicker \ No newline at end of file diff --git a/src/frameworks/tkinter/plugins/assets/map.png b/src/frameworks/tkinter/plugins/assets/map.png new file mode 100644 index 0000000..fcfd2c0 Binary files /dev/null and b/src/frameworks/tkinter/plugins/assets/map.png differ diff --git a/src/frameworks/tkinter/plugins/assets/video.jpg b/src/frameworks/tkinter/plugins/assets/video.jpg new file mode 100644 index 0000000..d0692e6 Binary files /dev/null and b/src/frameworks/tkinter/plugins/assets/video.jpg differ diff --git a/src/frameworks/tkinter/plugins/mapview.js b/src/frameworks/tkinter/plugins/mapview.js new file mode 100644 index 0000000..bd6ddf4 --- /dev/null +++ b/src/frameworks/tkinter/plugins/mapview.js @@ -0,0 +1,79 @@ +import React from "react" + + +import Widget from "../../../canvas/widgets/base" +import Tools from "../../../canvas/constants/tools" +import { removeKeyFromObject } from "../../../utils/common" + +import MapImage from "./assets/map.png" +import { MinusOutlined, PlayCircleFilled, PlusOutlined } from "@ant-design/icons" + + +class MapView extends Widget{ + + static widgetType = "map_view" + + constructor(props) { + super(props) + + this.droppableTags = null + + const newAttrs = removeKeyFromObject("layout", this.state.attrs) + + this.state = { + ...this.state, + size: { width: 400, height: 250 }, + } + } + + componentDidMount(){ + super.componentDidMount() + this.setWidgetName("Map viewer") + this.setAttrValue("styling.backgroundColor", "#E4E2E2") + } + + getToolbarAttrs(){ + + const toolBarAttrs = super.getToolbarAttrs() + + + return ({ + id: this.__id, + widgetName: toolBarAttrs.widgetName, + size: toolBarAttrs.size, + + ...this.state.attrs, + + }) + } + + renderContent(){ + return ( + + + + + + + + + + + + + + + + ) + } + +} + + +export default MapView \ No newline at end of file diff --git a/src/frameworks/tkinter/plugins/pandasTable.js b/src/frameworks/tkinter/plugins/pandasTable.js new file mode 100644 index 0000000..6c90c3b --- /dev/null +++ b/src/frameworks/tkinter/plugins/pandasTable.js @@ -0,0 +1,139 @@ + + + + +import React, { useEffect, useRef, useState } from "react" + +import Widget from "../../../canvas/widgets/base" +import { removeKeyFromObject } from "../../../utils/common" + +import MapImage from "./assets/map.png" +import { MinusOutlined, PlusOutlined } from "@ant-design/icons" + + +const ResizableTable = ({minRows=5, minCols=5}) => { + const [rows, setRows] = useState(minRows) + const [cols, setCols] = useState(minCols) + const containerRef = useRef(null) + + + + useEffect(() => { + const resizeObserver = new ResizeObserver((entries) => { + for (let entry of entries) { + const { width, height } = entry.contentRect + + // Set number of columns and rows based on widget width and height + const newCols = Math.max(minCols, Math.floor(width / 100)) // each column is 100px wide + const newRows = Math.max(minRows, Math.floor(height / 50)) // each row is 50px high + + setCols(newCols) + setRows(newRows) + } + }) + + if (containerRef.current) { + resizeObserver.observe(containerRef.current); // Start observing the widget + } + + return () => { + if (containerRef.current) { + resizeObserver.unobserve(containerRef.current); // Stop observing when component unmounts + } + } + }, [containerRef]) + + + return ( + + + + {Array.from({ length: rows }).map((_, rowIndex) => ( + + {Array.from({ length: cols }).map((_, colIndex) => ( + + {/* Row {rowIndex + 1}, Col {colIndex + 1} */} + + ))} + + ))} + + + + ) +} + + +class PandasTable extends Widget{ + + static widgetType = "pandas_table" + + constructor(props) { + super(props) + + this.droppableTags = null + + const newAttrs = removeKeyFromObject("layout", this.state.attrs) + + this.state = { + ...this.state, + size: { width: 400, height: 250 }, + } + } + + componentDidMount(){ + super.componentDidMount() + this.setWidgetName("Pandas Table") + this.setAttrValue("styling.backgroundColor", "#E4E2E2") + } + + getToolbarAttrs(){ + + const toolBarAttrs = super.getToolbarAttrs() + + + return ({ + id: this.__id, + widgetName: toolBarAttrs.widgetName, + size: toolBarAttrs.size, + + ...this.state.attrs, + + }) + } + + renderContent(){ + return ( + + + + + + ) + } + +} + + +export default PandasTable + + + + +/** + * {'align': 'w', + 'cellbackgr': '#F4F4F3', + 'cellwidth': 80, + 'floatprecision': 2, + 'thousandseparator': '', + 'font': 'Arial', + 'fontsize': 12, + 'fontstyle': '', + 'grid_color': '#ABB1AD', + 'linewidth': 1, + 'rowheight': 22, + 'rowselectedcolor': '#E4DED4', + 'textcolor': 'black'} + */ \ No newline at end of file diff --git a/src/frameworks/tkinter/plugins/videoPlayer.js b/src/frameworks/tkinter/plugins/videoPlayer.js new file mode 100644 index 0000000..5225e75 --- /dev/null +++ b/src/frameworks/tkinter/plugins/videoPlayer.js @@ -0,0 +1,70 @@ +import React from "react" + +import Widget from "../../../canvas/widgets/base" +import Tools from "../../../canvas/constants/tools" +import { removeKeyFromObject } from "../../../utils/common" + +import VideoImage from "./assets/video.jpg" +import { PlayCircleFilled } from "@ant-design/icons" + + +class VideoPlayer extends Widget{ + + static widgetType = "video_player" + + constructor(props) { + super(props) + + this.droppableTags = null + + const newAttrs = removeKeyFromObject("layout", this.state.attrs) + + this.state = { + ...this.state, + size: { width: 'fit', height: 'fit' }, + } + } + + componentDidMount(){ + super.componentDidMount() + this.setWidgetName("Video Player") + this.setAttrValue("styling.backgroundColor", "#E4E2E2") + } + + getToolbarAttrs(){ + + const toolBarAttrs = super.getToolbarAttrs() + + + return ({ + id: this.__id, + widgetName: toolBarAttrs.widgetName, + size: toolBarAttrs.size, + + ...this.state.attrs, + + }) + } + + renderContent(){ + return ( + + + + + + + + + + + ) + } + +} + + +export default VideoPlayer \ No newline at end of file diff --git a/src/frameworks/tkinter/sidebarPlugins.js b/src/frameworks/tkinter/sidebarPlugins.js new file mode 100644 index 0000000..a14ff56 --- /dev/null +++ b/src/frameworks/tkinter/sidebarPlugins.js @@ -0,0 +1,42 @@ + +import ClockImage from "./assets/widgets/plugins/clock.png" +import VideoImage from "./assets/widgets/plugins/video.png" +import MapImage from "./assets/widgets/plugins/map.png" +import DataTableImage from "./assets/widgets/plugins/tables.png" + +import AnalogTimePicker from "./plugins/analogTimepicker" +import VideoPlayer from "./plugins/videoPlayer" +import MapView from "./plugins/mapview" +import PandasTable from "./plugins/pandasTable" + + +const TkinterPluginWidgets = [ + { + name: "Analog TimePicker", + img: ClockImage, + link: "https://github.com", + widgetClass: AnalogTimePicker + }, + { + name: "Video Player", + img: VideoImage, + link: "https://github.com/PaulleDemon/tkVideoPlayer", + widgetClass: VideoPlayer + }, + { + name: "Map viewer", + img: MapImage, + link: "https://github.com/TomSchimansky/TkinterMapView", + widgetClass: MapView + }, + { + name: "Pandas Table", + img: DataTableImage, + link: "https://github.com/dmnfarrell/pandastable", + widgetClass: PandasTable + }, + +] + + +export default TkinterPluginWidgets diff --git a/src/frameworks/tkinter/sidebarWidgets.js b/src/frameworks/tkinter/sidebarWidgets.js index b1c861e..2a36fae 100644 --- a/src/frameworks/tkinter/sidebarWidgets.js +++ b/src/frameworks/tkinter/sidebarWidgets.js @@ -1,31 +1,31 @@ -import { CheckBox, RadioButton } from "./widgets/ checkButton" -import Button from "./widgets/button" -import Frame from "./widgets/frame" -import { Input, Text } from "./widgets/input" -import Label from "./widgets/label" import MainWindow from "./widgets/mainWindow" +import TopLevel from "./widgets/toplevel" +import Frame from "./widgets/frame" +import Label from "./widgets/label" +import Button from "./widgets/button" import OptionMenu from "./widgets/optionMenu" import Slider from "./widgets/slider" -import TopLevel from "./widgets/toplevel" +import { CheckBox, RadioButton } from "./widgets/ checkButton" +import { Input, Text } from "./widgets/input" import SpinBox from "./widgets/spinBox" -import MainWindowImage from "./assets/widgets/mainwindow.png" -import TopLevelImage from "./assets/widgets/Toplevel.png" -import FrameImage from "./assets/widgets/frame2.png" -import LabelImage from "./assets/widgets/label.png" -import ButtonImage from "./assets/widgets/button.png" -import InputImage from "./assets/widgets/input.png" -import TextAreaImage from "./assets/widgets/textarea.png" -import SliderImage from "./assets/widgets/slider.png" -import DropDownImage from "./assets/widgets/dropdown.png" -import CheckButtonImage from "./assets/widgets/check.png" -import RadioButtonImage from "./assets/widgets/radio.png" -import SpinBoxImage from "./assets/widgets/spinbox.png" +import MainWindowImage from "./assets/widgets/main/mainwindow.png" +import TopLevelImage from "./assets/widgets/main/Toplevel.png" +import FrameImage from "./assets/widgets/main/frame2.png" +import LabelImage from "./assets/widgets/main/label.png" +import ButtonImage from "./assets/widgets/main/button.png" +import InputImage from "./assets/widgets/main/input.png" +import TextAreaImage from "./assets/widgets/main/textarea.png" +import SliderImage from "./assets/widgets/main/slider.png" +import DropDownImage from "./assets/widgets/main/dropdown.png" +import CheckButtonImage from "./assets/widgets/main/check.png" +import RadioButtonImage from "./assets/widgets/main/radio.png" +import SpinBoxImage from "./assets/widgets/main/spinbox.png" -const TkinterSidebar = [ +const TkinterWidgets = [ { name: "Main window", img: MainWindowImage, @@ -102,7 +102,7 @@ const TkinterSidebar = [ ] -export default TkinterSidebar +export default TkinterWidgets /** diff --git a/src/frameworks/tkinter/widgets/button.js b/src/frameworks/tkinter/widgets/button.js index 8b0d41a..f1b49b8 100644 --- a/src/frameworks/tkinter/widgets/button.js +++ b/src/frameworks/tkinter/widgets/button.js @@ -10,12 +10,7 @@ class Button extends Widget{ constructor(props) { super(props) - // TODO: disable drop - - this.droppableTags = { - // TODO: exclude all - exclude: ["image", "video", "media", "main_window", "toplevel"] - } + this.droppableTags = null const newAttrs = removeKeyFromObject("layout", this.state.attrs) this.state = { diff --git a/src/sidebar/pluginsContainer.js b/src/sidebar/pluginsContainer.js new file mode 100644 index 0000000..cf2e031 --- /dev/null +++ b/src/sidebar/pluginsContainer.js @@ -0,0 +1,90 @@ +import { useEffect, useMemo, useState } from "react" + +import { CloseCircleFilled, SearchOutlined } from "@ant-design/icons" + +import {SidebarWidgetCard} from "../components/cards" + +import ButtonWidget from "../assets/widgets/button.png" + +import { filterObjectListStartingWith } from "../utils/filter" +import Widget from "../canvas/widgets/base" + + +/** + * + * @param {function} onWidgetsUpdate - this is a callback that will be called once the sidebar is populated with widgets + * @returns + */ +function PluginsContainer({sidebarContent, onWidgetsUpdate}){ + + + const [searchValue, setSearchValue] = useState("") + const [widgetData, setWidgetData] = useState(sidebarContent) + + useEffect(() => { + + setWidgetData(sidebarContent) + // if (onWidgetsUpdate){ + // onWidgetsUpdate(widgets) + // } + + }, [sidebarContent]) + + + + useEffect(() => { + + if (searchValue.length > 0){ + const searchData = filterObjectListStartingWith(sidebarContent, "name", searchValue) + setWidgetData(searchData) + }else{ + setWidgetData(sidebarContent) + } + + }, [searchValue]) + + function onSearch(event){ + + setSearchValue(event.target.value) + + } + + return ( + + + + + + + { + searchValue.length > 0 && + setSearchValue("")}> + + + } + + + + + { + widgetData.map((widget, index) => { + return ( + + + ) + }) + } + + + ) + +} + + +export default PluginsContainer \ No newline at end of file