2025-03-24 15:50:46 +05:30
|
|
|
import lo from 'lodash'
|
|
|
|
|
|
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"
|
2025-03-24 15:50:46 +05:30
|
|
|
import { DynamicGridWeightInput } from "../../../components/inputs"
|
2025-03-16 10:01:35 +05:30
|
|
|
import { convertObjectToKeyValueString, isNumeric, removeKeyFromObject } from "../../../utils/common"
|
2025-03-18 18:08:25 +05:30
|
|
|
import { randomArrayChoice } from "../../../utils/random"
|
2024-09-27 16:04:03 +05:30
|
|
|
import { Tkinter_TO_WEB_CURSOR_MAPPING } from "../constants/cursor"
|
|
|
|
|
import { Tkinter_To_GFonts } from "../constants/fontFamily"
|
2025-03-26 15:08:25 +05:30
|
|
|
import { ANCHOR, GRID_STICKY, JUSTIFY, RELIEF } from "../constants/styling"
|
2024-09-25 17:27:12 +05:30
|
|
|
|
2024-09-29 19:17:11 +05:30
|
|
|
|
2025-03-24 19:21:50 +05:30
|
|
|
// FIXME: grid sticky may clash with flex sticky when changing layout, check it once
|
|
|
|
|
// FIXME: widget items should add width and height in tkinter code especially in frame
|
2025-03-24 21:04:49 +05:30
|
|
|
// TODO: width and height aren't really fixed
|
2024-09-27 16:04:03 +05:30
|
|
|
export 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)
|
2025-03-18 18:08:25 +05:30
|
|
|
|
2025-03-16 15:43:41 +05:30
|
|
|
this.state = {
|
|
|
|
|
...this.state,
|
2025-03-25 15:34:18 +05:30
|
|
|
packAttrs: { // This is required as during flex layout change remount happens and the state updates my not function as expected
|
2025-03-20 11:25:07 +05:30
|
|
|
side: "top",
|
2025-03-26 15:08:25 +05:30
|
|
|
anchor: "n",
|
2025-03-18 21:29:41 +05:30
|
|
|
}
|
2025-03-16 15:43:41 +05:30
|
|
|
}
|
2025-03-18 18:08:25 +05:30
|
|
|
|
|
|
|
|
this.renderTkinterLayout = this.renderTkinterLayout.bind(this)
|
2024-09-26 11:59:24 +05:30
|
|
|
}
|
|
|
|
|
|
2025-03-18 21:29:41 +05:30
|
|
|
|
2024-09-26 11:59:24 +05:30
|
|
|
getLayoutCode(){
|
2024-09-30 15:30:46 +05:30
|
|
|
const {layout: parentLayout, direction, gap, align="start"} = this.getParentLayout()
|
2024-09-26 11:59:24 +05:30
|
|
|
|
2025-03-24 15:50:46 +05:30
|
|
|
|
2024-09-29 19:17:11 +05:30
|
|
|
const absolutePositioning = this.getAttrValue("positioning")
|
|
|
|
|
|
2024-09-26 11:59:24 +05:30
|
|
|
let layoutManager = `pack()`
|
|
|
|
|
|
2024-09-29 19:17:11 +05:30
|
|
|
if (parentLayout === Layouts.PLACE || absolutePositioning){
|
|
|
|
|
|
|
|
|
|
const config = {
|
2025-03-10 10:37:57 +05:30
|
|
|
x: Math.trunc(this.state.pos.x),
|
|
|
|
|
y: Math.trunc(this.state.pos.y),
|
2024-09-29 19:17:11 +05:30
|
|
|
}
|
|
|
|
|
|
2025-03-10 10:37:57 +05:30
|
|
|
config["width"] = Math.trunc(this.state.size.width)
|
|
|
|
|
config["height"] = Math.trunc(this.state.size.height)
|
2024-09-30 15:30:46 +05:30
|
|
|
|
|
|
|
|
// if (!this.state.fitContent.width){
|
|
|
|
|
// config["width"] = this.state.size.width
|
|
|
|
|
// }
|
|
|
|
|
// if (!this.state.fitContent.height){
|
|
|
|
|
// config["height"] = this.state.size.height
|
|
|
|
|
// }
|
2024-09-29 19:17:11 +05:30
|
|
|
|
|
|
|
|
const configStr = convertObjectToKeyValueString(config)
|
|
|
|
|
|
|
|
|
|
layoutManager = `place(${configStr})`
|
|
|
|
|
|
2024-09-30 15:30:46 +05:30
|
|
|
}else if (parentLayout === Layouts.FLEX){
|
2024-09-29 19:17:11 +05:30
|
|
|
|
2025-03-22 11:11:19 +05:30
|
|
|
const packSide = this.getAttrValue("flexManager.side")
|
|
|
|
|
|
2025-03-26 15:08:25 +05:30
|
|
|
const marginX = this.getAttrValue("margin.marginX")
|
|
|
|
|
const marginY = this.getAttrValue("margin.marginY")
|
|
|
|
|
|
|
|
|
|
const paddingX = this.getAttrValue("padding.padX")
|
|
|
|
|
const paddingY = this.getAttrValue("padding.padY")
|
|
|
|
|
|
2025-03-22 11:11:19 +05:30
|
|
|
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`
|
2024-09-29 19:17:11 +05:30
|
|
|
}
|
|
|
|
|
|
2025-03-26 15:08:25 +05:30
|
|
|
// if (gap > 0){
|
|
|
|
|
// config["padx"] = gap
|
|
|
|
|
// config["pady"] = gap
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
if (marginX){
|
|
|
|
|
config["padx"] = marginX
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (marginY){
|
|
|
|
|
config["pady"] = marginY
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (paddingX){
|
|
|
|
|
config["ipadx"] = paddingX
|
2024-09-30 15:30:46 +05:30
|
|
|
}
|
|
|
|
|
|
2025-03-26 15:08:25 +05:30
|
|
|
if (paddingY){
|
|
|
|
|
config["ipady"] = paddingY
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
// if (align === "start"){
|
|
|
|
|
// config["anchor"] = "'nw'"
|
|
|
|
|
// }else if (align === "center"){
|
|
|
|
|
// config["anchor"] = "'center'"
|
|
|
|
|
// }else if (align === "end"){
|
|
|
|
|
// config["anchor"] = "'se'"
|
|
|
|
|
// }
|
2024-09-30 15:30:46 +05:30
|
|
|
|
2024-09-29 19:17:11 +05:30
|
|
|
const fillX = this.getAttrValue("flexManager.fillX")
|
|
|
|
|
const fillY = this.getAttrValue("flexManager.fillY")
|
|
|
|
|
const expand = this.getAttrValue("flexManager.expand")
|
|
|
|
|
|
|
|
|
|
if (fillX){
|
2024-09-29 20:57:10 +05:30
|
|
|
config['fill'] = `"x"`
|
2024-09-29 19:17:11 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fillY){
|
2024-09-29 20:57:10 +05:30
|
|
|
config['fill'] = `"y"`
|
2024-09-29 19:17:11 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fillX && fillY){
|
2024-09-29 20:57:10 +05:30
|
|
|
config['fill'] = `"both"`
|
2024-09-29 19:17:11 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (expand){
|
2024-09-29 20:57:10 +05:30
|
|
|
config['expand'] = "True"
|
2024-09-29 19:17:11 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layoutManager = `pack(${convertObjectToKeyValueString(config)})`
|
|
|
|
|
|
2024-09-26 11:59:24 +05:30
|
|
|
}else if (parentLayout === Layouts.GRID){
|
|
|
|
|
const row = this.getAttrValue("gridManager.row")
|
2025-03-24 21:04:49 +05:30
|
|
|
const column = this.getAttrValue("gridManager.column")
|
|
|
|
|
const rowSpan = this.getAttrValue("gridManager.rowSpan")
|
|
|
|
|
const columnSpan = this.getAttrValue("gridManager.columnSpan")
|
|
|
|
|
|
|
|
|
|
const sticky = this.getAttrValue("gridManager.sticky")
|
|
|
|
|
|
|
|
|
|
const config = {
|
|
|
|
|
row: row-1, // unlike css grid tkinter grid starts from 0
|
|
|
|
|
column: column-1, // unlike css grid tkinter grid starts from 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rowSpan > 1){
|
|
|
|
|
config['rowspan'] = rowSpan
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (columnSpan > 1){
|
|
|
|
|
config['columnspan'] = columnSpan
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sticky !== ""){
|
2025-03-25 05:24:37 +05:30
|
|
|
config['sticky'] = `"${sticky}"`
|
2025-03-24 21:04:49 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layoutManager = `grid(${convertObjectToKeyValueString(config)})`
|
2024-09-26 11:59:24 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return layoutManager
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-24 15:50:46 +05:30
|
|
|
|
|
|
|
|
getGridLayoutConfigurationCode = (variableName) => {
|
|
|
|
|
const {layout: currentLayout} = this.getLayout()
|
|
|
|
|
|
|
|
|
|
let columnConfigure = []
|
|
|
|
|
let rowConfigure = []
|
|
|
|
|
|
|
|
|
|
if (currentLayout === Layouts.GRID){
|
|
|
|
|
|
|
|
|
|
const rowWeights = this.getAttrValue("gridWeights.rowWeights")
|
|
|
|
|
const colWeights = this.getAttrValue("gridWeights.colWeights")
|
|
|
|
|
|
|
|
|
|
if (rowWeights){
|
|
|
|
|
const correctedRowWeight = Object.fromEntries(
|
2025-03-24 19:21:50 +05:30
|
|
|
Object.entries(rowWeights).map(([_, { gridNo, weight }]) => [gridNo-1, weight]) // tkinter grid starts from 0 unlike css grid
|
2025-03-24 15:50:46 +05:30
|
|
|
);// converts the format : {index: {gridNo, weight}} to {gridNo: weight}
|
|
|
|
|
|
|
|
|
|
const groupByWeight = Object.entries(correctedRowWeight).reduce((acc, [gridNo, weight]) => {
|
|
|
|
|
if (!acc[weight])
|
|
|
|
|
acc[weight] = []; // Initialize array if it doesn't exist
|
|
|
|
|
|
|
|
|
|
acc[weight].push(Number(gridNo)); // Convert key to number and add it to the array
|
|
|
|
|
return acc;
|
|
|
|
|
}, {})
|
|
|
|
|
|
|
|
|
|
Object.entries(groupByWeight).forEach(([weight, indices]) => {
|
|
|
|
|
rowConfigure.push(`${variableName}.grid_rowconfigure(index=[${indices.join(",")}], weight=${weight})`)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (colWeights){
|
|
|
|
|
const correctedColWeight = Object.fromEntries(
|
2025-03-24 19:21:50 +05:30
|
|
|
Object.entries(colWeights).map(([_, { gridNo, weight }]) => [gridNo-1, weight]) // tkinter grid starts from 0, so -1
|
2025-03-25 05:24:37 +05:30
|
|
|
) // converts the format : {index: {gridNo, weight}} to {gridNo: weight}
|
2025-03-24 15:50:46 +05:30
|
|
|
|
|
|
|
|
const groupByWeight = Object.entries(correctedColWeight).reduce((acc, [gridNo, weight]) => {
|
|
|
|
|
if (!acc[weight])
|
2025-03-25 05:24:37 +05:30
|
|
|
acc[weight] = [] // Initialize array if it doesn't exist
|
2025-03-24 15:50:46 +05:30
|
|
|
|
2025-03-25 05:24:37 +05:30
|
|
|
acc[weight].push(Number(gridNo)) // Convert key to number and add it to the array
|
|
|
|
|
return acc
|
2025-03-24 15:50:46 +05:30
|
|
|
}, {})
|
|
|
|
|
|
|
|
|
|
Object.entries(groupByWeight).forEach(([weight, indices]) => {
|
|
|
|
|
columnConfigure.push(`${variableName}.grid_columnconfigure(index=[${indices.join(",")}], weight=${weight})`)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [...rowConfigure, ...columnConfigure]
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
getPackAttrs = () => {
|
2025-03-18 18:08:25 +05:30
|
|
|
return ({
|
2025-03-18 21:29:41 +05:30
|
|
|
side: this.state.packAttrs.side,
|
|
|
|
|
anchor: this.state.packAttrs.anchor,
|
2025-03-25 15:34:18 +05:30
|
|
|
expand: this.getAttrValue("flexManager.expand"),
|
2025-03-18 18:08:25 +05:30
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-24 15:50:46 +05:30
|
|
|
/**
|
|
|
|
|
* A simple function that returns a mapping for grid sticky tkinter
|
|
|
|
|
*/
|
|
|
|
|
getGridStickyStyling(sticky){
|
|
|
|
|
|
|
|
|
|
const styleMapping = {
|
2025-03-24 21:04:49 +05:30
|
|
|
[GRID_STICKY.N]: { alignSelf: "start", justifySelf: "center" },
|
|
|
|
|
[GRID_STICKY.S]: { alignSelf: "end", justifySelf: "center" },
|
|
|
|
|
[GRID_STICKY.E]: { alignSelf: "center", justifySelf: "end" },
|
|
|
|
|
[GRID_STICKY.W]: { alignSelf: "center", justifySelf: "start" },
|
|
|
|
|
[GRID_STICKY.NS]: { alignSelf: "stretch", justifySelf: "center" }, // Stretch vertically
|
|
|
|
|
[GRID_STICKY.EW]: { alignSelf: "center", justifySelf: "stretch" }, // Stretch horizontally
|
|
|
|
|
[GRID_STICKY.NE]: { alignSelf: "start", justifySelf: "end" }, // Top-right
|
|
|
|
|
[GRID_STICKY.SE]: { alignSelf: "end", justifySelf: "end" }, // Bottom-right
|
|
|
|
|
[GRID_STICKY.NW]: { alignSelf: "start", justifySelf: "start" }, // Top-left
|
|
|
|
|
[GRID_STICKY.SW]: { alignSelf: "end", justifySelf: "start" }, // Bottom-left
|
|
|
|
|
[GRID_STICKY.NEWS]: { placeSelf: "stretch" } // Stretch in all directions
|
2025-03-24 15:50:46 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return styleMapping[sticky]
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-27 23:27:07 +05:30
|
|
|
setParentLayout(layout){
|
2024-09-26 11:59:24 +05:30
|
|
|
|
2024-09-27 23:27:07 +05:30
|
|
|
if (!layout){
|
2024-09-27 16:04:03 +05:30
|
|
|
return {}
|
|
|
|
|
}
|
2025-03-22 11:11:19 +05:30
|
|
|
let updates = super.setParentLayout(layout)
|
2024-09-27 16:04:03 +05:30
|
|
|
|
2024-09-27 23:27:07 +05:30
|
|
|
const {layout: parentLayout, direction, gap} = layout
|
2024-09-26 11:59:24 +05:30
|
|
|
|
2024-09-25 17:27:12 +05:30
|
|
|
// show attributes related to the layout manager
|
2024-09-29 23:34:26 +05:30
|
|
|
// remove gridManager, flexManager positioning
|
|
|
|
|
const {gridManager, flexManager, positioning, ...restAttrs} = this.state.attrs
|
|
|
|
|
|
2024-09-27 23:27:07 +05:30
|
|
|
if (parentLayout === Layouts.FLEX || parentLayout === Layouts.GRID) {
|
2024-09-25 17:27:12 +05:30
|
|
|
|
|
|
|
|
updates = {
|
|
|
|
|
...updates,
|
2025-03-08 12:02:00 +05:30
|
|
|
// pos: pos,
|
2024-09-29 19:17:11 +05:30
|
|
|
positionType: PosType.NONE,
|
|
|
|
|
}
|
|
|
|
|
// Allow optional absolute positioning if the parent layout is flex or grid
|
|
|
|
|
const updateAttrs = {
|
2024-09-29 23:34:26 +05:30
|
|
|
...restAttrs,
|
2024-09-29 19:17:11 +05:30
|
|
|
positioning: {
|
|
|
|
|
label: "Absolute positioning",
|
|
|
|
|
tool: Tools.CHECK_BUTTON,
|
|
|
|
|
value: false,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
this.setAttrValue("positioning", value)
|
|
|
|
|
|
|
|
|
|
this.updateState({
|
|
|
|
|
positionType: value ? PosType.ABSOLUTE : PosType.NONE,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-09-25 17:27:12 +05:30
|
|
|
}
|
2024-09-25 19:20:05 +05:30
|
|
|
|
2024-09-29 17:51:42 +05:30
|
|
|
if (parentLayout === Layouts.FLEX){
|
|
|
|
|
updates = {
|
|
|
|
|
...updates,
|
|
|
|
|
attrs: {
|
2024-09-29 19:17:11 +05:30
|
|
|
...updateAttrs,
|
2024-09-29 17:51:42 +05:30
|
|
|
flexManager: {
|
2025-03-16 10:01:35 +05:30
|
|
|
label: "Pack Manager",
|
2024-09-29 17:51:42 +05:30
|
|
|
display: "horizontal",
|
|
|
|
|
fillX: {
|
|
|
|
|
label: "Fill X",
|
|
|
|
|
tool: Tools.CHECK_BUTTON,
|
|
|
|
|
value: false,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
this.setAttrValue("flexManager.fillX", value)
|
2024-09-29 19:17:11 +05:30
|
|
|
|
2025-03-16 15:43:41 +05:30
|
|
|
this.updateState((prevState) => ({
|
|
|
|
|
widgetOuterStyling: {
|
|
|
|
|
...prevState.widgetOuterStyling,
|
|
|
|
|
width: "100%"
|
|
|
|
|
}
|
|
|
|
|
}))
|
2024-09-29 17:51:42 +05:30
|
|
|
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
fillY: {
|
|
|
|
|
label: "Fill Y",
|
|
|
|
|
tool: Tools.CHECK_BUTTON,
|
|
|
|
|
value: false,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
this.setAttrValue("flexManager.fillY", value)
|
|
|
|
|
|
2025-03-16 15:43:41 +05:30
|
|
|
this.updateState((prevState) => ({
|
|
|
|
|
widgetOuterStyling: {
|
|
|
|
|
...prevState.widgetOuterStyling,
|
|
|
|
|
height: "100%"
|
|
|
|
|
}
|
|
|
|
|
}))
|
2024-09-29 17:51:42 +05:30
|
|
|
}
|
|
|
|
|
},
|
2025-03-21 09:10:48 +05:30
|
|
|
side: {
|
|
|
|
|
label: "Align Side",
|
|
|
|
|
tool: Tools.SELECT_DROPDOWN,
|
|
|
|
|
options: ["left", "right", "top", "bottom", ""].map(val => ({value: val, label: val})),
|
|
|
|
|
value: this.state.packAttrs.side,
|
2024-09-29 17:51:42 +05:30
|
|
|
onChange: (value) => {
|
2025-03-21 09:10:48 +05:30
|
|
|
this.setAttrValue("flexManager.side", value, () => {
|
|
|
|
|
this.updateState((prevState) => ({packAttrs: {...prevState.packAttrs, side: value}}), () => {
|
2025-03-25 15:34:18 +05:30
|
|
|
|
|
|
|
|
// this.props.parentWidgetRef.current.forceRerender()
|
2025-03-21 09:10:48 +05:30
|
|
|
this.props.requestWidgetDataUpdate(this.props.parentWidgetRef.current.__id)
|
|
|
|
|
this.stateChangeSubscriberCallback() // call this to notify the toolbar that the widget has changed state
|
|
|
|
|
})
|
2025-03-25 15:34:18 +05:30
|
|
|
|
|
|
|
|
|
2024-09-29 17:51:42 +05:30
|
|
|
})
|
2025-03-21 09:10:48 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
// console.log("updateing state: ", value, this.props.parentWidgetRef.current)
|
2024-09-29 17:51:42 +05:30
|
|
|
}
|
|
|
|
|
},
|
2025-03-25 15:34:18 +05:30
|
|
|
expand: {
|
|
|
|
|
label: "Expand",
|
|
|
|
|
tool: Tools.CHECK_BUTTON,
|
|
|
|
|
value: false,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
this.setAttrValue("flexManager.expand", value)
|
|
|
|
|
|
|
|
|
|
// this.setWidgetOuterStyle(value ? 1 : 0)
|
|
|
|
|
}
|
|
|
|
|
},
|
2025-03-26 15:08:25 +05:30
|
|
|
anchor: {
|
|
|
|
|
label: "Anchor",
|
|
|
|
|
tool: Tools.SELECT_DROPDOWN,
|
|
|
|
|
options: ANCHOR.map(val => ({value: val, label: val})),
|
|
|
|
|
value: this.state.packAttrs.anchor,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
this.setAttrValue("flexManager.anchor", value, () => {
|
|
|
|
|
console.log("set anchor: ", this.state.attrs.flexManager)
|
|
|
|
|
// this.props.parentWidgetRef.current.forceRerender()
|
|
|
|
|
})
|
|
|
|
|
this.updateState((prevState) => ({packAttrs: {...prevState.packAttrs, anchor: value}}), () => {
|
|
|
|
|
|
|
|
|
|
// this.props.requestWidgetDataUpdate(this.props.parentWidgetRef.current.__id)
|
|
|
|
|
|
|
|
|
|
// this.props.requestWidgetDataUpdate(this.__id)
|
|
|
|
|
// this.stateChangeSubscriberCallback() // call this to notify the toolbar that the widget has changed state
|
|
|
|
|
// this.props.parentWidgetRef.current.forceRerender()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
},
|
2024-09-29 17:51:42 +05:30
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (parentLayout === Layouts.GRID) {
|
2024-09-25 17:27:12 +05:30
|
|
|
// Set attributes related to grid layout manager
|
|
|
|
|
updates = {
|
|
|
|
|
...updates,
|
|
|
|
|
attrs: {
|
2024-09-29 19:17:11 +05:30
|
|
|
...updateAttrs,
|
2024-09-25 17:27:12 +05:30
|
|
|
gridManager: {
|
|
|
|
|
label: "Grid manager",
|
|
|
|
|
display: "horizontal",
|
|
|
|
|
row: {
|
|
|
|
|
label: "Row",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
2025-03-24 19:21:50 +05:30
|
|
|
toolProps: { placeholder: "row", max: 1000, min: 1 },
|
2025-03-23 19:02:54 +05:30
|
|
|
value: 0,
|
2024-09-25 17:27:12 +05:30
|
|
|
onChange: (value) => {
|
|
|
|
|
|
2025-03-24 19:21:50 +05:30
|
|
|
const previousRow = this.getWidgetOuterStyle("gridRow") || "1 / span 1"
|
2025-03-23 19:02:54 +05:30
|
|
|
let [_row=1, rowSpan=1] = previousRow.replace(/\s+/g, '').split("/span").map(Number)
|
2024-09-25 19:20:05 +05:30
|
|
|
|
|
|
|
|
this.setAttrValue("gridManager.row", value)
|
2025-03-23 19:02:54 +05:30
|
|
|
this.setWidgetOuterStyle("gridRow", `${value+' / span '+rowSpan}`)
|
2024-09-25 17:27:12 +05:30
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
rowSpan: {
|
|
|
|
|
label: "Row span",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
2025-03-23 19:02:54 +05:30
|
|
|
toolProps: { placeholder: "row span", max: 1000, min: 1 },
|
2024-09-25 17:27:12 +05:30
|
|
|
value: 1,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
|
2025-03-23 19:02:54 +05:30
|
|
|
const previousRow = this.getWidgetOuterStyle("gridRow") || "1 / span 1"
|
2024-09-25 19:20:05 +05:30
|
|
|
|
2025-03-23 19:02:54 +05:30
|
|
|
// const [row=1, _rowSpan=1] = previousRow.replace(/\s+/g, '').split("/").map(Number)
|
|
|
|
|
const [row=1, rowSpan=1] = previousRow.replace(/\s+/g, '').split("/span").map(Number)
|
2024-09-25 19:20:05 +05:30
|
|
|
|
2025-03-23 19:02:54 +05:30
|
|
|
// if (value < row){
|
|
|
|
|
// value = row + 1
|
|
|
|
|
// }
|
|
|
|
|
if (value < 1){
|
|
|
|
|
value = 1
|
2024-09-25 19:20:05 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.setAttrValue("gridManager.rowSpan", value)
|
2025-03-23 19:02:54 +05:30
|
|
|
this.setWidgetOuterStyle("gridRow", `${(row || 1) + ' / span ' +value}`)
|
2024-09-25 17:27:12 +05:30
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
column: {
|
|
|
|
|
label: "Column",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
2025-03-24 19:21:50 +05:30
|
|
|
toolProps: { placeholder: "column", max: 1000, min: 1 },
|
2025-03-23 19:02:54 +05:30
|
|
|
value: 0,
|
2024-09-25 17:27:12 +05:30
|
|
|
onChange: (value) => {
|
|
|
|
|
|
2025-03-24 19:21:50 +05:30
|
|
|
const previousRow = this.getWidgetOuterStyle("gridColumn") || "1 / span 1"
|
2024-09-25 17:27:12 +05:30
|
|
|
|
2025-03-23 19:02:54 +05:30
|
|
|
let [_col=1, colSpan=1] = previousRow.replace(/\s+/g, '').split("/span").map(Number)
|
2024-09-25 19:20:05 +05:30
|
|
|
|
2025-03-23 19:02:54 +05:30
|
|
|
// if (value > colSpan){
|
|
|
|
|
// // The colSpan has always be equal or greater than col
|
|
|
|
|
// colSpan = value
|
|
|
|
|
// this.setAttrValue("gridManager.columnSpan", colSpan)
|
|
|
|
|
// }
|
2024-09-25 19:20:05 +05:30
|
|
|
|
|
|
|
|
this.setAttrValue("gridManager.column", value)
|
2025-03-23 19:02:54 +05:30
|
|
|
this.setWidgetOuterStyle("gridColumn", `${value +' / span ' + colSpan}`)
|
2024-09-25 17:27:12 +05:30
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
columnSpan: {
|
|
|
|
|
label: "Column span",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
2025-03-23 19:02:54 +05:30
|
|
|
toolProps: { placeholder: "column span", max: 1000, min: 1 },
|
2024-09-25 17:27:12 +05:30
|
|
|
value: 1,
|
|
|
|
|
onChange: (value) => {
|
2024-09-25 19:20:05 +05:30
|
|
|
|
2025-03-23 19:02:54 +05:30
|
|
|
const previousCol = this.getWidgetOuterStyle("gridColumn") || "1 / span 1"
|
2024-09-25 17:27:12 +05:30
|
|
|
|
2025-03-23 19:02:54 +05:30
|
|
|
const [col=1, _colSpan=1] = previousCol.replace(/\s+/g, '').split("/span").map(Number)
|
2024-09-25 17:27:12 +05:30
|
|
|
|
2025-03-23 19:02:54 +05:30
|
|
|
|
|
|
|
|
if (value < 1){
|
|
|
|
|
value = 1
|
2024-09-25 19:20:05 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.setAttrValue("gridManager.columnSpan", value)
|
2025-03-23 19:02:54 +05:30
|
|
|
this.setWidgetOuterStyle("gridColumn", `${(col || 1) + ' / span ' + value}`)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
sticky: {
|
|
|
|
|
label: "Sticky",
|
|
|
|
|
tool: Tools.SELECT_DROPDOWN,
|
|
|
|
|
toolProps: { placeholder: "Sticky", },
|
2025-03-24 19:21:50 +05:30
|
|
|
options: Object.values(GRID_STICKY).map((val) => ({value: val, label: val})),
|
2025-03-23 19:02:54 +05:30
|
|
|
value: GRID_STICKY.NONE,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
|
|
|
|
|
this.setAttrValue("gridManager.sticky", value)
|
|
|
|
|
|
2025-03-24 19:21:50 +05:30
|
|
|
|
2025-03-24 21:04:49 +05:30
|
|
|
this.updateState((prev) => {
|
|
|
|
|
|
|
|
|
|
const { alignSelf, justifySelf, placeSelf, ...restStates } = prev.widgetOuterStyling; // Remove these properties
|
|
|
|
|
|
|
|
|
|
return ({
|
|
|
|
|
widgetOuterStyling: {
|
|
|
|
|
...restStates,
|
|
|
|
|
...this.getGridStickyStyling(value)
|
|
|
|
|
}
|
|
|
|
|
})
|
2025-03-24 15:50:46 +05:30
|
|
|
})
|
2025-03-24 19:21:50 +05:30
|
|
|
|
2025-03-24 15:50:46 +05:30
|
|
|
// this.setW
|
|
|
|
|
|
2024-09-25 17:27:12 +05:30
|
|
|
}
|
2025-03-24 15:50:46 +05:30
|
|
|
}
|
2024-09-25 17:27:12 +05:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-27 23:27:07 +05:30
|
|
|
} else if (parentLayout === Layouts.PLACE) {
|
2024-09-25 17:27:12 +05:30
|
|
|
updates = {
|
|
|
|
|
...updates,
|
|
|
|
|
positionType: PosType.ABSOLUTE
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
|
2025-03-18 21:29:41 +05:30
|
|
|
this.updateState((prevState) => ({...prevState, ...updates}))
|
2025-03-16 10:01:35 +05:30
|
|
|
|
2024-09-25 17:27:12 +05:30
|
|
|
|
|
|
|
|
return updates
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-18 21:29:41 +05:30
|
|
|
getFlexLayoutStyle = (side, anchor) => {
|
2025-03-21 09:10:48 +05:30
|
|
|
// NOTE: may no longer be required
|
2025-03-18 21:29:41 +05:30
|
|
|
// let baseStyle = { display: "flex", width: "100%", height: "100%", ...this.getPackAnchorStyle(anchor) }
|
|
|
|
|
let baseStyle = { }
|
2025-03-16 10:01:35 +05:30
|
|
|
|
|
|
|
|
const rowStyle = {
|
|
|
|
|
display: "flex",
|
2025-03-20 11:25:07 +05:30
|
|
|
gap: "10px",
|
2025-03-16 10:01:35 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const columnStyle = {
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexDirection: "column",
|
2025-03-20 11:25:07 +05:30
|
|
|
gap: "10px",
|
2025-03-16 10:01:35 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (side) {
|
2025-03-16 15:43:41 +05:30
|
|
|
case "top":
|
2025-03-20 11:25:07 +05:30
|
|
|
return { gridColumn: "1 / -1", alignSelf: "stretch", ...baseStyle, ...columnStyle };
|
2025-03-16 15:43:41 +05:30
|
|
|
case "bottom":
|
2025-03-20 11:25:07 +05:30
|
|
|
return { gridColumn: "1 / -1", alignSelf: "stretch", ...baseStyle, ...columnStyle };
|
2025-03-16 15:43:41 +05:30
|
|
|
case "left":
|
2025-03-20 11:25:07 +05:30
|
|
|
return { gridRow: "2", gridColumn: "1", justifySelf: "stretch", ...baseStyle, ...rowStyle };
|
2025-03-16 15:43:41 +05:30
|
|
|
case "right":
|
2025-03-20 11:25:07 +05:30
|
|
|
return { gridRow: "2", gridColumn: "3", justifySelf: "stretch", ...baseStyle, ...rowStyle };
|
2025-03-16 15:43:41 +05:30
|
|
|
case "center":
|
2025-03-18 21:29:41 +05:30
|
|
|
return { gridRow: "2", gridColumn: "2", alignSelf: "center", justifySelf: "center", ...baseStyle, };
|
2025-03-16 15:43:41 +05:30
|
|
|
default:
|
|
|
|
|
return {};
|
2025-03-16 10:01:35 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-18 21:29:41 +05:30
|
|
|
/**
|
|
|
|
|
* Pack manager has anchor parameter
|
|
|
|
|
* @param {*} anchor
|
|
|
|
|
*/
|
|
|
|
|
getPackAnchorStyle = (anchor, isColumn) => {
|
2025-03-21 09:10:48 +05:30
|
|
|
// NOTE: may no longer be required
|
2025-03-18 21:29:41 +05:30
|
|
|
const styleMap = {
|
|
|
|
|
nw: { justifyContent: "flex-start", alignItems: "flex-start" },
|
|
|
|
|
ne: { justifyContent: "flex-end", alignItems: "flex-start" },
|
|
|
|
|
sw: { justifyContent: "flex-start", alignItems: "flex-end" },
|
|
|
|
|
se: { justifyContent: "flex-end", alignItems: "flex-end" },
|
|
|
|
|
center: { justifyContent: "center", alignItems: "center" }
|
|
|
|
|
}
|
|
|
|
|
// return styleMap[anchor] || {}
|
|
|
|
|
|
|
|
|
|
const baseStyle = styleMap[anchor] || {};
|
|
|
|
|
const fillX = this.getAttrValue("flexManager.fillX")
|
|
|
|
|
const fillY = this.getAttrValue("flexManager.fillY")
|
|
|
|
|
|
|
|
|
|
if (fillX) {
|
|
|
|
|
return { ...baseStyle, width: "100%", flexGrow: isColumn ? 0 : 1 };
|
|
|
|
|
}
|
|
|
|
|
if (fillY) {
|
|
|
|
|
return { ...baseStyle, height: "100%", flexGrow: isColumn ? 1 : 0 };
|
|
|
|
|
}
|
|
|
|
|
if (fillX && fillY) {
|
|
|
|
|
return { ...baseStyle, width: "100%", height: "100%", flexGrow: 1 };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
...baseStyle, alignSelf: "stretch", // Forces stretching in grid rows
|
|
|
|
|
justifySelf: "stretch", // Forces stretching in grid columns
|
2025-03-20 11:25:07 +05:30
|
|
|
flexGrow: (fillX || fillY) ? 1 : 0
|
2025-03-25 15:34:18 +05:30
|
|
|
}
|
2025-03-18 21:29:41 +05:30
|
|
|
}
|
2025-03-20 11:25:07 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* adds the layout to achieve the pack from tkinter refer: https://www.youtube.com/watch?v=rbW1iJO1psk
|
|
|
|
|
* @param {*} widgets
|
|
|
|
|
* @param {*} index
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
2025-03-26 15:08:25 +05:30
|
|
|
renderPackWidgetsRecursively = (widgets, index = 0, lastSide = "", previousExpandValue = 0) => {
|
|
|
|
|
if (index >= widgets.length) return null;
|
|
|
|
|
|
|
|
|
|
const widget = widgets[index];
|
|
|
|
|
const widgetRef = widget.ref?.current;
|
|
|
|
|
if (!widgetRef) return null; // Ensure ref exists before accessing
|
|
|
|
|
|
|
|
|
|
const { side = "top", expand = false, anchor } = widgetRef.getPackAttrs() || {};
|
|
|
|
|
|
|
|
|
|
console.log("rerendering:", side, expand);
|
|
|
|
|
|
|
|
|
|
const directionMap = {
|
|
|
|
|
top: "column",
|
|
|
|
|
bottom: "column-reverse",
|
|
|
|
|
left: "row",
|
|
|
|
|
right: "row-reverse",
|
2025-03-20 11:25:07 +05:30
|
|
|
}
|
2025-03-26 15:08:25 +05:30
|
|
|
|
|
|
|
|
const currentWidgetDirection = directionMap[side] || "column"; // Default to "column"
|
|
|
|
|
const isSameSide = lastSide === side;
|
|
|
|
|
const isVertical = ["top", "bottom"].includes(side);
|
|
|
|
|
|
|
|
|
|
let expandValue = expand ? (isSameSide ? previousExpandValue : widgets.length - index) : 1;
|
|
|
|
|
if (expand && !isSameSide) previousExpandValue = expandValue;
|
|
|
|
|
|
|
|
|
|
lastSide = side; // Update last side for recursion
|
2025-03-25 15:34:18 +05:30
|
|
|
|
2025-03-26 15:08:25 +05:30
|
|
|
// 🟢 Mapping Tkinter anchors to Flexbox styles
|
|
|
|
|
const anchorStyles = {
|
|
|
|
|
n: { alignItems: "flex-start", justifyContent: "center" }, // Top-center
|
|
|
|
|
s: { alignItems: "flex-end", justifyContent: "center" }, // Bottom-center
|
|
|
|
|
e: { alignItems: "center", justifyContent: "flex-end" }, // Right-center
|
|
|
|
|
w: { alignItems: "center", justifyContent: "flex-start" }, // Left-center
|
|
|
|
|
ne: { alignItems: "flex-start", justifyContent: "flex-end" }, // Top-right
|
|
|
|
|
nw: { alignItems: "flex-start", justifyContent: "flex-start" }, // Top-left
|
|
|
|
|
se: { alignItems: "flex-end", justifyContent: "flex-end" }, // Bottom-right
|
|
|
|
|
sw: { alignItems: "flex-end", justifyContent: "flex-start" }, // Bottom-left
|
|
|
|
|
center: { alignItems: "center", justifyContent: "center" }, // Fully centered
|
|
|
|
|
};
|
|
|
|
|
const { justifyContent, alignItems } = anchorStyles[anchor] || anchorStyles["n"]
|
2025-03-20 11:25:07 +05:30
|
|
|
|
|
|
|
|
|
2025-03-26 15:08:25 +05:30
|
|
|
const stretchClass = isVertical ? "tw-flex-grow" : "tw-h-full"; // Allow only horizontal growth for top/bottom
|
|
|
|
|
|
2025-03-20 11:25:07 +05:30
|
|
|
if (isSameSide) {
|
|
|
|
|
return (
|
|
|
|
|
<>
|
2025-03-26 15:08:25 +05:30
|
|
|
<div
|
|
|
|
|
className={`tw-flex tw-justify-center tw-items-center ${stretchClass}`}
|
2025-03-25 15:34:18 +05:30
|
|
|
style={{
|
2025-03-26 15:08:25 +05:30
|
|
|
flexGrow: expand ? expandValue : 0, // Prevent vertical stretching
|
|
|
|
|
flexShrink: expand ? 0 : 1, // Prevent collapse when expanding
|
|
|
|
|
flexBasis: "auto",
|
|
|
|
|
minWidth: isVertical ? "0" : "auto",
|
|
|
|
|
minHeight: !isVertical ? "0" : "auto",
|
|
|
|
|
// alignSelf,
|
|
|
|
|
// justifySelf,
|
|
|
|
|
alignItems,
|
|
|
|
|
justifyContent
|
2025-03-25 15:34:18 +05:30
|
|
|
}}
|
2025-03-26 15:08:25 +05:30
|
|
|
>
|
2025-03-20 11:25:07 +05:30
|
|
|
{widget}
|
|
|
|
|
</div>
|
2025-03-26 15:08:25 +05:30
|
|
|
|
2025-03-25 15:34:18 +05:30
|
|
|
{this.renderPackWidgetsRecursively(widgets, index + 1, side, previousExpandValue)}
|
2025-03-20 11:25:07 +05:30
|
|
|
</>
|
2025-03-26 15:08:25 +05:30
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
data-pack-container={side}
|
|
|
|
|
className={`tw-flex ${isVertical ? "!tw-h-full" : "!tw-w-full"}`}
|
|
|
|
|
style={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexDirection: currentWidgetDirection,
|
|
|
|
|
flexGrow: expand ? expandValue : 1, //((widgets.length - 1) === index) ? 1 : 0, // last index will always have flex-grow 1
|
|
|
|
|
flexShrink: expand ? 0 : 1,
|
|
|
|
|
flexBasis: "auto",
|
|
|
|
|
minWidth: isVertical ? "0" : "auto",
|
|
|
|
|
minHeight: !isVertical ? "0" : "auto",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
className={`tw-flex ${isVertical ? "tw-flex-grow" : "tw-h-full"}
|
|
|
|
|
tw-justify-center tw-items-center`}
|
2025-03-25 15:34:18 +05:30
|
|
|
style={{
|
2025-03-26 15:08:25 +05:30
|
|
|
flexGrow: expand ? expandValue : 0,
|
|
|
|
|
flexShrink: expand ? 0 : 1,
|
|
|
|
|
flexBasis: "auto",
|
|
|
|
|
minWidth: isVertical ? "0" : "auto",
|
|
|
|
|
minHeight: !isVertical ? "0" : "auto",
|
|
|
|
|
// alignSelf,
|
|
|
|
|
// justifySelf,
|
|
|
|
|
alignItems,
|
|
|
|
|
justifyContent
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{widget}
|
2025-03-20 11:25:07 +05:30
|
|
|
</div>
|
2025-03-26 15:08:25 +05:30
|
|
|
|
|
|
|
|
{this.renderPackWidgetsRecursively(widgets, index + 1, side, previousExpandValue)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-20 11:25:07 +05:30
|
|
|
|
2025-03-18 21:29:41 +05:30
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* Helps with pack layout manager and grid manager
|
|
|
|
|
*/
|
|
|
|
|
renderTkinterLayout(){
|
|
|
|
|
const {layout, direction, gap} = this.getLayout()
|
2025-03-24 15:50:46 +05:30
|
|
|
|
2025-03-18 21:29:41 +05:30
|
|
|
if (layout === Layouts.FLEX){
|
2025-03-20 11:25:07 +05:30
|
|
|
|
|
|
|
|
|
2025-03-18 21:29:41 +05:30
|
|
|
return (
|
|
|
|
|
<>
|
2025-03-20 11:25:07 +05:30
|
|
|
{this.renderPackWidgetsRecursively(this.props.children)}
|
2025-03-18 21:29:41 +05:30
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
return (<>{this.props.children}</>)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
setLayout(value) {
|
|
|
|
|
const { layout, direction, grid = { rows: 1, cols: 1 }, gap = 10, align } = value
|
|
|
|
|
|
2025-03-26 15:08:25 +05:30
|
|
|
// FIXME: when the layout changes the data is lost
|
2025-03-23 19:02:54 +05:30
|
|
|
|
|
|
|
|
if (layout === Layouts.GRID){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const {gridManager, flexManager, positioning, ...restAttrs} = this.state.attrs
|
|
|
|
|
|
|
|
|
|
const updates = {
|
|
|
|
|
attrs: {
|
|
|
|
|
...restAttrs,
|
|
|
|
|
gridConfig: {
|
|
|
|
|
label: "Grid Configure",
|
|
|
|
|
display: "horizontal",
|
|
|
|
|
noOfRows: {
|
|
|
|
|
label: "No of rows",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
|
|
|
|
toolProps: { placeholder: "no of rows", max: 1000, min: 1 },
|
|
|
|
|
value: 3,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
this.setAttrValue("gridConfig.noOfRows", value)
|
|
|
|
|
|
2025-03-24 15:50:46 +05:30
|
|
|
const gridWeights = this.getAttrValue("gridConfig.rowWeights")
|
|
|
|
|
|
|
|
|
|
let gridTemplateRows = `repeat(${value}, max-content)`
|
|
|
|
|
|
|
|
|
|
if (gridWeights){
|
|
|
|
|
gridTemplateRows = Array.from({ length: value }, (_, i) =>
|
|
|
|
|
`${gridWeights[i + 1]}fr` || "max-content"
|
|
|
|
|
).join(" ") // creates "max-content max-content 1fr 3fr" depending on value
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-26 15:08:25 +05:30
|
|
|
this.updateState((prev) => ({
|
|
|
|
|
widgetInnerStyling: {
|
|
|
|
|
...prev.widgetInnerStyling,
|
2025-03-24 15:50:46 +05:30
|
|
|
gridTemplateRows: gridTemplateRows
|
2025-03-26 15:08:25 +05:30
|
|
|
}
|
|
|
|
|
}))
|
2025-03-23 19:02:54 +05:30
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
noOfCols: {
|
|
|
|
|
label: "No of cols",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
|
|
|
|
toolProps: { placeholder: "no of cols", max: 1000, min: 1 },
|
|
|
|
|
value: 3,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
this.setAttrValue("gridConfig.noOfCols", value)
|
|
|
|
|
|
2025-03-26 15:08:25 +05:30
|
|
|
this.updateState((prev) => ({
|
|
|
|
|
widgetInnerStyling: {
|
|
|
|
|
...prev.widgetInnerStyling,
|
|
|
|
|
gridTemplateColumns: `repeat(${value}, max-content)`
|
|
|
|
|
}
|
|
|
|
|
}))
|
2025-03-23 19:02:54 +05:30
|
|
|
}
|
|
|
|
|
},
|
2025-03-24 15:50:46 +05:30
|
|
|
|
2025-03-23 19:02:54 +05:30
|
|
|
},
|
2025-03-24 15:50:46 +05:30
|
|
|
gridWeights: {
|
|
|
|
|
label: "Grid weights",
|
|
|
|
|
display: "vertical",
|
|
|
|
|
rowWeights: {
|
|
|
|
|
label: "Row weights",
|
|
|
|
|
tool: Tools.CUSTOM,
|
|
|
|
|
toolProps: {
|
|
|
|
|
// placeholder: "weight",
|
|
|
|
|
// defaultWeightMapping: this.getAttrValue("gridWeights.rowWeights"),
|
|
|
|
|
},
|
|
|
|
|
value: undefined,
|
|
|
|
|
Component: DynamicGridWeightInput,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
|
|
|
|
|
if (!value) return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.setAttrValue("gridWeights.rowWeights", value)
|
|
|
|
|
|
|
|
|
|
const noOfRows = this.getAttrValue("gridConfig.noOfRows")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const gridTemplateRows = Array.from({ length: noOfRows }, (_, i) => {
|
|
|
|
|
const row = value[i] // Get the row object
|
|
|
|
|
return row ? `${row.weight}fr` : "max-content"; // Use weight if available
|
|
|
|
|
}).join(" ") // creates "max-content max-content 1fr 3fr" depending on value
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.setWidgetInnerStyle("gridTemplateRows", gridTemplateRows)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
colWeights: {
|
|
|
|
|
label: "Column weights",
|
|
|
|
|
tool: Tools.CUSTOM,
|
|
|
|
|
toolProps: {
|
|
|
|
|
// placeholder: "weight",
|
|
|
|
|
// defaultWeightMapping: {0: {weight: 0, gridNo: 0}}
|
|
|
|
|
},
|
|
|
|
|
value: undefined,
|
|
|
|
|
Component: DynamicGridWeightInput,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
|
|
|
|
|
if (!value) return
|
|
|
|
|
|
|
|
|
|
this.setAttrValue("gridWeights.colWeights", value)
|
|
|
|
|
|
|
|
|
|
const noOfCols = this.getAttrValue("gridConfig.noOfCols")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const gridTemplateCol = Array.from({ length: noOfCols }, (_, i) => {
|
|
|
|
|
const col = value[i] // Get the row object
|
|
|
|
|
return col ? `${col.weight}fr` : "max-content"; // Use weight if available
|
|
|
|
|
}).join(" ") // creates "max-content max-content 1fr 3fr" depending on value
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.setWidgetInnerStyle("gridTemplateColumns", gridTemplateCol)
|
|
|
|
|
// this.setW
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-23 19:02:54 +05:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this.updateState((prevState) => ({...prevState, ...updates}))
|
2025-03-20 11:25:07 +05:30
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.props.onLayoutUpdate({parentId: this.__id, parentLayout: value})// inform children about the layout update
|
2025-03-26 15:08:25 +05:30
|
|
|
this.setAttrValue("layout", value)
|
|
|
|
|
|
|
|
|
|
this.updateState((prev) => ({
|
|
|
|
|
widgetInnerStyling: {
|
|
|
|
|
...prev.widgetInnerStyling,
|
|
|
|
|
display: layout !== Layouts.PLACE ? (layout === "grid" ? "grid" : "flex" ) : "block",
|
|
|
|
|
flexDirection: "column",
|
|
|
|
|
// flexDirection: direction,
|
|
|
|
|
gap: `${gap}px`,
|
|
|
|
|
gridTemplateColumns: "repeat(3, max-content)",
|
|
|
|
|
gridTemplateRows: "repeat(3, max-content)",
|
|
|
|
|
// gridTemplateColumns: "repeat(auto-fill, minmax(100px, auto))",
|
|
|
|
|
// gridTemplateRows: "repeat(auto-fill, minmax(100px, auto))",
|
|
|
|
|
}
|
|
|
|
|
}))
|
2025-03-16 10:01:35 +05:30
|
|
|
|
2025-03-26 15:08:25 +05:30
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
}
|
|
|
|
|
|
2024-09-29 19:17:11 +05:30
|
|
|
getInnerRenderStyling(){
|
|
|
|
|
let {width, height, minWidth, minHeight} = this.getRenderSize()
|
2025-03-20 11:25:07 +05:30
|
|
|
|
2024-09-29 19:17:11 +05:30
|
|
|
const {layout: parentLayout, direction, gap} = this.getParentLayout() || {}
|
|
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
// if (parentLayout === Layouts.FLEX){
|
|
|
|
|
// const fillX = this.getAttrValue("flexManager.fillX")
|
|
|
|
|
// const fillY = this.getAttrValue("flexManager.fillY")
|
2024-09-29 19:17:11 +05:30
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
// // This is needed if fillX or fillY is true, as the parent is applied flex-grow
|
2024-09-29 19:17:11 +05:30
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
// if (fillX || fillY){
|
|
|
|
|
// width = "100%"
|
|
|
|
|
// height = "100%"
|
|
|
|
|
// }
|
2024-09-29 19:17:11 +05:30
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
// }
|
2025-03-20 11:25:07 +05:30
|
|
|
|
2024-09-29 19:17:11 +05:30
|
|
|
const styling = {
|
|
|
|
|
...this.state.widgetInnerStyling,
|
|
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
minWidth,
|
|
|
|
|
minHeight
|
|
|
|
|
}
|
|
|
|
|
return styling
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
getRenderSize(){
|
|
|
|
|
|
|
|
|
|
let {width, height, minWidth, minHeight} = super.getRenderSize()
|
|
|
|
|
|
|
|
|
|
let fillX = this.getAttrValue("flexManager.fillX") || false
|
|
|
|
|
let fillY = this.getAttrValue("flexManager.fillY") || false
|
|
|
|
|
|
2025-03-24 21:04:49 +05:30
|
|
|
const {layout: parentLayout} = (this.getParentLayout() || {})
|
|
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
if (fillX){
|
|
|
|
|
width = "100%"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fillY){
|
|
|
|
|
height = "100%"
|
|
|
|
|
}
|
2025-03-24 21:04:49 +05:30
|
|
|
|
|
|
|
|
if (parentLayout && parentLayout === Layouts.GRID){
|
|
|
|
|
const sticky = this.getAttrValue("gridManager.sticky")
|
|
|
|
|
|
|
|
|
|
if (sticky === GRID_STICKY.NEWS){
|
|
|
|
|
width = "100%"
|
|
|
|
|
height = "100%"
|
|
|
|
|
}else if (sticky === GRID_STICKY.WE){
|
|
|
|
|
width = "100%"
|
|
|
|
|
}else if (sticky === GRID_STICKY.NS){
|
|
|
|
|
height = "100%"
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-16 10:01:35 +05:30
|
|
|
|
|
|
|
|
return {width, height, minWidth, minHeight}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2025-03-16 15:43:41 +05:30
|
|
|
serialize(){
|
|
|
|
|
return ({
|
|
|
|
|
...super.serialize(),
|
2025-03-18 18:08:25 +05:30
|
|
|
attrs: this.serializeAttrsValues(), // makes sure that functions are not serialized
|
2025-03-18 21:29:41 +05:30
|
|
|
packAttrs: this.state.packAttrs,
|
2025-03-16 15:43:41 +05:30
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-25 17:27:12 +05:30
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
2025-03-06 19:20:40 +05:30
|
|
|
// TODO: call the base widget
|
|
|
|
|
|
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
|
|
|
|
|
|
2025-03-22 11:11:19 +05:30
|
|
|
const {attrs={}, selected, pos={x: 0, y: 0}, ...restData} = data
|
|
|
|
|
|
|
|
|
|
const parentLayout = this.props.parentWidgetRef?.current?.getLayout()
|
|
|
|
|
|
2024-09-25 17:27:12 +05:30
|
|
|
|
|
|
|
|
let layoutUpdates = {
|
|
|
|
|
parentLayout: parentLayout
|
|
|
|
|
}
|
2024-09-27 16:04:03 +05:30
|
|
|
|
|
|
|
|
if (parentLayout){
|
|
|
|
|
if (parentLayout.layout === Layouts.FLEX || parentLayout.layout === Layouts.GRID){
|
2024-09-25 17:27:12 +05:30
|
|
|
|
2024-09-27 16:04:03 +05:30
|
|
|
layoutUpdates = {
|
|
|
|
|
...layoutUpdates,
|
|
|
|
|
positionType: PosType.NONE
|
|
|
|
|
}
|
2024-09-25 17:27:12 +05:30
|
|
|
|
2024-09-27 16:04:03 +05:30
|
|
|
}else if (parentLayout.layout === Layouts.PLACE){
|
|
|
|
|
layoutUpdates = {
|
|
|
|
|
...layoutUpdates,
|
|
|
|
|
positionType: PosType.ABSOLUTE
|
|
|
|
|
}
|
2024-09-25 17:27:12 +05:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const newData = {
|
|
|
|
|
...restData,
|
2025-03-16 15:43:41 +05:30
|
|
|
...layoutUpdates,
|
|
|
|
|
pos
|
2024-09-25 17:27:12 +05:30
|
|
|
}
|
2024-09-27 16:04:03 +05:30
|
|
|
|
2024-09-25 17:27:12 +05:30
|
|
|
|
|
|
|
|
this.setState(newData, () => {
|
2024-09-27 23:27:07 +05:30
|
|
|
let layoutAttrs = this.setParentLayout(parentLayout).attrs || {}
|
|
|
|
|
|
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
|
|
|
|
2025-03-26 15:08:25 +05:30
|
|
|
// FIXME: when changing layouts all the widgets are being selected
|
2025-03-18 18:08:25 +05:30
|
|
|
if (selected){
|
|
|
|
|
this.select()
|
|
|
|
|
}
|
2024-09-25 17:27:12 +05:30
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
2025-03-06 19:20:40 +05:30
|
|
|
|
2024-09-25 17:27:12 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-09-27 16:04:03 +05:30
|
|
|
// base for widgets that have common base properties such as bg, fg, cursor etc
|
|
|
|
|
export class TkinterWidgetBase extends TkinterBase{
|
|
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
|
super(props)
|
|
|
|
|
|
|
|
|
|
this.droppableTags = null // disables drops
|
|
|
|
|
|
|
|
|
|
const newAttrs = removeKeyFromObject("layout", this.state.attrs)
|
|
|
|
|
|
|
|
|
|
this.state = {
|
|
|
|
|
...this.state,
|
|
|
|
|
attrs: {
|
|
|
|
|
...newAttrs,
|
|
|
|
|
styling: {
|
|
|
|
|
...newAttrs.styling,
|
|
|
|
|
foregroundColor: {
|
|
|
|
|
label: "Foreground Color",
|
|
|
|
|
tool: Tools.COLOR_PICKER,
|
|
|
|
|
value: "#000",
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
this.setWidgetInnerStyle("color", value)
|
|
|
|
|
this.setAttrValue("styling.foregroundColor", value)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
borderWidth: {
|
|
|
|
|
label: "Border thickness",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
|
|
|
|
toolProps: {min: 0, max: 10},
|
|
|
|
|
value: 0,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
this.setWidgetInnerStyle("border", `${value}px solid black`)
|
|
|
|
|
this.setAttrValue("styling.borderWidth", value)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
relief: {
|
|
|
|
|
label: "Relief",
|
|
|
|
|
tool: Tools.SELECT_DROPDOWN,
|
|
|
|
|
options: RELIEF.map((val) => ({value: val, label: val})),
|
2024-09-27 19:22:33 +05:30
|
|
|
value: "",
|
2024-09-27 16:04:03 +05:30
|
|
|
onChange: (value) => {
|
2024-09-27 19:22:33 +05:30
|
|
|
// this.setWidgetInnerStyle("fontFamily", Tkinter_To_GFonts[value])
|
|
|
|
|
this.setAttrValue("styling.relief", value)
|
2024-09-27 16:04:03 +05:30
|
|
|
}
|
2024-09-27 19:22:33 +05:30
|
|
|
},
|
|
|
|
|
// justify: {
|
|
|
|
|
// label: "Justify",
|
|
|
|
|
// tool: Tools.SELECT_DROPDOWN,
|
|
|
|
|
// options: JUSTIFY.map((val) => ({value: val, label: val})),
|
|
|
|
|
// value: "",
|
|
|
|
|
// onChange: (value) => {
|
|
|
|
|
// this.setWidgetInnerStyle("text-align", value)
|
|
|
|
|
// this.setAttrValue("styling.justify", value)
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
},
|
|
|
|
|
padding: {
|
|
|
|
|
label: "padding",
|
|
|
|
|
padX: {
|
|
|
|
|
label: "Pad X",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
2025-03-14 16:42:27 +05:30
|
|
|
toolProps: {min: 0, max: 140},
|
2024-09-27 19:22:33 +05:30
|
|
|
value: null,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
// this.setWidgetInnerStyle("paddingLeft", `${value}px`)
|
|
|
|
|
// this.setWidgetInnerStyle("paddingRight", `${value}px`)
|
|
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
// const widgetStyle = {
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
this.setState((prevState) => ({
|
2024-09-27 19:22:33 +05:30
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
widgetInnerStyling: {
|
|
|
|
|
...prevState.widgetInnerStyling,
|
|
|
|
|
paddingLeft: `${value}px`,
|
|
|
|
|
paddingRight: `${value}px`
|
|
|
|
|
}
|
|
|
|
|
}))
|
2024-09-27 19:22:33 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
this.setAttrValue("padding.padX", value)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
padY: {
|
|
|
|
|
label: "Pad Y",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
2025-03-14 16:42:27 +05:30
|
|
|
toolProps: {min: 0, max: 140},
|
2024-09-27 19:22:33 +05:30
|
|
|
value: null,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
|
2025-03-16 10:01:35 +05:30
|
|
|
this.setState((prevState) => ({
|
|
|
|
|
|
|
|
|
|
widgetInnerStyling: {
|
|
|
|
|
...prevState.widgetInnerStyling,
|
|
|
|
|
paddingTop: `${value}px`,
|
|
|
|
|
paddingBottom: `${value}px`
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
// this.setState({
|
|
|
|
|
|
|
|
|
|
// widgetInnerStyling: widgetStyle
|
|
|
|
|
// })
|
2024-09-27 19:22:33 +05:30
|
|
|
this.setAttrValue("padding.padX", value)
|
|
|
|
|
}
|
|
|
|
|
},
|
2024-09-27 16:04:03 +05:30
|
|
|
},
|
2025-03-14 16:42:27 +05:30
|
|
|
margin: {
|
|
|
|
|
label: "Margin",
|
|
|
|
|
marginX: {
|
|
|
|
|
label: "Margin X",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
|
|
|
|
toolProps: {min: 0, max: 140},
|
|
|
|
|
value: null,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
|
|
|
|
|
|
2025-03-26 15:08:25 +05:30
|
|
|
this.updateState((prev) => ({
|
|
|
|
|
widgetOuterStyling: {
|
|
|
|
|
...prev.widgetOuterStyling,
|
|
|
|
|
marginLeft: `${value}px`,
|
|
|
|
|
marginRight: `${value}px`
|
|
|
|
|
},
|
|
|
|
|
}))
|
2025-03-14 16:42:27 +05:30
|
|
|
this.setAttrValue("margin.marginX", value)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
marginY: {
|
|
|
|
|
label: "Margin Y",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
|
|
|
|
toolProps: {min: 0, max: 140},
|
|
|
|
|
value: null,
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
|
2025-03-26 15:08:25 +05:30
|
|
|
this.updateState((prev) => ({
|
|
|
|
|
widgetOuterStyling: {
|
|
|
|
|
...prev.widgetOuterStyling,
|
|
|
|
|
marginTop: `${value}px`,
|
|
|
|
|
marginBottom: `${value}px`
|
|
|
|
|
},
|
|
|
|
|
}))
|
|
|
|
|
|
2025-03-14 16:42:27 +05:30
|
|
|
this.setAttrValue("margin.marginY", value)
|
|
|
|
|
}
|
|
|
|
|
},
|
2025-03-16 10:01:35 +05:30
|
|
|
},
|
2024-09-27 16:04:03 +05:30
|
|
|
font: {
|
|
|
|
|
label: "font",
|
|
|
|
|
fontFamily: {
|
|
|
|
|
label: "font family",
|
|
|
|
|
tool: Tools.SELECT_DROPDOWN,
|
|
|
|
|
options: Object.keys(Tkinter_To_GFonts).map((val) => ({value: val, label: val})),
|
2024-09-29 17:51:42 +05:30
|
|
|
value: "",
|
2024-09-27 16:04:03 +05:30
|
|
|
onChange: (value) => {
|
|
|
|
|
this.setWidgetInnerStyle("fontFamily", Tkinter_To_GFonts[value])
|
|
|
|
|
this.setAttrValue("font.fontFamily", value)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
fontSize: {
|
|
|
|
|
label: "font size",
|
|
|
|
|
tool: Tools.NUMBER_INPUT,
|
2024-09-29 17:51:42 +05:30
|
|
|
toolProps: {min: 3, max: 140},
|
2024-09-27 19:22:33 +05:30
|
|
|
value: null,
|
2024-09-27 16:04:03 +05:30
|
|
|
onChange: (value) => {
|
|
|
|
|
this.setWidgetInnerStyle("fontSize", `${value}px`)
|
|
|
|
|
this.setAttrValue("font.fontSize", value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
cursor: {
|
|
|
|
|
label: "Cursor",
|
|
|
|
|
tool: Tools.SELECT_DROPDOWN,
|
|
|
|
|
toolProps: {placeholder: "select cursor"},
|
2024-09-27 19:22:33 +05:30
|
|
|
value: "",
|
2024-09-27 16:04:03 +05:30
|
|
|
options: Object.keys(Tkinter_TO_WEB_CURSOR_MAPPING).map((val) => ({value: val, label: val})),
|
|
|
|
|
onChange: (value) => {
|
|
|
|
|
this.setWidgetInnerStyle("cursor", Tkinter_TO_WEB_CURSOR_MAPPING[value])
|
|
|
|
|
this.setAttrValue("cursor", value)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-09-27 19:22:33 +05:30
|
|
|
|
|
|
|
|
this.getConfigCode = this.getConfigCode.bind(this)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getConfigCode(){
|
|
|
|
|
|
2024-09-30 15:54:09 +05:30
|
|
|
const config = {
|
2024-09-27 19:22:33 +05:30
|
|
|
bg: `"${this.getAttrValue("styling.backgroundColor")}"`,
|
|
|
|
|
fg: `"${this.getAttrValue("styling.foregroundColor")}"`,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.getAttrValue("styling.borderWidth"))
|
2024-09-30 15:54:09 +05:30
|
|
|
config["bd"] = this.getAttrValue("styling.borderWidth")
|
2024-09-27 19:22:33 +05:30
|
|
|
|
|
|
|
|
if (this.getAttrValue("styling.relief"))
|
2025-01-01 16:43:25 +05:30
|
|
|
config["relief"] = `tk.${this.getAttrValue("styling.relief")}`
|
2024-09-27 19:22:33 +05:30
|
|
|
|
|
|
|
|
if (this.getAttrValue("font.fontFamily") || this.getAttrValue("font.fontSize")){
|
2024-09-30 15:54:09 +05:30
|
|
|
config["font"] = `("${this.getAttrValue("font.fontFamily")}", ${this.getAttrValue("font.fontSize") || 12}, )`
|
2024-09-27 19:22:33 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.getAttrValue("cursor"))
|
2024-09-30 15:54:09 +05:30
|
|
|
config["cursor"] = `"${this.getAttrValue("cursor")}"`
|
2024-09-27 19:22:33 +05:30
|
|
|
|
|
|
|
|
if (this.getAttrValue("padding.padX")){
|
2025-03-14 16:42:27 +05:30
|
|
|
// inner padding
|
|
|
|
|
config["ipadx"] = this.getAttrValue("padding.padX")
|
2024-09-27 19:22:33 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.getAttrValue("padding.padY")){
|
2025-03-14 16:42:27 +05:30
|
|
|
config["ipady"] = this.getAttrValue("padding.padY")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this.getAttrValue("margin.marginX")){
|
|
|
|
|
config["padx"] = this.getAttrValue("margin.marginX")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.getAttrValue("margin.marginY")){
|
|
|
|
|
config["pady"] = this.getAttrValue("margin.marginY")
|
2024-09-27 19:22:33 +05:30
|
|
|
}
|
|
|
|
|
|
2024-09-30 15:54:09 +05:30
|
|
|
// FIXME: add width and height, the scales may not be correct as the width and height are based on characters in pack and grid not pixels
|
|
|
|
|
// if (!this.state.fitContent.width){
|
|
|
|
|
// config["width"] = this.state.size.width
|
|
|
|
|
// }
|
|
|
|
|
// if (!this.state.fitContent.height){
|
|
|
|
|
// config["height"] = this.state.size.height
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return config
|
2024-09-27 16:04:03 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|