2024-09-25 17:27:12 +05:30
|
|
|
import { Layouts, PosType } from "../../../canvas/constants/layouts"
|
2024-09-26 11:59:24 +05:30
|
|
|
import Tools from "../../../canvas/constants/tools"
|
|
|
|
|
import Widget from "../../../canvas/widgets/base"
|
2024-09-25 17:27:12 +05:30
|
|
|
|
2024-09-26 23:16:43 +05:30
|
|
|
// TODO: add full width and full height in base widget
|
|
|
|
|
// TODO: the pack should configure width and height of widgets
|
2024-09-25 17:27:12 +05:30
|
|
|
|
|
|
|
|
class TkinterBase extends Widget {
|
2024-09-26 11:59:24 +05:30
|
|
|
|
|
|
|
|
static requiredImports = ['import tkinter as tk']
|
|
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
|
super(props)
|
|
|
|
|
|
|
|
|
|
this.getLayoutCode = this.getLayoutCode.bind(this)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getLayoutCode(){
|
|
|
|
|
const {layout: parentLayout, direction, gap} = this.getParentLayout()
|
|
|
|
|
|
|
|
|
|
let layoutManager = `pack()`
|
|
|
|
|
|
|
|
|
|
if (parentLayout === Layouts.FLEX){
|
2024-09-26 23:16:43 +05:30
|
|
|
layoutManager = `pack(side=${direction === "row" ? "tk.LEFT" : "tk.TOP"})`
|
2024-09-26 11:59:24 +05:30
|
|
|
}else if (parentLayout === Layouts.GRID){
|
|
|
|
|
const row = this.getAttrValue("gridManager.row")
|
|
|
|
|
const col = this.getAttrValue("gridManager.col")
|
|
|
|
|
layoutManager = `grid(row=${row}, col=${col})`
|
|
|
|
|
}else{
|
|
|
|
|
// FIXME: position may not be correct
|
|
|
|
|
layoutManager = `place(x=${this.state.pos.x}, y=${this.state.pos.y})`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return layoutManager
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setParentLayout(parentLayout){
|
|
|
|
|
|
|
|
|
|
const {layout, direction, gap} = parentLayout
|
|
|
|
|
|
2024-09-25 17:27:12 +05:30
|
|
|
// show attributes related to the layout manager
|
|
|
|
|
let updates = {
|
2024-09-26 11:59:24 +05:30
|
|
|
parentLayout: parentLayout,
|
2024-09-25 17:27:12 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.removeAttr("gridManager")
|
|
|
|
|
if (layout === Layouts.FLEX || layout === Layouts.GRID) {
|
|
|
|
|
|
|
|
|
|
updates = {
|
|
|
|
|
...updates,
|
|
|
|
|
positionType: PosType.NONE
|
|
|
|
|
}
|
2024-09-25 19:20:05 +05:30
|
|
|
|
2024-09-26 11:59:24 +05:30
|
|
|
if (parentLayout === Layouts.GRID) {
|
2024-09-25 17:27:12 +05:30
|
|
|
// Set attributes related to grid layout manager
|
|
|
|
|
updates = {
|
|
|
|
|
...updates,
|
|
|
|
|
attrs: {
|
|
|
|
|
...this.state.attrs,
|
|
|
|
|
gridManager: {
|
|
|
|
|
label: "Grid manager",
|
|
|
|
|
display: "horizontal",
|
|
|
|
|
row: {
|
|
|
|
|
label: "Row",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
|
|
|
|
toolProps: { placeholder: "width", max: 1000, min: 1 },
|
|
|
|
|
value: 1,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
|
|
|
|
|
const previousRow = this.getWidgetOuterStyle("gridRow") || "1/1"
|
2024-09-25 19:20:05 +05:30
|
|
|
|
|
|
|
|
let [_row=1, rowSpan=1] = previousRow.replace(/\s+/g, '').split("/").map(Number)
|
|
|
|
|
|
|
|
|
|
if (value > rowSpan){
|
|
|
|
|
// rowSpan should always be greater than or eq to row
|
|
|
|
|
rowSpan = value
|
|
|
|
|
this.setAttrValue("gridManager.rowSpan", rowSpan)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.setAttrValue("gridManager.row", value)
|
2024-09-25 17:27:12 +05:30
|
|
|
this.setWidgetOuterStyle("gridRow", `${value+' / '+rowSpan}`)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
rowSpan: {
|
|
|
|
|
label: "Row span",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
|
|
|
|
toolProps: { placeholder: "height", max: 1000, min: 1 },
|
|
|
|
|
value: 1,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
|
|
|
|
|
const previousRow = this.getWidgetOuterStyle("gridRow") || "1/1"
|
2024-09-25 19:20:05 +05:30
|
|
|
|
2024-09-25 17:27:12 +05:30
|
|
|
const [row=1, _rowSpan=1] = previousRow.replace(/\s+/g, '').split("/").map(Number)
|
2024-09-25 19:20:05 +05:30
|
|
|
|
|
|
|
|
if (value < row){
|
|
|
|
|
value = row + 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.setAttrValue("gridManager.rowSpan", value)
|
2024-09-25 17:27:12 +05:30
|
|
|
this.setWidgetOuterStyle("gridRow", `${row + ' / ' +value}`)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
column: {
|
|
|
|
|
label: "Column",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
|
|
|
|
toolProps: { placeholder: "height", max: 1000, min: 1 },
|
|
|
|
|
value: 1,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
|
|
|
|
|
const previousRow = this.getWidgetOuterStyle("gridColumn") || "1/1"
|
|
|
|
|
|
2024-09-25 19:20:05 +05:30
|
|
|
let [_col=1, colSpan=1] = previousRow.replace(/\s+/g, '').split("/").map(Number)
|
|
|
|
|
|
|
|
|
|
if (value > colSpan){
|
|
|
|
|
// The colSpan has always be equal or greater than col
|
|
|
|
|
colSpan = value
|
|
|
|
|
this.setAttrValue("gridManager.columnSpan", colSpan)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.setAttrValue("gridManager.column", value)
|
2024-09-25 17:27:12 +05:30
|
|
|
this.setWidgetOuterStyle("gridColumn", `${value +' / ' + colSpan}`)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
columnSpan: {
|
|
|
|
|
label: "Column span",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
|
|
|
|
toolProps: { placeholder: "height", max: 1000, min: 1 },
|
|
|
|
|
value: 1,
|
|
|
|
|
onChange: (value) => {
|
2024-09-25 19:20:05 +05:30
|
|
|
|
2024-09-25 17:27:12 +05:30
|
|
|
const previousCol = this.getWidgetOuterStyle("gridColumn") || "1/1"
|
|
|
|
|
|
|
|
|
|
const [col=1, _colSpan=1] = previousCol.replace(/\s+/g, '').split("/").map(Number)
|
|
|
|
|
|
2024-09-25 19:20:05 +05:30
|
|
|
if (value < col){
|
|
|
|
|
value = col + 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.setAttrValue("gridManager.columnSpan", value)
|
2024-09-25 17:27:12 +05:30
|
|
|
this.setWidgetOuterStyle("gridColumn", `${col + ' / ' + value}`)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (layout === Layouts.PLACE) {
|
|
|
|
|
updates = {
|
|
|
|
|
...updates,
|
|
|
|
|
positionType: PosType.ABSOLUTE
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.updateState(updates)
|
|
|
|
|
|
|
|
|
|
return updates
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* loads the data
|
|
|
|
|
* @param {object} data
|
|
|
|
|
*/
|
2024-09-25 23:29:50 +05:30
|
|
|
load(data, callback=null){
|
2024-09-25 17:27:12 +05:30
|
|
|
|
|
|
|
|
if (Object.keys(data).length === 0) return // no data to load
|
|
|
|
|
|
|
|
|
|
data = {...data} // create a shallow copy
|
|
|
|
|
|
|
|
|
|
const {attrs, parentLayout, ...restData} = data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let layoutUpdates = {
|
|
|
|
|
parentLayout: parentLayout
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-26 11:59:24 +05:30
|
|
|
if (parentLayout.layout === Layouts.FLEX || parentLayout.layout === Layouts.GRID){
|
2024-09-25 17:27:12 +05:30
|
|
|
|
|
|
|
|
layoutUpdates = {
|
|
|
|
|
...layoutUpdates,
|
|
|
|
|
positionType: PosType.NONE
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-26 11:59:24 +05:30
|
|
|
}else if (parentLayout.layout === Layouts.PLACE){
|
2024-09-25 17:27:12 +05:30
|
|
|
layoutUpdates = {
|
|
|
|
|
...layoutUpdates,
|
|
|
|
|
positionType: PosType.ABSOLUTE
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const newData = {
|
|
|
|
|
...restData,
|
|
|
|
|
...layoutUpdates
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.setState(newData, () => {
|
2024-09-26 23:16:43 +05:30
|
|
|
let layoutAttrs = this.setParentLayout(parentLayout) || {}
|
2024-09-25 17:27:12 +05:30
|
|
|
|
|
|
|
|
// UPdates attrs
|
|
|
|
|
let newAttrs = { ...this.state.attrs, ...layoutAttrs }
|
|
|
|
|
|
|
|
|
|
// Iterate over each path in the updates object
|
|
|
|
|
Object.entries(attrs).forEach(([path, value]) => {
|
|
|
|
|
const keys = path.split('.')
|
|
|
|
|
const lastKey = keys.pop()
|
|
|
|
|
|
|
|
|
|
// Traverse the nested object within attrs
|
|
|
|
|
let nestedObject = newAttrs
|
|
|
|
|
|
|
|
|
|
keys.forEach(key => {
|
|
|
|
|
nestedObject[key] = { ...nestedObject[key] } // Ensure immutability for each nested level
|
|
|
|
|
nestedObject = nestedObject[key]
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Set the value at the last key
|
|
|
|
|
if (nestedObject[lastKey])
|
|
|
|
|
nestedObject[lastKey].value = value
|
|
|
|
|
})
|
|
|
|
|
|
2024-09-25 23:29:50 +05:30
|
|
|
|
|
|
|
|
if (newAttrs?.styling?.backgroundColor){
|
|
|
|
|
// TODO: find a better way to apply innerStyles
|
|
|
|
|
this.setWidgetInnerStyle("backgroundColor", newAttrs.styling.backgroundColor.value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.updateState({ attrs: newAttrs }, callback)
|
2024-09-25 17:27:12 +05:30
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default TkinterBase
|