From 81ddfc58c58b010c6b2dc8fb39f5fd76c898cc22 Mon Sep 17 00:00:00 2001 From: paul Date: Sun, 16 Mar 2025 15:43:41 +0530 Subject: [PATCH] fix: added initialPosition to createWidget --- src/App.js | 10 ++- src/canvas/canvas.js | 10 +-- src/canvas/toolbar.js | 43 +++++++--- src/canvas/widgets/base.js | 49 ++++++++---- src/frameworks/tkinter/widgets/base.js | 82 ++++++++++++-------- src/frameworks/tkinter/widgets/mainWindow.js | 8 +- 6 files changed, 135 insertions(+), 67 deletions(-) diff --git a/src/App.js b/src/App.js index c040107..452c636 100644 --- a/src/App.js +++ b/src/App.js @@ -93,8 +93,14 @@ function App() { const canvasCenterX = (canvasBoundingBox.width - canvasBoundingBox.left) / 2 const canvasCenterY = (canvasBoundingBox.height - canvasBoundingBox.top) / 2 + // console.log("position: ", TkMainWindow.) if (UIFramework === FrameWorks.TKINTER){ - canvasRef?.current?.createWidget(TkMainWindow, ({id, widgetRef}) => { + + const widgetCenterX = (TkMainWindow.initialSize.width - canvasBoundingBox.left) / 2 + const widgetCenterY = (TkMainWindow.initialSize.height - canvasBoundingBox.top) / 2 + + + canvasRef?.current?.createWidget(TkMainWindow, {x: canvasCenterX - widgetCenterX, y: canvasCenterY - widgetCenterY}, ({id, widgetRef}) => { // center the widget when adding to canvas if (!widgetRef.current){ @@ -106,7 +112,7 @@ function App() { const widgetCenterY = (widgetBoundingBox.height - widgetBoundingBox.top) / 2 - widgetRef.current?.setPos(canvasCenterX-widgetCenterX, canvasCenterY-widgetCenterY) + // widgetRef.current?.setPos(canvasCenterX-widgetCenterX, canvasCenterY-widgetCenterY) }) }else if (UIFramework === FrameWorks.CUSTOMTK){ diff --git a/src/canvas/canvas.js b/src/canvas/canvas.js index db12b58..e040ae1 100644 --- a/src/canvas/canvas.js +++ b/src/canvas/canvas.js @@ -761,8 +761,8 @@ class Canvas extends React.Component { } // if the widget is being dropped from the sidebar, use the info to create the widget first - this.createWidget(widgetClass, ({ id, widgetRef }) => { - widgetRef.current.setPos(finalPosition.x, finalPosition.y) + this.createWidget(widgetClass, {x: finalPosition.x, y: finalPosition.y},({ id, widgetRef }) => { + // widgetRef.current.setPos(finalPosition.x, finalPosition.y) }) } else if ([WidgetContainer.CANVAS, WidgetContainer.WIDGET].includes(container)) { @@ -1045,7 +1045,7 @@ class Canvas extends React.Component { * * @param {Widget} widgetComponentType - don't pass instead pass Widget object/class */ - createWidget(widgetComponentType, callback) { + createWidget(widgetComponentType, initialPos={x: 0, y: 0}, callback,) { if (!isSubClassOfWidget(widgetComponentType)) { throw new Error("widgetComponentType must be a subclass of Widget class") @@ -1067,7 +1067,7 @@ class Canvas extends React.Component { widgetType: widgetComponentType, children: [], parent: "", - initialData: {} // useful for serializing and deserializing (aka, saving and loading) + initialData: {pos: initialPos} // useful for serializing and deserializing (aka, saving and loading) } const widgets = [...this.widgets, newWidget] // don't add the widget refs in the state @@ -1180,7 +1180,7 @@ class Canvas extends React.Component { } onActiveWidgetUpdate(widgetId) { - + // TODO: remove this as it may no longer be required also remove toolbarAttrs if (!this.selectedWidget || widgetId !== this.selectedWidget.__id) return diff --git a/src/canvas/toolbar.js b/src/canvas/toolbar.js index a5c6c30..ba8c618 100644 --- a/src/canvas/toolbar.js +++ b/src/canvas/toolbar.js @@ -12,6 +12,7 @@ import { Layouts } from "./constants/layouts.js" import { DynamicRadioInputList } from "../components/inputs.js" import { useFileUploadContext } from "../contexts/fileUploadContext.js" import { AudioOutlined, FileImageOutlined, FileTextOutlined, VideoCameraOutlined } from "@ant-design/icons" +import { useWidgetContext } from "./context/widgetContext.js" // FIXME: Maximum recursion error @@ -22,16 +23,44 @@ import { AudioOutlined, FileImageOutlined, FileTextOutlined, VideoCameraOutlined * @param {string} widgetType * @param {object} attrs - widget attributes */ -const CanvasToolBar = memo(({ isOpen, widgetType, attrs = {} }) => { +const CanvasToolBar = memo(({ isOpen, widgetType, }) => { // const { activeWidgetAttrs } = useActiveWidget() + const {activeWidget} = useWidgetContext() + + console.log("active widget: ", activeWidget) + // console.log("active widget context: ", activeWidgetAttrs) const [toolbarOpen, setToolbarOpen] = useState(isOpen) - const [toolbarAttrs, setToolbarAttrs] = useState(attrs) + const [toolbarAttrs, setToolbarAttrs] = useState({}) const {uploadedAssets} = useFileUploadContext() + useEffect(() => { + + const stateUpdatedCallback = () => { + setToolbarAttrs(activeWidget.getToolbarAttrs()) + } + + if (activeWidget){ + activeWidget.stateChangeSubscriberCallback(stateUpdatedCallback) + // console.log("sytate update: ", activeWidget.getToolbarAttrs()) + setToolbarAttrs(activeWidget.getToolbarAttrs()) + } + + }, [activeWidget]) // , activeWidget?.state + + useEffect(() => { + setToolbarOpen(isOpen) + }, [isOpen]) + + // useEffect(() => { + + // setToolbarAttrs(activeWidget.getToolbarAttrs()) + + // }, []) + const uploadItems = useMemo(() => { const returnComponentBasedOnFileType = (file) => { @@ -81,14 +110,6 @@ const CanvasToolBar = memo(({ isOpen, widgetType, attrs = {} }) => { }, [uploadedAssets]) - useEffect(() => { - setToolbarOpen(isOpen) - }, [isOpen]) - - useEffect(() => { - setToolbarAttrs(attrs) - }, [attrs]) - const handleChange = (value, callback) => { if (callback) { @@ -407,7 +428,7 @@ const CanvasToolBar = memo(({ isOpen, widgetType, attrs = {} }) => { >

- {capitalize(`${widgetType || ""}`).replace(/_/g, " ")} + {capitalize(`${activeWidget?.getDisplayName() || ""}`).replace(/_/g, " ")}

diff --git a/src/canvas/widgets/base.js b/src/canvas/widgets/base.js index caa680d..31dcde8 100644 --- a/src/canvas/widgets/base.js +++ b/src/canvas/widgets/base.js @@ -202,6 +202,8 @@ class Widget extends React.Component { this.getRenderSize = this.getRenderSize.bind(this) this.getInnerRenderStyling = this.getInnerRenderStyling.bind(this) + this.stateUpdateCallback = null // allowing other components such as toolbar to subscribe to changes in this widget + } componentDidMount() { @@ -227,6 +229,12 @@ class Widget extends React.Component { } + stateChangeSubscriberCallback = (callback) => { + // NOTE: don't subscribe to multiple callbacks, only the last one will work + // allowing other components such as toolbar to subscribe to changes in this widget + this.stateUpdateCallback = callback + } + /** * This function will notify the canvas of the updates to the widgets * @@ -234,15 +242,18 @@ class Widget extends React.Component { * @param {*} callback - callback to run after setState */ updateState = (newState, callback) => { - - console.log("updatstate called: ", newState, this.state.attrs) + // FIXME: maximum recursion error when updating size, color etc this.setState(newState, () => { console.log("updatinhg./..: ", this.state) const { onWidgetUpdate } = this.props - if (onWidgetUpdate) { - onWidgetUpdate(this.__id) - } + + + if (this.stateUpdateCallback) + this.stateUpdateCallback() + // if (onWidgetUpdate) { + // onWidgetUpdate(this.__id) + // } // const { activeWidgetId, updateToolAttrs } = this.context @@ -318,7 +329,7 @@ class Widget extends React.Component { } forceRerender = () => { - this.forceUpdate(() => console.log("forced")) + this.forceUpdate() } // TODO: add context menu items such as delete, add etc @@ -487,9 +498,9 @@ class Widget extends React.Component { * @param {string} path - path to the key, eg: styling.backgroundColor * @param {any} value */ - setAttrValue(path, value) { + setAttrValue(path, value, callback) { - this.setState((prevState) => { // since the setState is Async only the prevState contains the latest state + this.updateState((prevState) => { // since the setState is Async only the prevState contains the latest state const keys = path.split('.') const lastKey = keys.pop() @@ -511,9 +522,7 @@ class Widget extends React.Component { return { attrs: newAttrs } - }, () => { - console.log("new data updated: ", this.state.attrs) - }) + }, callback) } /** @@ -533,7 +542,6 @@ class Widget extends React.Component { return undefined // Return undefined if the key doesn't exist } } - console.log("found value: ", nestedObject, path) return nestedObject?.value // Return the value (assuming it has a 'value' field) } @@ -822,7 +830,7 @@ class Widget extends React.Component { data = {...data} // create a shallow copy - const {attrs, parentLayout, ...restData} = data + const {attrs={}, pos={x: 0, y: 0}, parentLayout=null, ...restData} = data let layoutUpdates = { @@ -846,7 +854,8 @@ class Widget extends React.Component { const newData = { ...restData, - ...layoutUpdates + ...layoutUpdates, + pos } this.setState(newData, () => { @@ -1079,7 +1088,17 @@ class Widget extends React.Component { // initialPos: newInitialPos, // } // console.log("Dropped on Sidebar: ", this.__id) - this.props.onCreateWidgetRequest(widgetClass, ({ id, widgetRef }) => { + + + const parentRect = this.getBoundingRect() + const {zoom, pan} = this.props.canvasMetaData + + let initialPos = { + x: (e.clientX - parentRect.left) / zoom, + y: (e.clientY - parentRect.top) / zoom, + } + + this.props.onCreateWidgetRequest(widgetClass, {x: initialPos.x, y: initialPos.y},({ id, widgetRef }) => { this.props.onAddChildWidget({ event: e, parentWidgetId: this.__id, diff --git a/src/frameworks/tkinter/widgets/base.js b/src/frameworks/tkinter/widgets/base.js index d7ebc9d..ddd8295 100644 --- a/src/frameworks/tkinter/widgets/base.js +++ b/src/frameworks/tkinter/widgets/base.js @@ -16,6 +16,11 @@ export class TkinterBase extends Widget { super(props) this.getLayoutCode = this.getLayoutCode.bind(this) + + this.state = { + ...this.state, + flexSide: "left" + } } getLayoutCode(){ @@ -99,7 +104,7 @@ export class TkinterBase extends Widget { getPackAttrs = () => { return { - side: this.getAttrValue("flexManager.side") , + side: this.state.flexSide, } } @@ -164,15 +169,13 @@ export class TkinterBase extends Widget { value: false, onChange: (value) => { this.setAttrValue("flexManager.fillX", value) - const widgetStyle = { - ...this.state.widgetOuterStyling, - // flexGrow: value ? 1 : 0, - width: "100%" - } - this.updateState({ - widgetOuterStyling: widgetStyle, - }) + this.updateState((prevState) => ({ + widgetOuterStyling: { + ...prevState.widgetOuterStyling, + width: "100%" + } + })) } }, @@ -183,15 +186,12 @@ export class TkinterBase extends Widget { onChange: (value) => { this.setAttrValue("flexManager.fillY", value) - const widgetStyle = { - ...this.state.widgetOuterStyling, - height: "100%" - - // flexGrow: value ? 1 : 0, - } - this.updateState({ - widgetOuterStyling: widgetStyle, - }) + this.updateState((prevState) => ({ + widgetOuterStyling: { + ...prevState.widgetOuterStyling, + height: "100%" + } + })) } }, expand: { @@ -215,14 +215,17 @@ export class TkinterBase extends Widget { label: "Align Side", tool: Tools.SELECT_DROPDOWN, options: ["left", "right", "top", "bottom", ""].map(val => ({value: val, label: val})), - value: "", + value: "left", onChange: (value) => { // FIXME: force parent rerender because, here only child get rerendered, if only parent get rerendered the widget would move this.setAttrValue("flexManager.side", value) + this.setState({flexSide: value}, () => { + console.log("updated side: ", this.state.attrs) + setTimeout(this.props.parentWidgetRef.current.forceRerender, 1) + }) // this.props.parentWidgetRef.current.forceRerender() - // setTimeout(this.props.parentWidgetRef.current.forceRerender, 1) // console.log("updateing state: ", value, this.props.parentWidgetRef.current) } }, @@ -361,7 +364,7 @@ export class TkinterBase extends Widget { console.log("side: ", packAttrs, item, item.ref?.current?.getPackAttrs()) // const widgetSide = item.ref.current?.getAttrValue("flexManager.side") || "left" // console.log("widget side: ", item.ref.current?.__id, item.ref.current, item.ref.current.getAttrValue("flexManager.side")) - return ((packAttrs?.side || "right") === pos) + return ((packAttrs?.side ) === pos) })}
))} @@ -385,12 +388,18 @@ export class TkinterBase extends Widget { } switch (side) { - case "top": return { gridColumn: "1 / -1", justifySelf: "center", ...columnStyle }; - case "bottom": return { gridColumn: "1 / -1", justifySelf: "center", ...columnStyle }; - case "left": return { gridRow: "2", gridColumn: "1", alignSelf: "center", ...rowStyle }; - case "right": return { gridRow: "2", gridColumn: "3", alignSelf: "center", ...rowStyle }; - case "center": return { gridRow: "2", gridColumn: "2", alignSelf: "center", justifySelf: "center" }; - default: return {} + case "top": + return { gridColumn: "1 / -1", alignSelf: "stretch", width: "100%", ...columnStyle }; + case "bottom": + return { gridColumn: "1 / -1", alignSelf: "stretch", width: "100%", ...columnStyle }; + case "left": + return { gridRow: "2", gridColumn: "1", justifySelf: "stretch", height: "100%", ...rowStyle }; + case "right": + return { gridRow: "2", gridColumn: "3", justifySelf: "stretch", height: "100%", ...rowStyle }; + case "center": + return { gridRow: "2", gridColumn: "2", alignSelf: "center", justifySelf: "center" }; + default: + return {}; } } @@ -494,6 +503,14 @@ export class TkinterBase extends Widget { // }) // } + + serialize(){ + return ({ + ...super.serialize(), + flexSide: this.state.flexSide + }) + } + /** * loads the data * @param {object} data @@ -506,8 +523,7 @@ export class TkinterBase extends Widget { data = {...data} // create a shallow copy - const {attrs, parentLayout=null, ...restData} = data - + const {attrs={}, pos={x: 0, y: 0}, parentLayout=null, ...restData} = data let layoutUpdates = { parentLayout: parentLayout @@ -531,16 +547,18 @@ export class TkinterBase extends Widget { const newData = { ...restData, - ...layoutUpdates + ...layoutUpdates, + pos } + console.log("data: ", newData) this.setState(newData, () => { let layoutAttrs = this.setParentLayout(parentLayout).attrs || {} // UPdates attrs let newAttrs = { ...this.state.attrs, ...layoutAttrs } - + console.log("new attrs: ", newAttrs, attrs) // Iterate over each path in the updates object Object.entries(attrs).forEach(([path, value]) => { const keys = path.split('.') @@ -564,7 +582,7 @@ export class TkinterBase extends Widget { // TODO: find a better way to apply innerStyles this.setWidgetInnerStyle("backgroundColor", newAttrs.styling.backgroundColor.value) } - + console.log("new arttrs: ", newData) this.updateState({ attrs: newAttrs }, callback) }) diff --git a/src/frameworks/tkinter/widgets/mainWindow.js b/src/frameworks/tkinter/widgets/mainWindow.js index a921a1d..34c3c21 100644 --- a/src/frameworks/tkinter/widgets/mainWindow.js +++ b/src/frameworks/tkinter/widgets/mainWindow.js @@ -9,6 +9,11 @@ class MainWindow extends TkinterBase{ static widgetType = "main_window" static displayName = "Main Window" + static initialSize = { + width: 700, + height: 400 + } + constructor(props) { super(props) @@ -20,7 +25,7 @@ class MainWindow extends TkinterBase{ this.state = { ...this.state, - size: { width: 700, height: 400 }, + size: { width: MainWindow.initialSize.width, height: MainWindow.initialSize.height }, widgetName: "main", attrs: { ...newAttrs, @@ -77,7 +82,6 @@ class MainWindow extends TkinterBase{ } renderContent(){ - console.log("inner style: ", this.getInnerRenderStyling()) return (