From 77b1c5a0f0e4aa4f40658fd89d9a196ec4731b0a Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 27 Sep 2024 16:04:03 +0530 Subject: [PATCH] adding more widget attributes --- src/canvas/toolbar.js | 4 + src/canvas/widgets/base.js | 7 +- src/frameworks/tkinter/constants/cursor.js | 43 ++++++ .../tkinter/constants/fontFamily.js | 20 +++ src/frameworks/tkinter/constants/styling.js | 8 ++ .../tkinter/widgets/ checkButton.js | 41 +++--- src/frameworks/tkinter/widgets/base.js | 125 ++++++++++++++++-- src/frameworks/tkinter/widgets/button.js | 4 +- src/frameworks/tkinter/widgets/frame.js | 19 ++- src/frameworks/tkinter/widgets/input.js | 4 +- src/frameworks/tkinter/widgets/label.js | 16 ++- src/frameworks/tkinter/widgets/mainWindow.js | 3 +- src/frameworks/tkinter/widgets/optionMenu.js | 5 +- src/frameworks/tkinter/widgets/slider.js | 4 +- src/frameworks/tkinter/widgets/spinBox.js | 4 +- src/frameworks/tkinter/widgets/toplevel.js | 2 +- 16 files changed, 251 insertions(+), 58 deletions(-) create mode 100644 src/frameworks/tkinter/constants/cursor.js create mode 100644 src/frameworks/tkinter/constants/fontFamily.js create mode 100644 src/frameworks/tkinter/constants/styling.js diff --git a/src/canvas/toolbar.js b/src/canvas/toolbar.js index 95c73db..617cac3 100644 --- a/src/canvas/toolbar.js +++ b/src/canvas/toolbar.js @@ -252,6 +252,10 @@ const CanvasToolBar = memo(({ isOpen, widgetType, attrs = {} }) => { showSearch value={val.value || ""} placeholder={`${val.label}`} + className="tw-w-full" + filterOption={(input, option) => + (option?.label ?? '').toLowerCase().includes(input.toLowerCase()) + } onChange={(value) => handleChange(value, val.onChange)} /> )} diff --git a/src/canvas/widgets/base.js b/src/canvas/widgets/base.js index 21eab56..e54510e 100644 --- a/src/canvas/widgets/base.js +++ b/src/canvas/widgets/base.js @@ -19,6 +19,7 @@ import { isNumeric, removeKeyFromObject } from "../../utils/common" // FIXME: the drag drop indicator is not going invisible if the drop happens on the child +// FIXME: once the width and height is set to fit-content, it can no longer be resized const ATTRS_KEYS = ['value', 'label', 'tool', 'onChange', 'toolProps'] // these are attrs keywords, don't use these keywords as keys while defining the attrs property @@ -532,7 +533,6 @@ class Widget extends React.Component { } setWidgetName(name) { - console.log("named: ", name) this.updateState({ widgetName: name.length > 0 ? name : this.state.widgetName }) @@ -544,6 +544,11 @@ class Widget extends React.Component { */ setParentLayout(parentLayout){ + if (!parentLayout){ + // if parent layout is null (i,e the widget is on the canvas) + return {} + } + const {layout, direction, gap} = parentLayout diff --git a/src/frameworks/tkinter/constants/cursor.js b/src/frameworks/tkinter/constants/cursor.js new file mode 100644 index 0000000..64a4e41 --- /dev/null +++ b/src/frameworks/tkinter/constants/cursor.js @@ -0,0 +1,43 @@ + + +export const Tkinter_TO_WEB_CURSOR_MAPPING = { + + "arrow": "default", + "circle": "wait", + "clock": "wait", + "cross": "crosshair", + "dotbox": "not-allowed", + "exchange": "alias", + "fleur": "move", + "heart": "default", // mapping doesn't exist + "man": "default", + "mouse": "default", + "pirate": "default", + "plus": "zoom-in", + "shuttle": "default", + "sizing": "se-resize", + "spider": "default", + "spraycan": "default", + "star": "default", + "target": "cell", + "tcross": "crosshair", + "trek": "default", + "watch": "wait", + "X_cursor": "not-allowed", + "bottom_left_corner": "sw-resize", + "bottom_right_corner": "se-resize", + "bottom_side": "s-resize", + "top_left_corner": "nw-resize", + "top_right_corner": "ne-resize", + "top_side": "n-resize", + "left_side": "w-resize", + "right_side": "e-resize", + "hand1": "pointer", + "hand2": "pointer", + "sb_h_double_arrow": "ew-resize", + "sb_v_double_arrow": "ns-resize", + "center_ptr": "default", + "question_arrow": "help", + "umbrella": "default", + "pencil": "copy", +} diff --git a/src/frameworks/tkinter/constants/fontFamily.js b/src/frameworks/tkinter/constants/fontFamily.js new file mode 100644 index 0000000..3b95f86 --- /dev/null +++ b/src/frameworks/tkinter/constants/fontFamily.js @@ -0,0 +1,20 @@ + + + +export const Tkinter_To_GFonts= { + "Arial": "Roboto", + "Courier": "Courier Prime", + "Comic Sans MS": "Comic Neue", + "Fixedsys": "Cousine", + "Helvetica": "Roboto", + "Times": "Merriweather", + "System": "Noto Sans", + "Verdana": "Open Sans", + "Symbol": "Noto Sans Symbols", + "TkDefaultFont": "Noto Sans", + "TkFixedFont": "Source Code Pro", + "TkMenuFont": "Roboto", + "TkHeadingFont": "Montserrat", + "TkTextFont": "Roboto", + "TkTooltipFont": "Lato", +} diff --git a/src/frameworks/tkinter/constants/styling.js b/src/frameworks/tkinter/constants/styling.js new file mode 100644 index 0000000..40b1103 --- /dev/null +++ b/src/frameworks/tkinter/constants/styling.js @@ -0,0 +1,8 @@ + +export const RELIEF = [ + "FLAT", + "RAISED", + "SUNKEN", + "GROOVE", + "RIDGE" +] \ No newline at end of file diff --git a/src/frameworks/tkinter/widgets/ checkButton.js b/src/frameworks/tkinter/widgets/ checkButton.js index 758b34e..5937be3 100644 --- a/src/frameworks/tkinter/widgets/ checkButton.js +++ b/src/frameworks/tkinter/widgets/ checkButton.js @@ -3,32 +3,29 @@ import Widget from "../../../canvas/widgets/base" import Tools from "../../../canvas/constants/tools" import { removeKeyFromObject } from "../../../utils/common" import { CheckSquareFilled } from "@ant-design/icons" -import TkinterBase from "./base" +import {TkinterBase} from "./base" export class CheckBox extends TkinterBase{ static widgetType = "check_button" - // TODO: remove layouts constructor(props) { super(props) - this.droppableTags = null // disables drops - // const {layout, ...newAttrs} = this.state.attrs // Removes the layout attribute let newAttrs = removeKeyFromObject("layout", this.state.attrs) - newAttrs = removeKeyFromObject("styling.backgroundColor", newAttrs) this.minSize = {width: 50, height: 30} this.state = { ...this.state, size: { width: 120, height: 30 }, + widgetName: "Check box", attrs: { ...newAttrs, styling: { - label: "Styling", + ...newAttrs.styling, foregroundColor: { label: "Foreground Color", tool: Tools.COLOR_PICKER, // the tool to display, can be either HTML ELement or a constant string @@ -60,7 +57,6 @@ export class CheckBox extends TkinterBase{ componentDidMount(){ super.componentDidMount() // this.setAttrValue("styling.backgroundColor", "#fff") - this.setWidgetName("Checkbox") this.setWidgetInnerStyle("backgroundColor", "#fff0") } @@ -126,7 +122,7 @@ export class CheckBox extends TkinterBase{ } -export class RadioButton extends Widget{ +export class RadioButton extends TkinterBase{ static widgetType = "radio_button" @@ -146,10 +142,11 @@ export class RadioButton extends Widget{ this.state = { ...this.state, size: { width: 120, height: 'fit' }, + widgetName: "Radio button", attrs: { ...newAttrs, styling: { - label: "styling", + ...newAttrs.styling, foregroundColor: { label: "Foreground Color", tool: Tools.COLOR_PICKER, // the tool to display, can be either HTML ELement or a constant string @@ -178,7 +175,6 @@ export class RadioButton extends Widget{ componentDidMount(){ super.componentDidMount() // this.setAttrValue("styling.backgroundColor", "#fff") - this.setWidgetName("Radio button") this.setWidgetInnerStyle("backgroundColor", "#fff0") } @@ -187,19 +183,26 @@ export class RadioButton extends Widget{ const bg = this.getAttrValue("styling.backgroundColor") const fg = this.getAttrValue("styling.foregroundColor") - const radios = this.getAttrValue("radios") - // TODO: from here const code = [ - `${variableName}_var = tk.IntVar()`, - `${variableName} = tk.Radiobutton(master=${parent}, text="")`, - `${variableName}.config(bg="${bg}", fg="${fg}")`, - ] + `${variableName}_var = tk.IntVar()`, + ] + const radios = this.getAttrValue("radios") - if (this.getAttrValue("defaultChecked")){ - code.push(`${variableName}.select()`) + radios.inputs.forEach((radio_text, idx) => { + + const radioBtnVariable = `${variableName}_${idx}` + code.push(`\n`) + code.push(`${radioBtnVariable} = tk.Radiobutton(master=${parent}, variable=${variableName}_var, text="${radio_text}")`) + code.push(`${radioBtnVariable}.config(bg="${bg}", fg="${fg}", value=${idx})`) + code.push(`${radioBtnVariable}.${this.getLayoutCode()}`) + }) + + const defaultSelected = radios.selectedRadio + + if (defaultSelected !== -1){ + code.push(`${variableName}_var.set(${defaultSelected})`) } - code.push(`${variableName}.${this.getLayoutCode()}`) return code } diff --git a/src/frameworks/tkinter/widgets/base.js b/src/frameworks/tkinter/widgets/base.js index 95b0121..e6be48a 100644 --- a/src/frameworks/tkinter/widgets/base.js +++ b/src/frameworks/tkinter/widgets/base.js @@ -1,11 +1,15 @@ import { Layouts, PosType } from "../../../canvas/constants/layouts" import Tools from "../../../canvas/constants/tools" import Widget from "../../../canvas/widgets/base" +import { removeKeyFromObject } from "../../../utils/common" +import { Tkinter_TO_WEB_CURSOR_MAPPING } from "../constants/cursor" +import { Tkinter_To_GFonts } from "../constants/fontFamily" +import { RELIEF } from "../constants/styling" // TODO: add full width and full height in base widget // TODO: the pack should configure width and height of widgets -class TkinterBase extends Widget { +export class TkinterBase extends Widget { static requiredImports = ['import tkinter as tk'] @@ -36,6 +40,10 @@ class TkinterBase extends Widget { setParentLayout(parentLayout){ + if (!parentLayout){ + return {} + } + const {layout, direction, gap} = parentLayout // show attributes related to the layout manager @@ -168,24 +176,26 @@ class TkinterBase extends Widget { data = {...data} // create a shallow copy - const {attrs, parentLayout, ...restData} = data + const {attrs, parentLayout=null, ...restData} = data let layoutUpdates = { parentLayout: parentLayout } + + if (parentLayout){ + if (parentLayout.layout === Layouts.FLEX || parentLayout.layout === Layouts.GRID){ - if (parentLayout.layout === Layouts.FLEX || parentLayout.layout === Layouts.GRID){ + layoutUpdates = { + ...layoutUpdates, + positionType: PosType.NONE + } - layoutUpdates = { - ...layoutUpdates, - positionType: PosType.NONE - } - - }else if (parentLayout.layout === Layouts.PLACE){ - layoutUpdates = { - ...layoutUpdates, - positionType: PosType.ABSOLUTE + }else if (parentLayout.layout === Layouts.PLACE){ + layoutUpdates = { + ...layoutUpdates, + positionType: PosType.ABSOLUTE + } } } @@ -193,6 +203,8 @@ class TkinterBase extends Widget { ...restData, ...layoutUpdates } + + console.log("new data: ", newData) this.setState(newData, () => { let layoutAttrs = this.setParentLayout(parentLayout) || {} @@ -223,7 +235,7 @@ class TkinterBase extends Widget { // TODO: find a better way to apply innerStyles this.setWidgetInnerStyle("backgroundColor", newAttrs.styling.backgroundColor.value) } - + this.updateState({ attrs: newAttrs }, callback) }) @@ -235,4 +247,89 @@ class TkinterBase extends Widget { } -export default TkinterBase \ No newline at end of file +// 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})), + value: "Arial", + onChange: (value) => { + this.setWidgetInnerStyle("fontFamily", Tkinter_To_GFonts[value]) + this.setAttrValue("font.fontFamily", value) + } + } + }, + font: { + label: "font", + fontFamily: { + label: "font family", + tool: Tools.SELECT_DROPDOWN, + options: Object.keys(Tkinter_To_GFonts).map((val) => ({value: val, label: val})), + value: "Arial", + onChange: (value) => { + this.setWidgetInnerStyle("fontFamily", Tkinter_To_GFonts[value]) + this.setAttrValue("font.fontFamily", value) + } + }, + fontSize: { + label: "font size", + tool: Tools.NUMBER_INPUT, + toolProps: {min: 1, max: 140}, + value: 14, + onChange: (value) => { + console.log("font size: ", value) + this.setWidgetInnerStyle("fontSize", `${value}px`) + this.setAttrValue("font.fontSize", value) + } + } + }, + cursor: { + label: "Cursor", + tool: Tools.SELECT_DROPDOWN, + toolProps: {placeholder: "select cursor"}, + value: Tkinter_TO_WEB_CURSOR_MAPPING["arrow"], + 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) + } + }, + } + } + } + +} \ No newline at end of file diff --git a/src/frameworks/tkinter/widgets/button.js b/src/frameworks/tkinter/widgets/button.js index 775a8d1..1ecc097 100644 --- a/src/frameworks/tkinter/widgets/button.js +++ b/src/frameworks/tkinter/widgets/button.js @@ -1,7 +1,7 @@ import Widget from "../../../canvas/widgets/base" import Tools from "../../../canvas/constants/tools" import { removeKeyFromObject } from "../../../utils/common" -import TkinterBase from "./base" +import {TkinterBase} from "./base" class Button extends TkinterBase{ @@ -17,6 +17,7 @@ class Button extends TkinterBase{ this.state = { ...this.state, size: { width: 80, height: 40 }, + widgetName: "Button", attrs: { ...newAttrs, styling: { @@ -46,7 +47,6 @@ class Button extends TkinterBase{ componentDidMount(){ super.componentDidMount() - this.setWidgetName("button") this.setAttrValue("styling.backgroundColor", "#E4E2E2") } diff --git a/src/frameworks/tkinter/widgets/frame.js b/src/frameworks/tkinter/widgets/frame.js index 8cc7614..061700e 100644 --- a/src/frameworks/tkinter/widgets/frame.js +++ b/src/frameworks/tkinter/widgets/frame.js @@ -1,5 +1,5 @@ import Widget from "../../../canvas/widgets/base" -import TkinterBase from "./base" +import {TkinterBase} from "./base" class Frame extends TkinterBase{ @@ -12,6 +12,17 @@ class Frame extends TkinterBase{ this.droppableTags = { exclude: ["image", "video", "media", "toplevel", "main_window"] } + + this.state = { + ...this.state, + widgetName: "Frame" + } + + } + + componentDidMount(){ + super.componentDidMount() + this.setAttrValue("styling.backgroundColor", "#EDECEC") } generateCode(variableName, parent){ @@ -25,11 +36,7 @@ class Frame extends TkinterBase{ ] } - componentDidMount(){ - super.componentDidMount() - this.setAttrValue("styling.backgroundColor", "#EDECEC") - this.setWidgetName("frame") - } + renderContent(){ // console.log("widget styling: ", this.state.widgetInnerStyling) diff --git a/src/frameworks/tkinter/widgets/input.js b/src/frameworks/tkinter/widgets/input.js index 4221817..3fa170e 100644 --- a/src/frameworks/tkinter/widgets/input.js +++ b/src/frameworks/tkinter/widgets/input.js @@ -1,7 +1,7 @@ import Widget from "../../../canvas/widgets/base" import Tools from "../../../canvas/constants/tools" import { removeKeyFromObject } from "../../../utils/common" -import TkinterBase from "./base" +import {TkinterBase} from "./base" export class Input extends TkinterBase{ @@ -18,6 +18,7 @@ export class Input extends TkinterBase{ this.state = { ...this.state, size: { width: 120, height: 40 }, + widgetName: "Entry", attrs: { ...newAttrs, styling: { @@ -47,7 +48,6 @@ export class Input extends TkinterBase{ componentDidMount(){ super.componentDidMount() this.setAttrValue("styling.backgroundColor", "#fff") - this.setWidgetName("Entry") } generateCode(variableName, parent){ diff --git a/src/frameworks/tkinter/widgets/label.js b/src/frameworks/tkinter/widgets/label.js index 5288040..ae676cd 100644 --- a/src/frameworks/tkinter/widgets/label.js +++ b/src/frameworks/tkinter/widgets/label.js @@ -1,11 +1,11 @@ import Widget from "../../../canvas/widgets/base" import Tools from "../../../canvas/constants/tools" import { removeKeyFromObject } from "../../../utils/common" -import TkinterBase from "./base" +import {TkinterBase, TkinterWidgetBase} from "./base" import { Layouts } from "../../../canvas/constants/layouts" -class Label extends TkinterBase{ +class Label extends TkinterWidgetBase{ static widgetType = "label" @@ -19,6 +19,7 @@ class Label extends TkinterBase{ this.state = { ...this.state, + widgetName: "Label", size: { width: 80, height: 40 }, attrs: { ...newAttrs, @@ -50,12 +51,16 @@ class Label extends TkinterBase{ }, } } + } componentDidMount(){ super.componentDidMount() + + this.setAttrValue("styling.backgroundColor", "#E4E2E2") - this.setWidgetName("label") + // this.setWidgetName("label") // Don't do this this causes issues while loading data + } @@ -89,9 +94,10 @@ class Label extends TkinterBase{ renderContent(){ return (
-
+
{/* {this.props.children} */} -
+
{this.getAttrValue("labelWidget")}
diff --git a/src/frameworks/tkinter/widgets/mainWindow.js b/src/frameworks/tkinter/widgets/mainWindow.js index 65186e0..c2ce836 100644 --- a/src/frameworks/tkinter/widgets/mainWindow.js +++ b/src/frameworks/tkinter/widgets/mainWindow.js @@ -18,6 +18,7 @@ class MainWindow extends Widget{ size: { width: 700, height: 400 }, attrs: { ...this.state.attrs, + widgetName: "main", title: { label: "Window Title", tool: Tools.INPUT, // the tool to display, can be either HTML ELement or a constant string @@ -33,7 +34,7 @@ class MainWindow extends Widget{ componentDidMount(){ super.componentDidMount() this.setAttrValue("styling.backgroundColor", "#E4E2E2") - this.setWidgetName("main") + // this.setWidgetName("main") // Don't do this as this will cause conflicts while loading names } generateCode(variableName, parent){ diff --git a/src/frameworks/tkinter/widgets/optionMenu.js b/src/frameworks/tkinter/widgets/optionMenu.js index 73b3489..e6c4530 100644 --- a/src/frameworks/tkinter/widgets/optionMenu.js +++ b/src/frameworks/tkinter/widgets/optionMenu.js @@ -3,7 +3,7 @@ import Widget from "../../../canvas/widgets/base" import Tools from "../../../canvas/constants/tools" import { removeKeyFromObject } from "../../../utils/common" import { ArrowDownOutlined, DownOutlined } from "@ant-design/icons" -import TkinterBase from "./base" +import {TkinterBase} from "./base" class OptionMenu extends TkinterBase{ @@ -25,6 +25,7 @@ class OptionMenu extends TkinterBase{ this.state = { ...this.state, isDropDownOpen: false, + widgetName: "Option menu", size: { width: 120, height: 'fit' }, attrs: { ...newAttrs, @@ -64,8 +65,6 @@ class OptionMenu extends TkinterBase{ componentDidMount(){ super.componentDidMount() - // this.setAttrValue("styling.backgroundColor", "#fff") - this.setWidgetName("Option menu") this.setWidgetInnerStyle("backgroundColor", "#fff") } diff --git a/src/frameworks/tkinter/widgets/slider.js b/src/frameworks/tkinter/widgets/slider.js index d75e0ce..c20feaa 100644 --- a/src/frameworks/tkinter/widgets/slider.js +++ b/src/frameworks/tkinter/widgets/slider.js @@ -1,7 +1,7 @@ import Widget from "../../../canvas/widgets/base" import Tools from "../../../canvas/constants/tools" import { removeKeyFromObject } from "../../../utils/common" -import TkinterBase from "./base" +import {TkinterBase} from "./base" class Slider extends TkinterBase{ @@ -17,6 +17,7 @@ class Slider extends TkinterBase{ this.state = { ...this.state, + widgetName: "Scale", size: { width: 'fit', height: 'fit' }, attrs: { ...newAttrs, @@ -72,7 +73,6 @@ class Slider extends TkinterBase{ componentDidMount(){ super.componentDidMount() this.setAttrValue("styling.backgroundColor", "#fff") - this.setWidgetName("Scale") } getToolbarAttrs(){ diff --git a/src/frameworks/tkinter/widgets/spinBox.js b/src/frameworks/tkinter/widgets/spinBox.js index ea92c61..c452711 100644 --- a/src/frameworks/tkinter/widgets/spinBox.js +++ b/src/frameworks/tkinter/widgets/spinBox.js @@ -2,7 +2,7 @@ import Widget from "../../../canvas/widgets/base" import Tools from "../../../canvas/constants/tools" import { removeKeyFromObject } from "../../../utils/common" import { DownOutlined, UpOutlined } from "@ant-design/icons" -import TkinterBase from "./base" +import {TkinterBase} from "./base" class SpinBox extends TkinterBase{ @@ -19,6 +19,7 @@ class SpinBox extends TkinterBase{ this.state = { ...this.state, size: { width: 70, height: 'fit' }, + widgetName: "Spin box", attrs: { ...newAttrs, styling: { @@ -73,7 +74,6 @@ class SpinBox extends TkinterBase{ componentDidMount(){ super.componentDidMount() this.setAttrValue("styling.backgroundColor", "#fff") - this.setWidgetName("SpinBox") } generateCode(variableName, parent){ diff --git a/src/frameworks/tkinter/widgets/toplevel.js b/src/frameworks/tkinter/widgets/toplevel.js index 681d656..c48b72a 100644 --- a/src/frameworks/tkinter/widgets/toplevel.js +++ b/src/frameworks/tkinter/widgets/toplevel.js @@ -17,6 +17,7 @@ class TopLevel extends Widget{ this.state = { ...this.state, size: { width: 450, height: 200 }, + widgetName: "top level", attrs: { ...this.state.attrs, title: { @@ -34,7 +35,6 @@ class TopLevel extends Widget{ componentDidMount(){ super.componentDidMount() this.setAttrValue("styling.backgroundColor", "#E4E2E2") - this.setWidgetName("toplevel") } generateCode(variableName, parent){