Merge pull request #12 from PaulleDemon/customtk-fixes

fixing customtk layout
This commit is contained in:
Art/Paul
2025-03-28 17:13:21 +05:30
committed by GitHub
8 changed files with 1007 additions and 147 deletions

View File

@@ -125,7 +125,6 @@ function App() {
const widgetCenterX = (TkMainWindow.initialSize.width - canvasBoundingBox.left) / 2
const widgetCenterY = (TkMainWindow.initialSize.height - canvasBoundingBox.top) / 2
canvasRef?.current?.createWidget(TkMainWindow, {x: canvasCenterX - widgetCenterX, y: canvasCenterY - widgetCenterY}, ({id, widgetRef}) => {
// center the widget when adding to canvas
@@ -142,7 +141,12 @@ function App() {
})
}else if (UIFramework === FrameWorks.CUSTOMTK){
canvasRef?.current?.createWidget(CTkMainWindow, ({id, widgetRef}) => {
const widgetCenterX = (TkMainWindow.initialSize.width - canvasBoundingBox.left) / 2
const widgetCenterY = (TkMainWindow.initialSize.height - canvasBoundingBox.top) / 2
canvasRef?.current?.createWidget(CTkMainWindow, {x: canvasCenterX - widgetCenterX, y: canvasCenterY - widgetCenterY}, ({id, widgetRef}) => {
// center the widget when adding to canvas
if (!widgetRef.current){
@@ -154,7 +158,7 @@ function App() {
const widgetCenterY = (widgetBoundingBox.height - widgetBoundingBox.top) / 2
widgetRef.current?.setPos(canvasCenterX-widgetCenterX, canvasCenterY-widgetCenterY)
// widgetRef.current?.setPos(canvasCenterX-widgetCenterX, canvasCenterY-widgetCenterY)
})
}

View File

@@ -20,5 +20,25 @@ export const ANCHOR = [
"s",
"e",
"w",
"center"
]
"center",
"ne",
"se",
"sw",
"nw",
]
export const GRID_STICKY = {
N: "n",
S: "s",
E: "e",
W: "w",
WE: "we",
NS: "ns",
NW: "nw",
NE: "ne",
SW: "sw",
SE: "se",
NEWS: "news",
NONE: "",
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,5 @@
import { Layouts } from "../../../canvas/constants/layouts"
import Tools from "../../../canvas/constants/tools"
import Widget from "../../../canvas/widgets/base"
import { CustomTkBase } from "./base"
@@ -17,7 +19,99 @@ class Frame extends CustomTkBase{
this.state = {
...this.state,
fitContent: {width: true, height: true},
widgetName: "Frame"
widgetName: "Frame",
attrs: {
...this.state.attrs,
padding: {
label: "padding",
padX: {
label: "Pad X",
tool: Tools.NUMBER_INPUT,
toolProps: {min: 0, max: 140},
value: null,
onChange: (value) => {
// this.setWidgetInnerStyle("paddingLeft", `${value}px`)
// this.setWidgetInnerStyle("paddingRight", `${value}px`)
// const widgetStyle = {
// }
this.setState((prevState) => ({
widgetInnerStyling: {
...prevState.widgetInnerStyling,
paddingLeft: `${value}px`,
paddingRight: `${value}px`
}
}))
this.setAttrValue("padding.padX", value)
}
},
padY: {
label: "Pad Y",
tool: Tools.NUMBER_INPUT,
toolProps: {min: 0, max: 140},
value: null,
onChange: (value) => {
this.setState((prevState) => ({
widgetInnerStyling: {
...prevState.widgetInnerStyling,
paddingTop: `${value}px`,
paddingBottom: `${value}px`
}
}))
// this.setState({
// widgetInnerStyling: widgetStyle
// })
this.setAttrValue("padding.padY", value)
}
},
},
margin: {
label: "Margin",
marginX: {
label: "Margin X",
tool: Tools.NUMBER_INPUT,
toolProps: {min: 0, max: 140},
value: null,
onChange: (value) => {
this.updateState((prev) => ({
widgetOuterStyling: {
...prev.widgetOuterStyling,
marginLeft: `${value}px`,
marginRight: `${value}px`
},
}))
this.setAttrValue("margin.marginX", value)
}
},
marginY: {
label: "Margin Y",
tool: Tools.NUMBER_INPUT,
toolProps: {min: 0, max: 140},
value: null,
onChange: (value) => {
this.updateState((prev) => ({
widgetOuterStyling: {
...prev.widgetOuterStyling,
marginTop: `${value}px`,
marginBottom: `${value}px`
},
}))
this.setAttrValue("margin.marginY", value)
}
},
},
}
}
}
@@ -27,6 +121,34 @@ class Frame extends CustomTkBase{
this.setAttrValue("styling.backgroundColor", "#EDECEC")
}
getConfigCode(){
const bg = this.getAttrValue("styling.backgroundColor")
const fitWidth = this.state.fitContent.width
const fitHeight = this.state.fitContent.height
const {width, height} = this.getSize()
const {layout} = this.getParentLayout()
const config = {
bg: `"${bg}"`
}
if (layout !== Layouts.PLACE){
if (!fitWidth){
config['width'] = width
}
if (!fitHeight){
config['height'] = height
}
}
return config
}
generateCode(variableName, parent){
const bg = this.getAttrValue("styling.backgroundColor")
@@ -34,12 +156,12 @@ class Frame extends CustomTkBase{
return [
`${variableName} = ctk.CTkFrame(master=${parent})`,
`${variableName}.configure(fg_color="${bg}")`,
`${variableName}.${this.getLayoutCode()}`
`${variableName}.${this.getLayoutCode()}`,
...this.getGridLayoutConfigurationCode(variableName)
]
}
renderContent(){
// console.log("bounding rect: ", this.getBoundingRect())
@@ -49,7 +171,7 @@ class Frame extends CustomTkBase{
<div className="tw-p-2 tw-w-full tw-h-full tw-content-start"
ref={this.styleAreaRef}
style={this.getInnerRenderStyling()}>
{this.props.children}
{this.renderTkinterLayout()}
</div>
</div>
)

View File

@@ -116,6 +116,22 @@ class Label extends CustomTkWidgetBase{
})
}
getAnchorStyle = (anchor) => {
const anchorStyles = {
n: { justifyContent: 'center', alignItems: 'flex-start' },
s: { justifyContent: 'center', alignItems: 'flex-end' },
e: { justifyContent: 'flex-end', alignItems: 'center' },
w: { justifyContent: 'flex-start', alignItems: 'center' },
ne: { justifyContent: 'flex-end', alignItems: 'flex-start' },
se: { justifyContent: 'flex-end', alignItems: 'flex-end' },
nw: { justifyContent: 'flex-start', alignItems: 'flex-start' },
sw: { justifyContent: 'flex-start', alignItems: 'flex-end' },
center: { justifyContent: 'center', alignItems: 'center' }
}
return anchorStyles[anchor] || anchorStyles["w"];
}
renderContent(){
const image = this.getAttrValue("imageUpload")
@@ -137,7 +153,10 @@ class Label extends CustomTkWidgetBase{
<img src={image.previewUrl} className="tw-bg-contain tw-w-full tw-h-full" />
)
}
<div className="" style={{color: this.getAttrValue("styling.foregroundColor")}}>
<div className={`tw-flex ${!image ? "tw-w-full tw-h-full" : ""}`} style={{
color: this.getAttrValue("styling.foregroundColor"),
...this.getAnchorStyle(this.getAttrValue("styling.anchor"))
}}>
{this.getAttrValue("labelWidget")}
</div>
</div>

View File

@@ -1,6 +1,7 @@
import Widget from "../../../canvas/widgets/base"
import Tools from "../../../canvas/constants/tools"
import { CustomTkBase } from "./base"
import { getPythonAssetPath } from "../../utils/pythonFilePath"
class MainWindow extends CustomTkBase{
@@ -8,6 +9,13 @@ class MainWindow extends CustomTkBase{
static widgetType = "main_window"
static displayName = "Main Window"
static initialSize = {
width: 700,
height: 400
}
constructor(props) {
super(props)
@@ -27,6 +35,13 @@ class MainWindow extends CustomTkBase{
toolProps: {placeholder: "Window title", maxLength: 40},
value: "Main Window",
onChange: (value) => this.setAttrValue("title", value)
},
logo: {
label: "Window Logo",
tool: Tools.UPLOADED_LIST,
toolProps: {filterOptions: ["image/jpg", "image/jpeg", "image/png"]},
value: "",
onChange: (value) => this.setAttrValue("logo", value)
}
}
@@ -43,12 +58,48 @@ class MainWindow extends CustomTkBase{
generateCode(variableName, parent){
const backgroundColor = this.getAttrValue("styling.backgroundColor")
const logo = this.getAttrValue("logo")
return [
`${variableName} = ctk.CTk()`,
`${variableName}.configure(fg_color="${backgroundColor}")`,
`${variableName}.title("${this.getAttrValue("title")}")`
]
const {width, height} = this.getSize()
const code = [
`${variableName} = ctk.CTk()`,
`${variableName}.configure(fg_color="${backgroundColor}")`,
`${variableName}.title("${this.getAttrValue("title")}")`,
`${variableName}.geometry("${width}x${height}")`,
...this.getGridLayoutConfigurationCode(variableName)
]
if (logo?.name){
// code.push(`\n`)
code.push(`${variableName}_img = Image.open(${getPythonAssetPath(logo.name, "image")})`)
code.push(`${variableName}_img = ImageTk.PhotoImage(${variableName}_img)`)
code.push(`${variableName}.iconphoto(False, ${variableName}_img)`)
// code.push("\n")
}
return code
}
getImports(){
const imports = super.getImports()
if (this.getAttrValue("logo"))
imports.push("import os", "from PIL import Image, ImageTk", )
return imports
}
getRequirements(){
const requirements = super.getRequirements()
if (this.getAttrValue("logo"))
requirements.push("pillow")
return requirements
}
getToolbarAttrs(){
@@ -58,8 +109,8 @@ class MainWindow extends CustomTkBase{
id: this.__id,
widgetName: toolBarAttrs.widgetName,
title: this.state.attrs.title,
logo: this.state.attrs.logo,
size: toolBarAttrs.size,
...this.state.attrs,
})
@@ -83,7 +134,7 @@ class MainWindow extends CustomTkBase{
<div className="tw-p-2 tw-w-full tw-relative tw-h-full tw-overflow-hidden tw-content-start"
ref={this.styleAreaRef}
style={this.state.widgetInnerStyling}>
{this.props.children}
{this.renderTkinterLayout()}
</div>
</div>
)

View File

@@ -1,8 +1,10 @@
import Widget from "../../../canvas/widgets/base"
import Tools from "../../../canvas/constants/tools"
import { getPythonAssetPath } from "../../utils/pythonFilePath"
import { CustomTkBase } from "./base"
class TopLevel extends Widget{
class TopLevel extends CustomTkBase{
static widgetType = "toplevel"
static displayName = "Top Level"
@@ -27,6 +29,13 @@ class TopLevel extends Widget{
toolProps: {placeholder: "Window title", maxLength: 40},
value: "Top level",
onChange: (value) => this.setAttrValue("title", value)
},
logo: {
label: "Toplevel Logo",
tool: Tools.UPLOADED_LIST,
toolProps: {filterOptions: ["image/jpg", "image/jpeg", "image/png"]},
value: "",
onChange: (value) => this.setAttrValue("logo", value)
}
}
@@ -42,11 +51,49 @@ class TopLevel extends Widget{
const backgroundColor = this.getAttrValue("styling.backgroundColor")
return [
`${variableName} = ctk.CTkToplevel(master=${parent})`,
`${variableName}.configure(fg_color="${backgroundColor}")`,
`${variableName}.title("${this.getAttrValue("title")}")`
]
const logo = this.getAttrValue("logo")
const {width, height} = this.getSize()
const code = [
`${variableName} = ctk.CTkToplevel(master=${parent})`,
`${variableName}.configure(fg_color="${backgroundColor}")`,
`${variableName}.title("${this.getAttrValue("title")}")`,
`${variableName}.geometry("${width}x${height}")`,
...this.getGridLayoutConfigurationCode(variableName)
]
if (logo?.name){
// code.push(`\n`)
code.push(`${variableName}_img = Image.open(${getPythonAssetPath(logo.name, "image")})`)
code.push(`${variableName}_img = ImageTk.PhotoImage(${variableName}_img)`)
code.push(`${variableName}.iconphoto(False, ${variableName}_img)`)
// code.push("\n")
}
return code
}
getImports(){
const imports = super.getImports()
if (this.getAttrValue("logo"))
imports.push("import os", "from PIL import Image, ImageTk", )
return imports
}
getRequirements(){
const requirements = super.getRequirements()
if (this.getAttrValue("logo"))
requirements.push("pillow")
return requirements
}
getToolbarAttrs(){
@@ -55,8 +102,8 @@ class TopLevel extends Widget{
return ({
widgetName: toolBarAttrs.widgetName,
title: this.state.attrs.title,
logo: this.state.attrs.logo,
size: toolBarAttrs.size,
...this.state.attrs,
})
@@ -80,7 +127,7 @@ class TopLevel extends Widget{
<div className="tw-p-2 tw-w-full tw-h-full tw-content-start"
ref={this.styleAreaRef}
style={this.state.widgetInnerStyling}>
{this.props.children}
{this.renderTkinterLayout()}
</div>
</div>
)

View File

@@ -659,7 +659,7 @@ export class TkinterBase extends Widget {
{this.renderPackWidgetsRecursively(widgets, index + 1, side, previousExpandValue)}
</div>
);
};
}
@@ -842,18 +842,6 @@ export class TkinterBase extends Widget {
const {layout: parentLayout, direction, gap} = this.getParentLayout() || {}
// if (parentLayout === Layouts.FLEX){
// const fillX = this.getAttrValue("flexManager.fillX")
// const fillY = this.getAttrValue("flexManager.fillY")
// // This is needed if fillX or fillY is true, as the parent is applied flex-grow
// if (fillX || fillY){
// width = "100%"
// height = "100%"
// }
// }
const styling = {
...this.state.widgetInnerStyling,