diff --git a/package-lock.json b/package-lock.json index 70ead3f..4b594be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "fabric": "^6.1.0", "file-saver": "^2.0.5", "jszip": "^3.10.1", + "lodash": "^4.17.21", "postcss-cli": "^11.0.0", "re-resizable": "^6.9.17", "react": "^18.3.1", @@ -14728,7 +14729,8 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", diff --git a/package.json b/package.json index 6fea594..197254d 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "fabric": "^6.1.0", "file-saver": "^2.0.5", "jszip": "^3.10.1", + "lodash": "^4.17.21", "postcss-cli": "^11.0.0", "re-resizable": "^6.9.17", "react": "^18.3.1", diff --git a/src/canvas/canvas.js b/src/canvas/canvas.js index d410e26..bb8f751 100644 --- a/src/canvas/canvas.js +++ b/src/canvas/canvas.js @@ -1257,7 +1257,6 @@ class Canvas extends React.Component { } - // FIXME: this must update the childrens corectly updateWidgetAndChildren = (widgetId) => { const serializeWidgetRecursively = (widget) => { const widgetObj = this.getWidgetById(widget.id)?.current; diff --git a/src/canvas/widgets/base.js b/src/canvas/widgets/base.js index cb88991..c67fde1 100644 --- a/src/canvas/widgets/base.js +++ b/src/canvas/widgets/base.js @@ -1,6 +1,9 @@ import { v4 as uuidv4 } from 'uuid'; import React, { useEffect, useLayoutEffect, useRef, useState } from "react" + +import lo from 'lodash' + import { NotImplementedError } from "../../utils/errors" import Tools from "../constants/tools" @@ -12,7 +15,7 @@ import EditableDiv from "../../components/editableDiv" import WidgetContainer from "../constants/containers" import { DragContext } from "../../components/draggable/draggableContext" -import { isNumeric, removeKeyFromObject } from "../../utils/common" +import { getGridPosition, isNumeric, removeKeyFromObject } from "../../utils/common" import { Layout, message } from "antd" @@ -66,6 +69,8 @@ class Widget extends React.Component { this.swappableAreaRef = React.createRef() // helps identify if the users intent is to swap or drop inside the widget this.innerAreaRef = React.createRef() // this is the inner area where swap is prevented and only drop is accepted + this.styleAreaRef = React.createRef() // use ref this where inner widget style is applied + this.functions = { "load": { "args1": "number", "args2": "string" } } @@ -79,7 +84,7 @@ class Widget extends React.Component { selected: false, isWidgetVisible: true, - forceRerenderId: "", + // forceRerenderId: "", widgetName: widgetName || 'widget', // this will later be converted to variable name enableRename: false, // will open the widgets editable div for renaming @@ -225,7 +230,10 @@ class Widget extends React.Component { if (this.state.attrs.styling.backgroundColor) this.setWidgetInnerStyle('backgroundColor', this.state.attrs.styling?.backgroundColor.value || "#fff") - this.load(this.props.initialData || {}) // load the initial data + this.load(this.props.initialData || {}, () => { + console.log("component remounted: ", this.__id) + + }) // load the initial data // The elementRect is received only after the elemet is added so, it may not be accurate so use resize handler // this.resizeObserver = new MutationObserver(this.handleResizeEvents) @@ -237,28 +245,21 @@ class Widget extends React.Component { } - handleResizeEvents = () => { - if (!this.elementRef.current) return; - - const elementRect = this.elementRef.current.getBoundingClientRect(); - - const parentRect = this.props.parentWidgetRef?.current?.getBoundingRect() - - - const left = ((elementRect.left || 0) - (parentRect?.left || this.props.canvasRectInner?.left)) / this.props.canvasZoom; - const top = ((elementRect.top || 0) - (parentRect?.top || this.props.canvasRectInner?.top)) / this.props.canvasZoom; - - // const left = (elementRect?.left || 0) - // const top = (elementRect?.top || 0) - - this.setState({pos: { x: left, y: top }}); - } - componentDidUpdate(prevProps, prevState) { if (prevProps !== this.props) { this.canvasMetaData = this.props.canvasMetaData } + const compareAttrs = ['attrs', 'widgetName', 'parentLayout', 'positionType'] + + // TODO: maybe find more efficient way to update the canvas about teh child updates??? + if (!lo.isEqual(lo.pick(prevState, compareAttrs), lo.pick(this.state, compareAttrs))){ + // THIS IS inefficeint + // this.props.requestThisWidgetDataUpdate(this.__id) + setTimeout(() => this.props.requestWidgetDataUpdate(this.__id), 1) + } + // call update widgets + } componentWillUnmount(){ @@ -640,7 +641,8 @@ class Widget extends React.Component { * @param {Layouts} parentLayout */ setParentLayout(parentLayout){ - + // FIXME: changing from one layout to another isn't working as expected + // TODO: add styleAreaRef to every where there is innerWidgetSTyle if (!parentLayout){ // if parent layout is null (i,e the widget is on the canvas) return {} @@ -672,6 +674,17 @@ class Widget extends React.Component { this.setPos(pos.x, pos.y) // console.log("setting pos: ", pos) + + if (layout === Layouts.GRID){ + setTimeout(() => { + const gridPos = getGridPosition(this.elementRef.current, this.props.parentWidgetRef.current.styleAreaRef.current) + if (gridPos){ + this.setAttrValue("gridManager.row", gridPos.row) + this.setAttrValue("gridManager.column", gridPos.column) + } + + }, 1) + } }else if (layout === Layouts.PLACE){ updates = { @@ -881,7 +894,9 @@ class Widget extends React.Component { data = {...data} // create a shallow copy - const {attrs={}, selected, pos={x: 0, y: 0}, parentLayout=null, ...restData} = data + const {attrs={}, selected, pos={x: 0, y: 0}, ...restData} = data + + const parentLayout = this.props.parentWidgetRef?.current?.getLayout() // don't get the parentLayout from serialized data as it may have become stale let layoutUpdates = { @@ -1128,23 +1143,7 @@ class Widget extends React.Component { } else if (container === WidgetContainer.SIDEBAR) { - // const { initialPos } = posMetaData - // const canvasInnerRect = this.props.canvasInnerContainerRef.current.getBoundingClientRect() - - // const newInitialPos = { - // x: (initialPos.x - canvasInnerRect.left), - // y: (initialPos.y - canvasInnerRect.top) - // } - - // posMetaData = { - // ...posMetaData, - // initialPos: newInitialPos, - // } - // console.log("Dropped on Sidebar: ", this.__id) - - - // const parentRect = this.getBoundingRect() const canvasRect = this.props.canvasInnerContainerRef.current.getBoundingClientRect() const {zoom, pan} = this.props.canvasMetaData diff --git a/src/frameworks/customtk/widgets/button.js b/src/frameworks/customtk/widgets/button.js index 39970cf..b208378 100644 --- a/src/frameworks/customtk/widgets/button.js +++ b/src/frameworks/customtk/widgets/button.js @@ -70,6 +70,7 @@ class Button extends CustomTkWidgetBase{
{/* {this.props.children} */}
diff --git a/src/frameworks/customtk/widgets/checkButton.js b/src/frameworks/customtk/widgets/checkButton.js index ca626ec..8faeff0 100644 --- a/src/frameworks/customtk/widgets/checkButton.js +++ b/src/frameworks/customtk/widgets/checkButton.js @@ -213,6 +213,7 @@ export class RadioButton extends CustomTkWidgetBase{ return (
diff --git a/src/frameworks/customtk/widgets/frame.js b/src/frameworks/customtk/widgets/frame.js index 61b2105..f1f813d 100644 --- a/src/frameworks/customtk/widgets/frame.js +++ b/src/frameworks/customtk/widgets/frame.js @@ -46,7 +46,9 @@ class Frame extends CustomTkBase{ // console.log("widget styling: ", this.state.widgetInnerStyling) return (
-
+
{this.props.children}
diff --git a/src/frameworks/customtk/widgets/input.js b/src/frameworks/customtk/widgets/input.js index c5c0c38..81f7c20 100644 --- a/src/frameworks/customtk/widgets/input.js +++ b/src/frameworks/customtk/widgets/input.js @@ -66,6 +66,7 @@ export class Input extends CustomTkWidgetBase{ return (
{this.getAttrValue("placeHolder")} diff --git a/src/frameworks/customtk/widgets/label.js b/src/frameworks/customtk/widgets/label.js index 1e580dc..3a11d6d 100644 --- a/src/frameworks/customtk/widgets/label.js +++ b/src/frameworks/customtk/widgets/label.js @@ -129,6 +129,7 @@ class Label extends CustomTkWidgetBase{ }} >
{/* {this.props.children} */} { diff --git a/src/frameworks/customtk/widgets/mainWindow.js b/src/frameworks/customtk/widgets/mainWindow.js index 43fb927..77e9784 100644 --- a/src/frameworks/customtk/widgets/mainWindow.js +++ b/src/frameworks/customtk/widgets/mainWindow.js @@ -81,6 +81,7 @@ class MainWindow extends CustomTkBase{
{this.props.children}
diff --git a/src/frameworks/customtk/widgets/optionMenu.js b/src/frameworks/customtk/widgets/optionMenu.js index f1265f0..ed2f07b 100644 --- a/src/frameworks/customtk/widgets/optionMenu.js +++ b/src/frameworks/customtk/widgets/optionMenu.js @@ -103,6 +103,7 @@ class OptionMenu extends CustomTkWidgetBase{ return (
diff --git a/src/frameworks/customtk/widgets/slider.js b/src/frameworks/customtk/widgets/slider.js index 50d9266..15bfa67 100644 --- a/src/frameworks/customtk/widgets/slider.js +++ b/src/frameworks/customtk/widgets/slider.js @@ -143,7 +143,9 @@ class Slider extends CustomTkWidgetBase{ return (
+ bg-gray-100" + ref={this.styleAreaRef} + style={this.getInnerRenderStyling()}>
{this.getAttrValue("spinProps.default")} diff --git a/src/frameworks/customtk/widgets/toplevel.js b/src/frameworks/customtk/widgets/toplevel.js index a5d13e0..a379abe 100644 --- a/src/frameworks/customtk/widgets/toplevel.js +++ b/src/frameworks/customtk/widgets/toplevel.js @@ -77,7 +77,9 @@ class TopLevel extends Widget{
-
+
{this.props.children}
diff --git a/src/frameworks/tkinter/widgets/base.js b/src/frameworks/tkinter/widgets/base.js index d156f67..16ad792 100644 --- a/src/frameworks/tkinter/widgets/base.js +++ b/src/frameworks/tkinter/widgets/base.js @@ -61,8 +61,24 @@ export class TkinterBase extends Widget { }else if (parentLayout === Layouts.FLEX){ - const config = { - side: direction === "row" ? "tk.LEFT" : "tk.TOP", + const packSide = this.getAttrValue("flexManager.side") + + const config = {} + + if (packSide === "" || packSide === "top"){ + + config['side'] = `tk.TOP` + + }else if (packSide === "left"){ + + config['side'] = `tk.LEFT` + + }else if (packSide === "right"){ + + config['side'] = `tk.RIGHT` + + }else{ + config['side'] = `tk.BOTTOM` } if (gap > 0){ @@ -126,19 +142,11 @@ export class TkinterBase extends Widget { if (!layout){ return {} } - super.setParentLayout(layout) + let updates = super.setParentLayout(layout) const {layout: parentLayout, direction, gap} = layout // show attributes related to the layout manager - let updates = { - parentLayout: layout, - } - - // this.removeAttr("gridManager") - // this.removeAttr("flexManager") - // this.removeAttr("positioning") - // remove gridManager, flexManager positioning const {gridManager, flexManager, positioning, ...restAttrs} = this.state.attrs @@ -284,7 +292,6 @@ export class TkinterBase extends Widget { onChange: (value) => { const previousRow = this.getWidgetOuterStyle("gridRow") || "1/1" - let [_row=1, rowSpan=1] = previousRow.replace(/\s+/g, '').split("/").map(Number) if (value > rowSpan){ @@ -292,7 +299,6 @@ export class TkinterBase extends Widget { rowSpan = value this.setAttrValue("gridManager.rowSpan", rowSpan) } - this.setAttrValue("gridManager.row", value) this.setWidgetOuterStyle("gridRow", `${value+' / '+rowSpan}`) } @@ -565,8 +571,6 @@ export class TkinterBase extends Widget { gridTemplateColumns: "repeat(auto-fill, minmax(100px, 1fr))", gridTemplateRows: "repeat(auto-fill, minmax(100px, 1fr))", - // gridTemplateColumns: layout === Layouts.FLEX ? "minmax(auto, 1fr) 1fr minmax(auto, 1fr)" : "repeat(auto-fill, minmax(100px, 1fr))", - // gridTemplateRows: layout === Layouts.FLEX ? "minmax(auto, 1fr) 1fr minmax(auto, 1fr)" : "repeat(auto-fill, minmax(100px, 1fr))", // gridAutoRows: 'minmax(100px, auto)', // Rows with minimum height of 100px, and grow to fit content // gridAutoCols: 'minmax(100px, auto)', // Cols with minimum height of 100px, and grow to fit content } @@ -648,7 +652,10 @@ export class TkinterBase extends Widget { data = {...data} // create a shallow copy - const {attrs={}, selected, pos={x: 0, y: 0}, parentLayout=null, ...restData} = data + const {attrs={}, selected, pos={x: 0, y: 0}, ...restData} = data + + const parentLayout = this.props.parentWidgetRef?.current?.getLayout() + let layoutUpdates = { parentLayout: parentLayout diff --git a/src/frameworks/tkinter/widgets/button.js b/src/frameworks/tkinter/widgets/button.js index abd68b1..83cc638 100644 --- a/src/frameworks/tkinter/widgets/button.js +++ b/src/frameworks/tkinter/widgets/button.js @@ -69,6 +69,7 @@ class Button extends TkinterWidgetBase{
{/* {this.props.children} */}
diff --git a/src/frameworks/tkinter/widgets/checkButton.js b/src/frameworks/tkinter/widgets/checkButton.js index 8bf86a4..3690cf9 100644 --- a/src/frameworks/tkinter/widgets/checkButton.js +++ b/src/frameworks/tkinter/widgets/checkButton.js @@ -98,6 +98,7 @@ export class CheckBox extends TkinterWidgetBase{ return (
diff --git a/src/frameworks/tkinter/widgets/frame.js b/src/frameworks/tkinter/widgets/frame.js index 7fe02d1..b40bab0 100644 --- a/src/frameworks/tkinter/widgets/frame.js +++ b/src/frameworks/tkinter/widgets/frame.js @@ -46,7 +46,9 @@ class Frame extends TkinterBase{ // console.log("widget styling: ", this.state.widgetInnerStyling) return (
-
+
{this.props.children}
diff --git a/src/frameworks/tkinter/widgets/input.js b/src/frameworks/tkinter/widgets/input.js index 3a3a4d5..f768dcf 100644 --- a/src/frameworks/tkinter/widgets/input.js +++ b/src/frameworks/tkinter/widgets/input.js @@ -66,6 +66,7 @@ export class Input extends TkinterWidgetBase{ return (
{this.getAttrValue("placeHolder")} @@ -139,6 +140,7 @@ export class Text extends TkinterWidgetBase{ return (
{this.getAttrValue("placeHolder")} diff --git a/src/frameworks/tkinter/widgets/label.js b/src/frameworks/tkinter/widgets/label.js index bdd654a..b76b07f 100644 --- a/src/frameworks/tkinter/widgets/label.js +++ b/src/frameworks/tkinter/widgets/label.js @@ -122,6 +122,7 @@ class Label extends TkinterWidgetBase{ }} >
{/* {this.props.children} */} { diff --git a/src/frameworks/tkinter/widgets/mainWindow.js b/src/frameworks/tkinter/widgets/mainWindow.js index 34c3c21..c6c3a8b 100644 --- a/src/frameworks/tkinter/widgets/mainWindow.js +++ b/src/frameworks/tkinter/widgets/mainWindow.js @@ -97,6 +97,7 @@ class MainWindow extends TkinterBase{
{/* {this.props.children} */} {this.renderTkinterLayout()} {/* This is required for pack layouts, so if your widget accepts child widgets, ensure to add this */} diff --git a/src/frameworks/tkinter/widgets/optionMenu.js b/src/frameworks/tkinter/widgets/optionMenu.js index 255047b..ae075e6 100644 --- a/src/frameworks/tkinter/widgets/optionMenu.js +++ b/src/frameworks/tkinter/widgets/optionMenu.js @@ -101,6 +101,7 @@ class OptionMenu extends TkinterWidgetBase{ return (
diff --git a/src/frameworks/tkinter/widgets/slider.js b/src/frameworks/tkinter/widgets/slider.js index fc6cc20..349fece 100644 --- a/src/frameworks/tkinter/widgets/slider.js +++ b/src/frameworks/tkinter/widgets/slider.js @@ -138,7 +138,9 @@ class Slider extends TkinterWidgetBase{ return (
+ bg-gray-100" + ref={this.styleAreaRef} + style={this.getInnerRenderStyling()}>
{this.getAttrValue("spinProps.default")} diff --git a/src/frameworks/tkinter/widgets/toplevel.js b/src/frameworks/tkinter/widgets/toplevel.js index 4938ea0..bf2e421 100644 --- a/src/frameworks/tkinter/widgets/toplevel.js +++ b/src/frameworks/tkinter/widgets/toplevel.js @@ -78,7 +78,9 @@ class TopLevel extends Widget{
-
+
{this.props.children}
diff --git a/src/utils/common.js b/src/utils/common.js index 5b98a0c..a8fdb26 100644 --- a/src/utils/common.js +++ b/src/utils/common.js @@ -69,4 +69,29 @@ export function convertObjectToKeyValueString(obj){ return Object.entries(obj) .map(([key, value]) => `${key}=${value}`) .join(', ') +} + + +/** + * + * @param {HTMLElement} widget + * @param {HTMLElement} gridContainer + * @returns + */ +export const getGridPosition = (widget, gridContainer) => { + if (!widget || !gridContainer) return null; + + const widgets = Array.from(gridContainer.children); // Get all grid items + // const index = widgets.indexOf(widget); + const widgetIndex = widgets.indexOf(widget); + + if (widgetIndex === -1) return null; // Widget not found + + const gridStyles = getComputedStyle(gridContainer); + const columnCount = gridStyles.gridTemplateColumns.split(' ').length; + + const row = Math.floor(widgetIndex / columnCount) + 1; + const column = (widgetIndex % columnCount) + 1; + + return { row, column }; } \ No newline at end of file