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 (