26 changed files with 2834 additions and 408 deletions
@ -0,0 +1,159 @@
|
||||
# MIT License |
||||
# |
||||
# Copyright (c) 2024 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com> |
||||
# |
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
# of this software and associated documentation files (the "Software"), to deal |
||||
# in the Software without restriction, including without limitation the rights |
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
# copies of the Software, and to permit persons to whom the Software is |
||||
# furnished to do so, subject to the following conditions: |
||||
# |
||||
# The above copyright notice and this permission notice shall be included in all |
||||
# copies or substantial portions of the Software. |
||||
# |
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
# SOFTWARE. |
||||
|
||||
__all__ = ['ttkCrossOpen', 'ttkCrossSave', 'ttkCrossSaveAs', 'TTkEncoding', 'ttkConnectDragOpen', 'ttkEmitDragOpen', 'ttkEmitFileOpen'] |
||||
|
||||
import os |
||||
import importlib.util |
||||
import json |
||||
|
||||
from TermTk import pyTTkSlot, pyTTkSignal |
||||
from TermTk import TTkLog |
||||
from TermTk import TTkMessageBox, TTkFileDialogPicker, TTkHelper, TTkString, TTkK, TTkColor |
||||
|
||||
ttkCrossOpen = None |
||||
ttkCrossSave = None |
||||
ttkCrossSaveAs = None |
||||
ttkEmitDragOpen = None |
||||
ttkEmitFileOpen = None |
||||
ttkConnectDragOpen = None |
||||
|
||||
class TTkEncoding(str): |
||||
TEXT = "text" |
||||
TEXT_PLAIN = "text/plain" |
||||
TEXT_PLAIN_UTF8 = "text/plain;charset=utf-8" |
||||
APPLICATION = 'application' |
||||
APPLICATION_JSON = 'application/json' |
||||
IMAGE = 'image' |
||||
IMAGE_PNG = 'image/png' |
||||
IMAGE_SVG = 'image/svg+xml' |
||||
IMAGE_JPG = 'image/jpeg' |
||||
|
||||
if importlib.util.find_spec('pyodideProxy'): |
||||
TTkLog.info("Using 'pyodideProxy' as clipboard manager") |
||||
import pyodideProxy |
||||
ttkDragOpen = {} |
||||
ttkFileOpen = pyTTkSignal(dict) |
||||
|
||||
def _open(path, encoding, filter, cb=None): |
||||
if not cb: return |
||||
ttkFileOpen.connect(cb) |
||||
pyodideProxy.openFile(encoding) |
||||
|
||||
def _save(filePath, content, encoding, filter=None): |
||||
pyodideProxy.saveFile(os.path.basename(filePath), content, encoding) |
||||
|
||||
def _connectDragOpen(encoding, cb): |
||||
if not encoding in ttkDragOpen: |
||||
ttkDragOpen[encoding] = pyTTkSignal(dict) |
||||
return ttkDragOpen[encoding].connect(cb) |
||||
|
||||
def _emitDragOpen(encoding, data): |
||||
for do in [ttkDragOpen[e] for e in ttkDragOpen if encoding.startswith(e)]: |
||||
do.emit(data) |
||||
|
||||
def _emitFileOpen(encoding, data): |
||||
ttkFileOpen.emit(data) |
||||
ttkFileOpen.clear() |
||||
|
||||
ttkCrossOpen = _open |
||||
ttkCrossSave = _save |
||||
ttkCrossSaveAs = _save |
||||
ttkEmitDragOpen = _emitDragOpen |
||||
ttkEmitFileOpen = _emitFileOpen |
||||
ttkConnectDragOpen = _connectDragOpen |
||||
|
||||
else: |
||||
def _crossDecoder_text(fileName) : |
||||
with open(fileName) as fp: |
||||
return fp.read() |
||||
def _crossDecoder_json(fileName) : |
||||
with open(fileName) as fp: |
||||
# return json.load(fp) |
||||
return fp.read() |
||||
def _crossDecoder_image(fileName): |
||||
return None |
||||
|
||||
_crossDecoder = { |
||||
TTkEncoding.TEXT : _crossDecoder_text , |
||||
TTkEncoding.TEXT_PLAIN : _crossDecoder_text , |
||||
TTkEncoding.TEXT_PLAIN_UTF8 : _crossDecoder_text , |
||||
TTkEncoding.APPLICATION : _crossDecoder_json , |
||||
TTkEncoding.APPLICATION_JSON : _crossDecoder_json , |
||||
TTkEncoding.IMAGE : _crossDecoder_image , |
||||
TTkEncoding.IMAGE_PNG : _crossDecoder_image , |
||||
TTkEncoding.IMAGE_SVG : _crossDecoder_image , |
||||
TTkEncoding.IMAGE_JPG : _crossDecoder_image , |
||||
} |
||||
|
||||
def _open(path, encoding, filter, cb=None): |
||||
if not cb: return |
||||
def __openFile(fileName): |
||||
_decoder = _crossDecoder.get(encoding,lambda _:None) |
||||
content = _decoder(fileName) |
||||
cb({'name':fileName, 'data':content}) |
||||
filePicker = TTkFileDialogPicker(pos = (3,3), size=(100,30), caption="Open", path=path, fileMode=TTkK.FileMode.ExistingFile ,filter=filter) |
||||
filePicker.pathPicked.connect(__openFile) |
||||
TTkHelper.overlay(None, filePicker, 5, 5, True) |
||||
|
||||
def _save(filePath, content, encoding): |
||||
TTkLog.info(f"Saving to: {filePath}") |
||||
with open(filePath,'w') as fp: |
||||
fp.write(content) |
||||
|
||||
def _saveAs(filePath, content, encoding, filter, cb=None): |
||||
if not cb: return |
||||
def _approveFile(fileName): |
||||
if os.path.exists(fileName): |
||||
@pyTTkSlot(TTkMessageBox.StandardButton) |
||||
def _cb(btn): |
||||
if btn == TTkMessageBox.StandardButton.Save: |
||||
ttkCrossSave(fileName,content,encoding) |
||||
elif btn == TTkMessageBox.StandardButton.Cancel: |
||||
return |
||||
if cb: |
||||
cb() |
||||
messageBox = TTkMessageBox( |
||||
text= ( |
||||
TTkString( f'A file named "{os.path.basename(fileName)}" already exists.\nDo you want to replace it?', TTkColor.BOLD) + |
||||
TTkString( f'\n\nReplacing it will overwrite its contents.') ), |
||||
icon=TTkMessageBox.Icon.Warning, |
||||
standardButtons=TTkMessageBox.StandardButton.Discard|TTkMessageBox.StandardButton.Save|TTkMessageBox.StandardButton.Cancel) |
||||
messageBox.buttonSelected.connect(_cb) |
||||
TTkHelper.overlay(None, messageBox, 5, 5, True) |
||||
else: |
||||
ttkCrossSave(fileName,content,encoding) |
||||
filePicker = TTkFileDialogPicker( |
||||
size=(100,30), path=filePath, |
||||
acceptMode=TTkK.AcceptMode.AcceptSave, |
||||
caption="Save As...", |
||||
fileMode=TTkK.FileMode.AnyFile , |
||||
filter=filter) |
||||
filePicker.pathPicked.connect(_approveFile) |
||||
TTkHelper.overlay(None, filePicker, 5, 5, True) |
||||
|
||||
ttkCrossOpen = _open |
||||
ttkCrossSave = _save |
||||
ttkCrossSaveAs = _saveAs |
||||
ttkEmitDragOpen = lambda a:None |
||||
ttkEmitFileOpen = lambda a:None |
||||
ttkConnectDragOpen = lambda a,b:None |
||||
@ -1,11 +1,12 @@
|
||||
from .TTkCore import * |
||||
from .TTkTheme import * |
||||
from .TTkGui import * |
||||
from .TTkWidgets import * |
||||
from .TTkTypes import * |
||||
from .TTkLayouts import * |
||||
from .TTkCore import * |
||||
from .TTkTheme import * |
||||
from .TTkGui import * |
||||
from .TTkWidgets import * |
||||
from .TTkTypes import * |
||||
from .TTkLayouts import * |
||||
from .TTkTestWidgets import * |
||||
from .TTkAbstract import * |
||||
from .TTkUiTools import * |
||||
from .TTkAbstract import * |
||||
from .TTkUiTools import * |
||||
from .TTkCrossTools import * |
||||
|
||||
TTkCfg.theme = TTkTheme() |
||||
|
||||
@ -0,0 +1,2 @@
|
||||
https://dev.to/shubhamtiwari909/drag-and-drop-file-using-javascript-2h99 |
||||
https://www.smashingmagazine.com/2018/01/drag-drop-file-uploader-vanilla-js/ |
||||
@ -1,4 +1,8 @@
|
||||
from .maintemplate import * |
||||
from .paintarea import * |
||||
from .textarea import * |
||||
from .palette import * |
||||
from .paintarea import * |
||||
from .painttoolkit import * |
||||
from .textarea import * |
||||
from .palette import * |
||||
from .layers import * |
||||
from .canvaslayer import * |
||||
from .about import * |
||||
@ -0,0 +1,33 @@
|
||||
# MIT License |
||||
# |
||||
# Copyright (c) 2024 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com> |
||||
# |
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
# of this software and associated documentation files (the "Software"), to deal |
||||
# in the Software without restriction, including without limitation the rights |
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
# copies of the Software, and to permit persons to whom the Software is |
||||
# furnished to do so, subject to the following conditions: |
||||
# |
||||
# The above copyright notice and this permission notice shall be included in all |
||||
# copies or substantial portions of the Software. |
||||
# |
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
# SOFTWARE. |
||||
|
||||
__all__ = ['About'] |
||||
|
||||
from TermTk.TTkCore.log import TTkLog |
||||
from TermTk.TTkCore.color import TTkColor |
||||
from TermTk.TTkCore.string import TTkString |
||||
from TermTk import TTkAbout, TTkWindow |
||||
# from .cfg import TTkDesignerCfg |
||||
|
||||
class About(TTkAbout): |
||||
def paintEvent(self, canvas): |
||||
super().paintEvent(canvas) |
||||
@ -0,0 +1,374 @@
|
||||
# MIT License |
||||
# |
||||
# Copyright (c) 2024 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com> |
||||
# |
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
# of this software and associated documentation files (the "Software"), to deal |
||||
# in the Software without restriction, including without limitation the rights |
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
# copies of the Software, and to permit persons to whom the Software is |
||||
# furnished to do so, subject to the following conditions: |
||||
# |
||||
# The above copyright notice and this permission notice shall be included in all |
||||
# copies or substantial portions of the Software. |
||||
# |
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
# SOFTWARE. |
||||
|
||||
__all__ = ['CanvasLayer'] |
||||
|
||||
import sys, os |
||||
|
||||
sys.path.append(os.path.join(sys.path[0],'../..')) |
||||
import TermTk as ttk |
||||
|
||||
# Canvas Layer structure |
||||
# The data may include more areas than the visible one |
||||
# This is helpful in case of resize to not lose the drawn areas |
||||
# |
||||
# |---| OffsetX |
||||
# x |
||||
# ╭────────────────╮ - - |
||||
# │ │ | OffsetY | |
||||
# y │ ┌───────┐ │ \ - | Data |
||||
# │ │Visible│ │ | h | |
||||
# │ └───────┘ │ / | |
||||
# │ │ | |
||||
# └────────────────┘ - |
||||
# \---w--/ |
||||
|
||||
class CanvasLayer(): |
||||
class Tool(int): |
||||
MOVE = 0x01 |
||||
RESIZE = 0x02 |
||||
BRUSH = 0x04 |
||||
RECTFILL = 0x08 |
||||
RECTEMPTY = 0x10 |
||||
CLONE = 0x20 |
||||
|
||||
__slot__ = ('_pos','_name','_visible','_size','_data','_colors','_preview','_offset') |
||||
def __init__(self) -> None: |
||||
self._pos = (0,0) |
||||
self._size = (0,0) |
||||
self._offset = (0,0) |
||||
self._name = "" |
||||
self._visible = True |
||||
self._preview = None |
||||
self._data: list[list[str ]] = [] |
||||
self._colors:list[list[ttk.TTkColor]] = [] |
||||
|
||||
def pos(self): |
||||
return self._pos |
||||
def size(self): |
||||
return self._size |
||||
|
||||
def visible(self): |
||||
return self._visible |
||||
@ttk.pyTTkSlot(bool) |
||||
def setVisible(self, visible): |
||||
self._visible = visible |
||||
|
||||
def name(self): |
||||
return self._name |
||||
@ttk.pyTTkSlot(str) |
||||
def setName(self, name): |
||||
self._name = name |
||||
|
||||
def isOpaque(self,x,y): |
||||
if not self._visible: return False |
||||
ox,oy = self._offset |
||||
w,h = self._size |
||||
data = self._data |
||||
colors = self._colors |
||||
if 0<=x<w and 0<=y<h: |
||||
return data[oy+y][ox+x] != ' ' or colors[oy+y][ox+x].background() |
||||
return False |
||||
|
||||
def move(self,x,y): |
||||
self._pos=(x,y) |
||||
|
||||
def resize(self,w,h): |
||||
self._size = (w,h) |
||||
self._data = (self._data + [[] for _ in range(h)])[:h] |
||||
self._colors = (self._colors + [[] for _ in range(h)])[:h] |
||||
for i in range(h): |
||||
self._data[i] = (self._data[i] + [' ' for _ in range(w)])[:w] |
||||
self._colors[i] = (self._colors[i] + [ttk.TTkColor.RST for _ in range(w)])[:w] |
||||
|
||||
def superResize(self,dx,dy,dw,dh): |
||||
ox,oy = self._offset |
||||
x,y = self.pos() |
||||
w,h = self.size() |
||||
daw = len(self._data[0]) |
||||
dah = len(self._data) |
||||
diffx = dx-x |
||||
diffy = dy-y |
||||
self._preview = None |
||||
if ox < x-dx: # we need to resize and move ox |
||||
_nw = x-dx-ox |
||||
ox = x-dx |
||||
self._data = [([' ']*_nw ) + _r for _r in self._data] |
||||
self._colors = [([ttk.TTkColor.RST]*_nw) + _r for _r in self._colors] |
||||
if dw+ox > daw: |
||||
_nw = dw+ox-daw |
||||
self._data = [_r + ([' ']*_nw ) for _r in self._data] |
||||
self._colors = [_r + ([ttk.TTkColor.RST]*_nw) for _r in self._colors] |
||||
daw = len(self._data[0]) |
||||
if oy < y-dy: # we need to resize and move ox |
||||
_nh = y-dy-oy |
||||
oy = y-dy |
||||
self._data = [[' ']*daw for _ in range(_nh)] + self._data |
||||
self._colors = [[ttk.TTkColor.RST]*daw for _ in range(_nh)] + self._colors |
||||
if dh+oy > dah: |
||||
_nh = dh+oy-dah |
||||
self._data = self._data + [[' ']*daw for _ in range(_nh)] |
||||
self._colors = self._colors + [[ttk.TTkColor.RST]*daw for _ in range(_nh)] |
||||
self._offset = (ox+diffx,oy+diffy) |
||||
self._pos = (dx,dy) |
||||
self._size = (dw,dh) |
||||
|
||||
|
||||
def clean(self): |
||||
w,h = self._size |
||||
self._offset = (0,0) |
||||
self._preview = None |
||||
for i in range(h): |
||||
self._data[i] = [' ']*w |
||||
self._colors[i] = [ttk.TTkColor.RST]*w |
||||
|
||||
|
||||
def exportLayer(self, full=False, palette=True, crop=True): |
||||
# xa|----------| xb |
||||
# px |-----------| = max(px,px+xa-ox) |
||||
# Offset |------| pw |
||||
# Data |----------------------------| |
||||
# daw |
||||
|
||||
# Don't try this at home |
||||
ox,oy = self._offset |
||||
px,py = self.pos() |
||||
pw,ph = self.size() |
||||
|
||||
if full: |
||||
data = self._data |
||||
colors = self._colors |
||||
else: |
||||
data = [row[ox:ox+pw] for row in self._data[ oy:oy+ph] ] |
||||
colors = [row[ox:ox+pw] for row in self._colors[oy:oy+ph] ] |
||||
ox=oy=0 |
||||
|
||||
daw = len(data[0]) |
||||
dah = len(data) |
||||
|
||||
# get the bounding box |
||||
if crop: |
||||
xa,xb,ya,yb = daw,0,dah,0 |
||||
for y,(drow,crow) in enumerate(zip(data,colors)): |
||||
for x,(d,c) in enumerate(zip(drow,crow)): |
||||
if d != ' ' or c.background(): |
||||
xa = min(x,xa) |
||||
xb = max(x,xb) |
||||
ya = min(y,ya) |
||||
yb = max(y,yb) |
||||
if (xa,xb,ya,yb) == (daw,0,dah,0): |
||||
xa=xb=ya=yb=0 |
||||
else: |
||||
xa,xb,ya,yb = 0,daw,0,dah |
||||
|
||||
# Visble Area intersecting the bounding box |
||||
vxa,vya = max(px,px+xa-ox), max(py,py+ya-oy) |
||||
vxb,vyb = min(px+pw,vxa+xb-xa),min(py+ph,vya+yb-ya) |
||||
vw,vh = vxb-vxa+1, vyb-vya+1 |
||||
|
||||
outData = { |
||||
'version':'1.1.0', |
||||
'size':[vw,vh], |
||||
'pos': (vxa,vya), |
||||
'name':str(self.name()), |
||||
'data':[], 'colors':[]} |
||||
|
||||
if palette: |
||||
palette = outData['palette'] = [] |
||||
for row in colors: |
||||
for c in row: |
||||
fg = f"{c.getHex(ttk.TTkK.Foreground)}" if c.foreground() else None |
||||
bg = f"{c.getHex(ttk.TTkK.Background)}" if c.background() else None |
||||
if (pc:=(fg,bg)) not in palette: |
||||
palette.append(pc) |
||||
|
||||
if full: |
||||
wslice = slice(xa,xb+1) |
||||
hslice = slice(ya,yb+1) |
||||
outData['offset'] = (max(0,ox-xa),max(0,oy-ya)) |
||||
else: |
||||
wslice = slice(ox+vxa-px,ox+vxa-px+vw) |
||||
hslice = slice(oy+vya-py,oy+vya-py+vh) |
||||
|
||||
for row in data[hslice]: |
||||
outData['data'].append(row[wslice]) |
||||
for row in colors[hslice]: |
||||
outData['colors'].append([]) |
||||
for c in row[wslice]: |
||||
fg = f"{c.getHex(ttk.TTkK.Foreground)}" if c.foreground() else None |
||||
bg = f"{c.getHex(ttk.TTkK.Background)}" if c.background() else None |
||||
if palette: |
||||
outData['colors'][-1].append(palette.index((fg,bg))) |
||||
else: |
||||
outData['colors'][-1].append((fg,bg)) |
||||
|
||||
return outData |
||||
|
||||
def _import_v1_1_0(self, dd): |
||||
self._import_v1_0_0(dd) |
||||
self._offset = dd.get('offset',(0,0)) |
||||
|
||||
def _import_v1_0_0(self, dd): |
||||
self._pos = dd['pos'] |
||||
self._size = dd['size'] |
||||
self._name = dd['name'] |
||||
self._data = dd['data'] |
||||
def _getColor(cd): |
||||
fg,bg = cd |
||||
if fg and bg: return ttk.TTkColor.fg(fg)+ttk.TTkColor.bg(bg) |
||||
elif fg: return ttk.TTkColor.fg(fg) |
||||
elif bg: return ttk.TTkColor.bg(bg) |
||||
else: return ttk.TTkColor.RST |
||||
if 'palette' in dd: |
||||
palette = [_getColor(c) for c in dd['palette']] |
||||
self._colors = [[palette[c] for c in row] for row in dd['colors']] |
||||
else: |
||||
self._colors = [[_getColor(c) for c in row] for row in dd['colors']] |
||||
|
||||
def _import_v0_0_0(self, dd): |
||||
# Legacy old import |
||||
w = len(dd['data'][0]) + 10 |
||||
h = len(dd['data']) + 4 |
||||
x,y=5,2 |
||||
self.resize(w,h) |
||||
self._pos = (0,0) |
||||
for i,rd in enumerate(dd['data']): |
||||
for ii,cd in enumerate(rd): |
||||
self._data[i+y][ii+x] = cd |
||||
for i,rd in enumerate(dd['colors']): |
||||
for ii,cd in enumerate(rd): |
||||
fg,bg = cd |
||||
if fg and bg: |
||||
self._colors[i+y][ii+x] = ttk.TTkColor.fg(fg)+ttk.TTkColor.bg(bg) |
||||
elif fg: |
||||
self._colors[i+y][ii+x] = ttk.TTkColor.fg(fg) |
||||
elif bg: |
||||
self._colors[i+y][ii+x] = ttk.TTkColor.bg(bg) |
||||
else: |
||||
self._colors[i+y][ii+x] = ttk.TTkColor.RST |
||||
|
||||
def importLayer(self, dd): |
||||
self.clean() |
||||
|
||||
if 'version' in dd: |
||||
ver = dd['version'] |
||||
if ver == ('1.0.0'): |
||||
self._import_v1_0_0(dd) |
||||
elif ver == ('1.1.0'): |
||||
self._import_v1_1_0(dd) |
||||
else: |
||||
self._import_v0_0_0(dd) |
||||
|
||||
def placeFill(self,geometry,tool,glyph:str,color:ttk.TTkColor,preview=False): |
||||
ox,oy = self._offset |
||||
w,h = self._size |
||||
ax,ay,bx,by = geometry |
||||
ax = max(0,min(w-1,ax)) |
||||
ay = max(0,min(h-1,ay)) |
||||
bx = max(0,min(w-1,bx)) |
||||
by = max(0,min(h-1,by)) |
||||
fax,fay = ox+min(ax,bx), oy+min(ay,by) |
||||
fbx,fby = ox+max(ax,bx), oy+max(ay,by) |
||||
|
||||
color = color if glyph != ' ' else color.background() |
||||
color = color if color else ttk.TTkColor.RST |
||||
if preview: |
||||
data = [_r.copy() for _r in self._data] |
||||
colors = [_r.copy() for _r in self._colors] |
||||
self._preview = {'data':data,'colors':colors} |
||||
else: |
||||
self._preview = None |
||||
data = self._data |
||||
colors = self._colors |
||||
|
||||
if tool == CanvasLayer.Tool.RECTFILL: |
||||
for row in data[fay:fby+1]: |
||||
row[fax:fbx+1] = [glyph]*(fbx-fax+1) |
||||
for row in colors[fay:fby+1]: |
||||
row[fax:fbx+1] = [color]*(fbx-fax+1) |
||||
if tool == CanvasLayer.Tool.RECTEMPTY: |
||||
data[fay][fax:fbx+1] = [glyph]*(fbx-fax+1) |
||||
data[fby][fax:fbx+1] = [glyph]*(fbx-fax+1) |
||||
colors[fay][fax:fbx+1] = [color]*(fbx-fax+1) |
||||
colors[fby][fax:fbx+1] = [color]*(fbx-fax+1) |
||||
for row in data[fay:fby]: |
||||
row[fax]=row[fbx]=glyph |
||||
for row in colors[fay:fby]: |
||||
row[fax]=row[fbx]=color |
||||
return True |
||||
|
||||
def placeGlyph(self,x,y,glyph:str,color:ttk.TTkColor,preview=False): |
||||
ox,oy = self._offset |
||||
w,h = self._size |
||||
color = color if glyph != ' ' else color.background() |
||||
color = color if color else ttk.TTkColor.RST |
||||
if preview: |
||||
data = [_r.copy() for _r in self._data] |
||||
colors = [_r.copy() for _r in self._colors] |
||||
self._preview = {'data':data,'colors':colors} |
||||
else: |
||||
self._preview = None |
||||
data = self._data |
||||
colors = self._colors |
||||
if 0<=x<w and 0<=y<h: |
||||
data[ oy+y][ox+x] = glyph |
||||
colors[oy+y][ox+x] = color |
||||
return True |
||||
return False |
||||
|
||||
def drawInCanvas(self, pos, canvas:ttk.TTkCanvas): |
||||
if not self._visible: return |
||||
px,py = pos |
||||
pw,ph = self._size |
||||
cw,ch = canvas.size() |
||||
if px+pw<0 or py+ph<0:return |
||||
if px>=cw or py>=ch:return |
||||
# Data Offset |
||||
ox,oy = self._offset |
||||
# x,y position in the Canvas |
||||
cx = max(0,px) |
||||
cy = max(0,py) |
||||
# x,y position in the Layer |
||||
lx,ly = (cx-px),(cy-py) |
||||
# Area to be copyed |
||||
dw = min(cw-cx,pw-lx) |
||||
dh = min(ch-cy,ph-ly) |
||||
|
||||
if _p := self._preview: |
||||
data = _p['data'] |
||||
colors = _p['colors'] |
||||
else: |
||||
data = self._data |
||||
colors = self._colors |
||||
for y in range(cy,cy+dh): |
||||
for x in range(cx,cx+dw): |
||||
gl = data[ oy+y+ly-cy][ox+x+lx-cx] |
||||
c = colors[oy+y+ly-cy][ox+x+lx-cx] |
||||
if gl==' ' and c._bg: |
||||
canvas._data[y][x] = gl |
||||
canvas._colors[y][x] = c |
||||
elif gl!=' ': |
||||
canvas._data[y][x] = gl |
||||
cc = canvas._colors[y][x] |
||||
newC = c.copy() |
||||
newC._bg = c._bg if c._bg else cc._bg |
||||
canvas._colors[y][x] = newC |
||||
@ -0,0 +1,324 @@
|
||||
# MIT License |
||||
# |
||||
# Copyright (c) 2024 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com> |
||||
# |
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
# of this software and associated documentation files (the "Software"), to deal |
||||
# in the Software without restriction, including without limitation the rights |
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
# copies of the Software, and to permit persons to whom the Software is |
||||
# furnished to do so, subject to the following conditions: |
||||
# |
||||
# The above copyright notice and this permission notice shall be included in all |
||||
# copies or substantial portions of the Software. |
||||
# |
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
# SOFTWARE. |
||||
|
||||
__all__ = ['Layers','LayerData'] |
||||
|
||||
import sys, os |
||||
|
||||
sys.path.append(os.path.join(sys.path[0],'../..')) |
||||
import TermTk as ttk |
||||
|
||||
class LayerData(): |
||||
__slots__ = ('_name','_data', |
||||
#signals |
||||
'nameChanged','visibilityToggled') |
||||
def __init__(self,name:ttk.TTkString=ttk.TTkString('New'),data=None) -> None: |
||||
self._name:ttk.TTkString = ttk.TTkString(name) if type(name)==str else name |
||||
self.visibilityToggled = ttk.pyTTkSignal(bool) |
||||
self._data = data |
||||
self.nameChanged = ttk.pyTTkSignal(str) |
||||
def name(self): |
||||
return self._name |
||||
def setName(self,name): |
||||
self.nameChanged.emit(name) |
||||
self._name = name |
||||
def data(self): |
||||
return self._data |
||||
def setData(self,data): |
||||
self._data = data |
||||
|
||||
class _layerButton(ttk.TTkContainer): |
||||
classStyle = { |
||||
'default': {'color': ttk.TTkColor.fg("#dddd88")+ttk.TTkColor.bg("#000044"), |
||||
'borderColor': ttk.TTkColor.fg('#CCDDDD'), |
||||
'grid':1}, |
||||
'disabled': {'color': ttk.TTkColor.fg('#888888'), |
||||
'borderColor':ttk.TTkColor.fg('#888888'), |
||||
'grid':0}, |
||||
'hover': {'color': ttk.TTkColor.fg("#dddd88")+ttk.TTkColor.bg("#000050")+ttk.TTkColor.BOLD, |
||||
'borderColor': ttk.TTkColor.fg("#FFFFCC")+ttk.TTkColor.BOLD, |
||||
'grid':1}, |
||||
'selected': {'color': ttk.TTkColor.fg("#dddd88")+ttk.TTkColor.bg("#004488"), |
||||
'borderColor': ttk.TTkColor.fg("#FFFF00"), |
||||
'grid':0}, |
||||
'unchecked': {'color': ttk.TTkColor.fg("#dddd88")+ttk.TTkColor.bg("#000044"), |
||||
'borderColor': ttk.TTkColor.RST, |
||||
'grid':3}, |
||||
'clicked': {'color': ttk.TTkColor.fg("#FFFFDD")+ttk.TTkColor.BOLD, |
||||
'borderColor': ttk.TTkColor.fg("#DDDDDD")+ttk.TTkColor.BOLD, |
||||
'grid':0}, |
||||
'focus': {'color': ttk.TTkColor.fg("#dddd88")+ttk.TTkColor.bg("#000044")+ttk.TTkColor.BOLD, |
||||
'borderColor': ttk.TTkColor.fg("#ffff00") + ttk.TTkColor.BOLD, |
||||
'grid':1}, |
||||
} |
||||
|
||||
__slots__ = ('_layerData','_first', '_isSelected', '_layerVisible', |
||||
'_ledit', |
||||
# signals |
||||
'clicked', 'visibilityToggled', |
||||
) |
||||
def __init__(self, layer:LayerData, **kwargs): |
||||
self.clicked = ttk.pyTTkSignal(_layerButton) |
||||
self._layerData:LayerData = layer |
||||
self._isSelected = False |
||||
self._first = True |
||||
self._layerVisible = True |
||||
self.visibilityToggled = layer.visibilityToggled |
||||
|
||||
super().__init__(**kwargs|{'layout':ttk.TTkGridLayout()}) |
||||
self.setPadding(1,1,7,2) |
||||
self._ledit = ttk.TTkLineEdit(parent=self, text=layer.name(),visible=False) |
||||
self._ledit.focusChanged.connect(self._ledit.setVisible) |
||||
self._ledit.textEdited.connect(self._textEdited) |
||||
# self.setFocusPolicy(ttk.TTkK.ClickFocus) |
||||
|
||||
@ttk.pyTTkSlot(str) |
||||
def _textEdited(self, text): |
||||
self._layerData.setName(text) |
||||
|
||||
def mousePressEvent(self, evt) -> bool: |
||||
if evt.x <= 3: |
||||
self._layerVisible = not self._layerVisible |
||||
self.visibilityToggled.emit(self._layerVisible) |
||||
self.setFocus() |
||||
self.update() |
||||
return True |
||||
|
||||
def mouseReleaseEvent(self, evt) -> bool: |
||||
self.clicked.emit(self) |
||||
return True |
||||
|
||||
def mouseDoubleClickEvent(self, evt) -> bool: |
||||
self._ledit.setVisible(True) |
||||
self._ledit.setFocus() |
||||
return True |
||||
|
||||
def mouseDragEvent(self, evt) -> bool: |
||||
drag = ttk.TTkDrag() |
||||
drag.setData(self) |
||||
name = self._layerData.name() |
||||
pm = ttk.TTkCanvas(width=len(name)+4,height=3) |
||||
pm.drawBox(pos=(0,0),size=pm.size()) |
||||
pm.drawText(pos=(2,1), text=name) |
||||
drag.setHotSpot(5, 1) |
||||
drag.setPixmap(pm) |
||||
drag.exec() |
||||
return True |
||||
|
||||
def paintEvent(self, canvas: ttk.TTkCanvas): |
||||
if self._isSelected: |
||||
style = self.style()['selected'] |
||||
else: |
||||
style = self.currentStyle() |
||||
borderColor = style['borderColor'] |
||||
textColor = style['color'] |
||||
btnVisible = '▣' if self._layerVisible else '□' |
||||
w,h = self.size() |
||||
canvas.drawText( pos=(0,0),text=f" ┏{'━'*(w-7)}┓",color=borderColor) |
||||
canvas.drawText( pos=(0,2),text=f" ┗{'━'*(w-7)}┛",color=borderColor) |
||||
if self._first: |
||||
canvas.drawText(pos=(0,1),text=f" {btnVisible} - ┃{' '*(w-7)}┃",color=borderColor) |
||||
else: |
||||
canvas.drawText(pos=(0,1),text=f" {btnVisible} - ╽{' '*(w-7)}╽",color=borderColor) |
||||
canvas.drawTTkString(pos=(7,1),text=self._layerData.name(), width=w-9, color=textColor) |
||||
|
||||
class LayerScrollWidget(ttk.TTkAbstractScrollView): |
||||
__slots__ = ('_layers','_selected', '_dropTo', |
||||
# Signals |
||||
'layerSelected','layerAdded','layerDeleted','layersOrderChanged') |
||||
def __init__(self, **kwargs): |
||||
self.layerSelected = ttk.pyTTkSignal(LayerData) |
||||
self.layerAdded = ttk.pyTTkSignal(LayerData) |
||||
self.layerDeleted = ttk.pyTTkSignal(LayerData) |
||||
self.layersOrderChanged = ttk.pyTTkSignal(list[LayerData]) |
||||
|
||||
self._selected = None |
||||
self._dropTo = None |
||||
self._layers:list[_layerButton] = [] |
||||
super().__init__(**kwargs) |
||||
self.viewChanged.connect(self._placeTheButtons) |
||||
self.viewChanged.connect(self._viewChangedHandler) |
||||
|
||||
@ttk.pyTTkSlot() |
||||
def _viewChangedHandler(self): |
||||
x,y = self.getViewOffsets() |
||||
self.layout().setOffset(-x,-y) |
||||
|
||||
def viewFullAreaSize(self) -> tuple: |
||||
_,_,w,h = self.layout().fullWidgetAreaGeometry() |
||||
return w,h |
||||
|
||||
def viewDisplayedSize(self) -> tuple: |
||||
return self.size() |
||||
|
||||
def maximumWidth(self): return 0x10000 |
||||
def maximumHeight(self): return 0x10000 |
||||
def minimumWidth(self): return 0 |
||||
def minimumHeight(self): return 0 |
||||
|
||||
@ttk.pyTTkSlot(_layerButton) |
||||
def _clickedLayer(self, layerButton:_layerButton): |
||||
if sel:=self._selected: |
||||
sel._isSelected = False |
||||
sel.update() |
||||
self._selected = layerButton |
||||
layerButton._isSelected = True |
||||
self.layerSelected.emit(layerButton._layerData) |
||||
self.update() |
||||
|
||||
def clear(self): |
||||
for layBtn in self._layers: |
||||
self.layout().removeWidget(layBtn) |
||||
layBtn.clicked.clear() |
||||
layBtn.visibilityToggled.clear() |
||||
layBtn._layerData.nameChanged.clear() |
||||
self._layers.clear() |
||||
self.update() |
||||
|
||||
@ttk.pyTTkSlot() |
||||
def moveUp(self): |
||||
return self._moveButton(-1) |
||||
|
||||
@ttk.pyTTkSlot() |
||||
def moveDown(self): |
||||
return self._moveButton(+1) |
||||
|
||||
def _moveButton(self,direction): |
||||
if not self._selected: return |
||||
index = self._layers.index(self._selected) |
||||
if index+direction < 0: return |
||||
l = self._layers.pop(index) |
||||
self._layers.insert(index+direction,l) |
||||
self._placeTheButtons() |
||||
self.layersOrderChanged.emit([_l._layerData for _l in self._layers]) |
||||
|
||||
@ttk.pyTTkSlot() |
||||
def addLayer(self,name=None, data=None): |
||||
name = name if name else f"Layer #{len(self._layers)}" |
||||
_l=LayerData(name=name,data=data) |
||||
newLayerBtn:_layerButton = _layerButton(parent=self,layer=_l) |
||||
self._layers.insert(0,newLayerBtn) |
||||
if sel:=self._selected: sel._isSelected = False |
||||
self._selected = newLayerBtn |
||||
newLayerBtn._isSelected = True |
||||
newLayerBtn.clicked.connect(self._clickedLayer) |
||||
self.viewChanged.emit() |
||||
self._placeTheButtons() |
||||
self.layerAdded.emit(newLayerBtn._layerData) |
||||
return _l |
||||
|
||||
def _placeTheButtons(self): |
||||
w,h = self.size() |
||||
for i,l in enumerate(self._layers): |
||||
l._first = i==0 |
||||
l.setGeometry(0,i*2,w,3) |
||||
l.lowerWidget() |
||||
self.update() |
||||
|
||||
@ttk.pyTTkSlot() |
||||
def delLayer(self): |
||||
self._layers.remove() |
||||
|
||||
def dragEnterEvent(self, evt) -> bool: |
||||
if type(evt.data())!=_layerButton: return False |
||||
x,y = self.getViewOffsets() |
||||
self._dropTo = max(0,min(len(self._layers),(evt.y-1+y)//2)) |
||||
self.update() |
||||
return True |
||||
def dragLeaveEvent(self, evt) -> bool: |
||||
if type(evt.data())!=_layerButton: return False |
||||
self._dropTo = None |
||||
self.update() |
||||
return True |
||||
def dragMoveEvent(self, evt) -> bool: |
||||
if type(evt.data())!=_layerButton: return False |
||||
x,y = self.getViewOffsets() |
||||
self._dropTo = max(0,min(len(self._layers),(evt.y-1+y)//2)) |
||||
self.update() |
||||
ttk.TTkLog.debug(f"{evt.x},{evt.y-y} - {len(self._layers)} - {self._dropTo}") |
||||
return True |
||||
def dropEvent(self, evt) -> bool: |
||||
if type(evt.data())!=_layerButton: return False |
||||
x,y = self.getViewOffsets() |
||||
self._dropTo = None |
||||
data = evt.data() |
||||
# dropPos = len(self._layers)-(evt.y-1)//2 |
||||
dropPos = max(0,min(len(self._layers),(evt.y-1+y)//2)) |
||||
ttk.TTkLog.debug(f"{evt.x},{evt.y-y} - {len(self._layers)} - {self._dropTo} {dropPos}") |
||||
if dropPos > self._layers.index(data): |
||||
dropPos -= 1 |
||||
self._layers.remove(data) |
||||
self._layers.insert(dropPos,data) |
||||
self._placeTheButtons() |
||||
self.layersOrderChanged.emit([_l._layerData for _l in self._layers]) |
||||
return True |
||||
|
||||
# Stupid hack to paint on top of the child widgets |
||||
def paintChildCanvas(self): |
||||
super().paintChildCanvas() |
||||
offx, offy = self.getViewOffsets() |
||||
if self._dropTo == None: return |
||||
canvas = self.getCanvas() |
||||
w,h = canvas.size() |
||||
color = ttk.TTkColor.YELLOW |
||||
canvas.drawText(pos=(0,(self._dropTo)*2-offy),text=f"╞{'═'*(w-2)}╍",color=color) |
||||
|
||||
|
||||
|
||||
class Layers(ttk.TTkGridLayout): |
||||
__slots__ = ('_scrollWidget', |
||||
# Forward Methods |
||||
'addLayer','clear', |
||||
# Forward Signals |
||||
'layerSelected','layerAdded','layerDeleted','layersOrderChanged') |
||||
def __init__(self, **kwargs): |
||||
super().__init__(**kwargs) |
||||
self._scrollWidget = _lsw = LayerScrollWidget() |
||||
_sa = ttk.TTkAbstractScrollArea(scrollWidget=self._scrollWidget,minWidth=16) |
||||
_sa.setViewport(_lsw) |
||||
self.addWidget(_sa,0,0,1,5) |
||||
self.addWidget(btnAdd :=ttk.TTkButton(text='add') ,1,0) |
||||
self.addWidget(btnUp :=ttk.TTkButton(text='▲',maxWidth=3) ,1,1) |
||||
self.addWidget(btnDown:=ttk.TTkButton(text='▼',maxWidth=3) ,1,2) |
||||
# self.addItem(ttk.TTkLayout(),1,3) |
||||
self.addWidget(btnDel :=ttk.TTkButton(text=ttk.TTkString('del',ttk.TTkColor.RED),maxWidth=5),1,4) |
||||
|
||||
btnAdd.setToolTip( "Create a new Layer\nand add it to the image") |
||||
btnDel.setToolTip( "Delete the selected Layer") |
||||
btnUp.setToolTip( "Raise the selected Layer one step") |
||||
btnDown.setToolTip("Lower the selected Layer one step") |
||||
|
||||
btnAdd.clicked.connect( _lsw.addLayer) |
||||
btnDel.clicked.connect( _lsw.delLayer) |
||||
btnUp.clicked.connect( _lsw.moveUp) |
||||
btnDown.clicked.connect(_lsw.moveDown) |
||||
|
||||
# forward signals |
||||
self.layerSelected = _lsw.layerSelected |
||||
self.layerSelected = _lsw.layerSelected |
||||
self.layerAdded = _lsw.layerAdded |
||||
self.layerDeleted = _lsw.layerDeleted |
||||
self.layersOrderChanged = _lsw.layersOrderChanged |
||||
|
||||
# forward methods |
||||
self.addLayer = _lsw.addLayer |
||||
self.clear = _lsw.clear |
||||
@ -0,0 +1,123 @@
|
||||
# MIT License |
||||
# |
||||
# Copyright (c) 2024 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com> |
||||
# |
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
# of this software and associated documentation files (the "Software"), to deal |
||||
# in the Software without restriction, including without limitation the rights |
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
# copies of the Software, and to permit persons to whom the Software is |
||||
# furnished to do so, subject to the following conditions: |
||||
# |
||||
# The above copyright notice and this permission notice shall be included in all |
||||
# copies or substantial portions of the Software. |
||||
# |
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
# SOFTWARE. |
||||
|
||||
__all__ = ['PaintToolKit'] |
||||
|
||||
import sys, os |
||||
|
||||
sys.path.append(os.path.join(sys.path[0],'../..')) |
||||
import TermTk as ttk |
||||
|
||||
from .paintarea import * |
||||
|
||||
class PaintToolKit(ttk.TTkContainer): |
||||
__slots__ = ('_rSelect', '_rPaint', '_lgliph', |
||||
'_cbFg', '_cbBg', |
||||
'_bpFg', '_bpBg', '_bpDef', |
||||
'_sbDx','_sbDy','_sbDw','_sbDh', |
||||
'_sbLx','_sbLy','_sbLw','_sbLh', |
||||
'_glyph', |
||||
#Signals |
||||
'updatedColor', 'updatedTrans') |
||||
def __init__(self, *args, **kwargs): |
||||
ttk.TTkUiLoader.loadFile(os.path.join(os.path.dirname(os.path.abspath(__file__)),"tui/paintToolKit.tui.json"),self) |
||||
self._glyph = 'X' |
||||
self.updatedColor = ttk.pyTTkSignal(ttk.TTkColor) |
||||
self.updatedTrans = ttk.pyTTkSignal(ttk.TTkColor) |
||||
self._lgliph = self.getWidgetByName("lglyph") |
||||
self._cbFg = self.getWidgetByName("cbFg") |
||||
self._cbBg = self.getWidgetByName("cbBg") |
||||
self._bpFg = self.getWidgetByName("bpFg") |
||||
self._bpBg = self.getWidgetByName("bpBg") |
||||
self._bpDef = self.getWidgetByName("bpDef") |
||||
|
||||
self._sbDx = self.getWidgetByName("sbDx") |
||||
self._sbDy = self.getWidgetByName("sbDy") |
||||
self._sbDw = self.getWidgetByName("sbDw") |
||||
self._sbDh = self.getWidgetByName("sbDh") |
||||
self._sbLx = self.getWidgetByName("sbLx") |
||||
self._sbLy = self.getWidgetByName("sbLy") |
||||
self._sbLw = self.getWidgetByName("sbLw") |
||||
self._sbLh = self.getWidgetByName("sbLh") |
||||
|
||||
self._bpDef.setColor(ttk.TTkColor.bg('#FF00FF')) |
||||
self._cbFg.toggled.connect(self._refreshColor) |
||||
self._cbBg.toggled.connect(self._refreshColor) |
||||
|
||||
self._bpFg.colorSelected.connect(self._refreshColor) |
||||
self._bpBg.colorSelected.connect(self._refreshColor) |
||||
self._bpDef.colorSelected.connect(self.updatedTrans.emit) |
||||
|
||||
self._refreshColor(emit=False) |
||||
|
||||
@ttk.pyTTkSlot(CanvasLayer) |
||||
def updateLayer(self, layer:CanvasLayer): |
||||
lx,ly = layer.pos() |
||||
lw,lh = layer.size() |
||||
self._sbLx.setValue(lx) |
||||
self._sbLy.setValue(ly) |
||||
self._sbLw.setValue(lw) |
||||
self._sbLh.setValue(lh) |
||||
|
||||
@ttk.pyTTkSlot() |
||||
def _refreshColor(self, emit=True): |
||||
color =self.color() |
||||
self._lgliph.setText( |
||||
ttk.TTkString("Glyph: '") + |
||||
ttk.TTkString(self._glyph,color) + |
||||
ttk.TTkString("'")) |
||||
if emit: |
||||
self.updatedColor.emit(color) |
||||
|
||||
@ttk.pyTTkSlot(ttk.TTkString) |
||||
def glyphFromString(self, ch:ttk.TTkString): |
||||
if len(ch)<=0: return |
||||
self._glyph = ch.charAt(0) |
||||
self._refreshColor() |
||||
# self.setColor(ch.colorAt(0)) |
||||
|
||||
def color(self): |
||||
color = ttk.TTkColor() |
||||
if self._cbFg.checkState() == ttk.TTkK.Checked: |
||||
color += self._bpFg.color().invertFgBg() |
||||
if self._cbBg.checkState() == ttk.TTkK.Checked: |
||||
color += self._bpBg.color() |
||||
return color |
||||
|
||||
@ttk.pyTTkSlot(ttk.TTkColor) |
||||
def setColor(self, color:ttk.TTkColor): |
||||
if fg := color.foreground(): |
||||
self._cbFg.setCheckState(ttk.TTkK.Checked) |
||||
self._bpFg.setEnabled() |
||||
self._bpFg.setColor(fg.invertFgBg()) |
||||
else: |
||||
self._cbFg.setCheckState(ttk.TTkK.Unchecked) |
||||
self._bpFg.setDisabled() |
||||
|
||||
if bg := color.background(): |
||||
self._cbBg.setCheckState(ttk.TTkK.Checked) |
||||
self._bpBg.setEnabled() |
||||
self._bpBg.setColor(bg) |
||||
else: |
||||
self._cbBg.setCheckState(ttk.TTkK.Unchecked) |
||||
self._bpBg.setDisabled() |
||||
self._refreshColor(emit=False) |
||||
@ -0,0 +1,918 @@
|
||||
{ |
||||
"version": "2.0.0", |
||||
"tui": { |
||||
"class": "TTkContainer", |
||||
"params": { |
||||
"Name": "MainWindow", |
||||
"Position": [ |
||||
4, |
||||
2 |
||||
], |
||||
"Size": [ |
||||
78, |
||||
2 |
||||
], |
||||
"Min Width": 50, |
||||
"Min Height": 2, |
||||
"Max Width": 65536, |
||||
"Max Height": 2, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Padding": [ |
||||
0, |
||||
0, |
||||
0, |
||||
0 |
||||
], |
||||
"Layout": "TTkLayout" |
||||
}, |
||||
"layout": { |
||||
"class": "TTkLayout", |
||||
"params": { |
||||
"Geometry": [ |
||||
0, |
||||
0, |
||||
78, |
||||
2 |
||||
] |
||||
}, |
||||
"children": [ |
||||
{ |
||||
"class": "TTkCheckbox", |
||||
"params": { |
||||
"Name": "cbFg", |
||||
"Position": [ |
||||
12, |
||||
0 |
||||
], |
||||
"Size": [ |
||||
5, |
||||
1 |
||||
], |
||||
"Min Width": 5, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 1, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "Fg", |
||||
"Tristate": false, |
||||
"Checked": false, |
||||
"Check State": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkCheckbox", |
||||
"params": { |
||||
"Name": "cbBg", |
||||
"Position": [ |
||||
12, |
||||
1 |
||||
], |
||||
"Size": [ |
||||
5, |
||||
1 |
||||
], |
||||
"Min Width": 5, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 1, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "Bg", |
||||
"Tristate": false, |
||||
"Checked": false, |
||||
"Check State": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkLabel", |
||||
"params": { |
||||
"Name": "TTkLabel-1", |
||||
"Position": [ |
||||
0, |
||||
1 |
||||
], |
||||
"Size": [ |
||||
5, |
||||
1 |
||||
], |
||||
"Min Width": 5, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "Trans", |
||||
"Color": "\u001b[0m", |
||||
"Alignment": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkLabel", |
||||
"params": { |
||||
"Name": "lglyph", |
||||
"Position": [ |
||||
0, |
||||
0 |
||||
], |
||||
"Size": [ |
||||
12, |
||||
1 |
||||
], |
||||
"Min Width": 6, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "Glyph:", |
||||
"Color": "\u001b[0m", |
||||
"Alignment": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkColorButtonPicker", |
||||
"params": { |
||||
"Name": "bpDef", |
||||
"Position": [ |
||||
5, |
||||
1 |
||||
], |
||||
"Size": [ |
||||
6, |
||||
1 |
||||
], |
||||
"Min Width": 1, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 1, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "", |
||||
"Border": false, |
||||
"Checkable": false, |
||||
"Checked": false, |
||||
"Color": "\u001b[48;2;0;0;0m" |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkLabel", |
||||
"params": { |
||||
"Name": "TTkLabel-2", |
||||
"Position": [ |
||||
25, |
||||
0 |
||||
], |
||||
"Size": [ |
||||
3, |
||||
1 |
||||
], |
||||
"Min Width": 3, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "Doc", |
||||
"Color": "\u001b[0m", |
||||
"Alignment": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkColorButtonPicker", |
||||
"params": { |
||||
"Name": "bpBg", |
||||
"Position": [ |
||||
17, |
||||
1 |
||||
], |
||||
"Size": [ |
||||
6, |
||||
1 |
||||
], |
||||
"Min Width": 2, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 1, |
||||
"Visible": true, |
||||
"Enabled": false, |
||||
"ToolTip": "", |
||||
"Text": "", |
||||
"Border": false, |
||||
"Checkable": false, |
||||
"Checked": false, |
||||
"Color": "\u001b[48;2;0;0;0m" |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkColorButtonPicker", |
||||
"params": { |
||||
"Name": "bpFg", |
||||
"Position": [ |
||||
17, |
||||
0 |
||||
], |
||||
"Size": [ |
||||
6, |
||||
1 |
||||
], |
||||
"Min Width": 2, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 1, |
||||
"Visible": true, |
||||
"Enabled": false, |
||||
"ToolTip": "", |
||||
"Text": "", |
||||
"Border": false, |
||||
"Checkable": false, |
||||
"Checked": false, |
||||
"Color": "\u001b[48;2;0;0;0m" |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkLabel", |
||||
"params": { |
||||
"Name": "TTkLabel-4", |
||||
"Position": [ |
||||
29, |
||||
0 |
||||
], |
||||
"Size": [ |
||||
1, |
||||
1 |
||||
], |
||||
"Min Width": 1, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "x", |
||||
"Color": "\u001b[0m", |
||||
"Alignment": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkLabel", |
||||
"params": { |
||||
"Name": "TTkLabel-5", |
||||
"Position": [ |
||||
29, |
||||
1 |
||||
], |
||||
"Size": [ |
||||
1, |
||||
1 |
||||
], |
||||
"Min Width": 1, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "y", |
||||
"Color": "\u001b[0m", |
||||
"Alignment": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkSpinBox", |
||||
"params": { |
||||
"Name": "sbDx", |
||||
"Position": [ |
||||
31, |
||||
0 |
||||
], |
||||
"Size": [ |
||||
6, |
||||
1 |
||||
], |
||||
"Min Width": 4, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Padding": [ |
||||
0, |
||||
0, |
||||
0, |
||||
2 |
||||
], |
||||
"Layout": "TTkGridLayout", |
||||
"Value": 0, |
||||
"Minimum": -100, |
||||
"Maximum": 100 |
||||
}, |
||||
"layout": { |
||||
"class": "TTkGridLayout", |
||||
"params": { |
||||
"Geometry": [ |
||||
0, |
||||
0, |
||||
4, |
||||
1 |
||||
] |
||||
}, |
||||
"children": [] |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkSpinBox", |
||||
"params": { |
||||
"Name": "sbDy", |
||||
"Position": [ |
||||
31, |
||||
1 |
||||
], |
||||
"Size": [ |
||||
6, |
||||
1 |
||||
], |
||||
"Min Width": 4, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Padding": [ |
||||
0, |
||||
0, |
||||
0, |
||||
2 |
||||
], |
||||
"Layout": "TTkGridLayout", |
||||
"Value": 0, |
||||
"Minimum": -100, |
||||
"Maximum": 100 |
||||
}, |
||||
"layout": { |
||||
"class": "TTkGridLayout", |
||||
"params": { |
||||
"Geometry": [ |
||||
0, |
||||
0, |
||||
4, |
||||
1 |
||||
] |
||||
}, |
||||
"children": [] |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkLabel", |
||||
"params": { |
||||
"Name": "TTkLabel-6", |
||||
"Position": [ |
||||
38, |
||||
0 |
||||
], |
||||
"Size": [ |
||||
1, |
||||
1 |
||||
], |
||||
"Min Width": 1, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "w", |
||||
"Color": "\u001b[0m", |
||||
"Alignment": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkLabel", |
||||
"params": { |
||||
"Name": "TTkLabel-7", |
||||
"Position": [ |
||||
38, |
||||
1 |
||||
], |
||||
"Size": [ |
||||
1, |
||||
1 |
||||
], |
||||
"Min Width": 1, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "h", |
||||
"Color": "\u001b[0m", |
||||
"Alignment": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkSpinBox", |
||||
"params": { |
||||
"Name": "sbDw", |
||||
"Position": [ |
||||
40, |
||||
0 |
||||
], |
||||
"Size": [ |
||||
6, |
||||
1 |
||||
], |
||||
"Min Width": 4, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Padding": [ |
||||
0, |
||||
0, |
||||
0, |
||||
2 |
||||
], |
||||
"Layout": "TTkGridLayout", |
||||
"Value": 0, |
||||
"Minimum": 0, |
||||
"Maximum": 99 |
||||
}, |
||||
"layout": { |
||||
"class": "TTkGridLayout", |
||||
"params": { |
||||
"Geometry": [ |
||||
0, |
||||
0, |
||||
4, |
||||
1 |
||||
] |
||||
}, |
||||
"children": [] |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkSpinBox", |
||||
"params": { |
||||
"Name": "sbDh", |
||||
"Position": [ |
||||
40, |
||||
1 |
||||
], |
||||
"Size": [ |
||||
6, |
||||
1 |
||||
], |
||||
"Min Width": 4, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Padding": [ |
||||
0, |
||||
0, |
||||
0, |
||||
2 |
||||
], |
||||
"Layout": "TTkGridLayout", |
||||
"Value": 0, |
||||
"Minimum": 0, |
||||
"Maximum": 99 |
||||
}, |
||||
"layout": { |
||||
"class": "TTkGridLayout", |
||||
"params": { |
||||
"Geometry": [ |
||||
0, |
||||
0, |
||||
4, |
||||
1 |
||||
] |
||||
}, |
||||
"children": [] |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkLabel", |
||||
"params": { |
||||
"Name": "TTkLabel-3", |
||||
"Position": [ |
||||
48, |
||||
0 |
||||
], |
||||
"Size": [ |
||||
5, |
||||
1 |
||||
], |
||||
"Min Width": 5, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "Layer", |
||||
"Color": "\u001b[0m", |
||||
"Alignment": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkLabel", |
||||
"params": { |
||||
"Name": "TTkLabel-8", |
||||
"Position": [ |
||||
54, |
||||
0 |
||||
], |
||||
"Size": [ |
||||
1, |
||||
1 |
||||
], |
||||
"Min Width": 1, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "x", |
||||
"Color": "\u001b[0m", |
||||
"Alignment": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkLabel", |
||||
"params": { |
||||
"Name": "TTkLabel-9", |
||||
"Position": [ |
||||
54, |
||||
1 |
||||
], |
||||
"Size": [ |
||||
1, |
||||
1 |
||||
], |
||||
"Min Width": 1, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "y", |
||||
"Color": "\u001b[0m", |
||||
"Alignment": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkSpinBox", |
||||
"params": { |
||||
"Name": "sbLx", |
||||
"Position": [ |
||||
56, |
||||
0 |
||||
], |
||||
"Size": [ |
||||
6, |
||||
1 |
||||
], |
||||
"Min Width": 4, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Padding": [ |
||||
0, |
||||
0, |
||||
0, |
||||
2 |
||||
], |
||||
"Layout": "TTkGridLayout", |
||||
"Value": 0, |
||||
"Minimum": -100, |
||||
"Maximum": 100 |
||||
}, |
||||
"layout": { |
||||
"class": "TTkGridLayout", |
||||
"params": { |
||||
"Geometry": [ |
||||
0, |
||||
0, |
||||
4, |
||||
1 |
||||
] |
||||
}, |
||||
"children": [] |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkSpinBox", |
||||
"params": { |
||||
"Name": "sbLy", |
||||
"Position": [ |
||||
56, |
||||
1 |
||||
], |
||||
"Size": [ |
||||
6, |
||||
1 |
||||
], |
||||
"Min Width": 4, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Padding": [ |
||||
0, |
||||
0, |
||||
0, |
||||
2 |
||||
], |
||||
"Layout": "TTkGridLayout", |
||||
"Value": 0, |
||||
"Minimum": -100, |
||||
"Maximum": 100 |
||||
}, |
||||
"layout": { |
||||
"class": "TTkGridLayout", |
||||
"params": { |
||||
"Geometry": [ |
||||
0, |
||||
0, |
||||
4, |
||||
1 |
||||
] |
||||
}, |
||||
"children": [] |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkLabel", |
||||
"params": { |
||||
"Name": "TTkLabel-10", |
||||
"Position": [ |
||||
63, |
||||
0 |
||||
], |
||||
"Size": [ |
||||
1, |
||||
1 |
||||
], |
||||
"Min Width": 1, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "w", |
||||
"Color": "\u001b[0m", |
||||
"Alignment": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkLabel", |
||||
"params": { |
||||
"Name": "TTkLabel-11", |
||||
"Position": [ |
||||
63, |
||||
1 |
||||
], |
||||
"Size": [ |
||||
1, |
||||
1 |
||||
], |
||||
"Min Width": 1, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Text": "h", |
||||
"Color": "\u001b[0m", |
||||
"Alignment": 0 |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkSpinBox", |
||||
"params": { |
||||
"Name": "sbLw", |
||||
"Position": [ |
||||
65, |
||||
0 |
||||
], |
||||
"Size": [ |
||||
6, |
||||
1 |
||||
], |
||||
"Min Width": 4, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Padding": [ |
||||
0, |
||||
0, |
||||
0, |
||||
2 |
||||
], |
||||
"Layout": "TTkGridLayout", |
||||
"Value": 0, |
||||
"Minimum": 0, |
||||
"Maximum": 99 |
||||
}, |
||||
"layout": { |
||||
"class": "TTkGridLayout", |
||||
"params": { |
||||
"Geometry": [ |
||||
0, |
||||
0, |
||||
4, |
||||
1 |
||||
] |
||||
}, |
||||
"children": [] |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
}, |
||||
{ |
||||
"class": "TTkSpinBox", |
||||
"params": { |
||||
"Name": "sbLh", |
||||
"Position": [ |
||||
65, |
||||
1 |
||||
], |
||||
"Size": [ |
||||
6, |
||||
1 |
||||
], |
||||
"Min Width": 4, |
||||
"Min Height": 1, |
||||
"Max Width": 65536, |
||||
"Max Height": 65536, |
||||
"Visible": true, |
||||
"Enabled": true, |
||||
"ToolTip": "", |
||||
"Padding": [ |
||||
0, |
||||
0, |
||||
0, |
||||
2 |
||||
], |
||||
"Layout": "TTkGridLayout", |
||||
"Value": 0, |
||||
"Minimum": 0, |
||||
"Maximum": 99 |
||||
}, |
||||
"layout": { |
||||
"class": "TTkGridLayout", |
||||
"params": { |
||||
"Geometry": [ |
||||
0, |
||||
0, |
||||
4, |
||||
1 |
||||
] |
||||
}, |
||||
"children": [] |
||||
}, |
||||
"row": 0, |
||||
"col": 0, |
||||
"rowspan": 1, |
||||
"colspan": 1 |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
"connections": [ |
||||
{ |
||||
"sender": "cbFg", |
||||
"receiver": "bpFg", |
||||
"signal": "toggled(bool)", |
||||
"slot": "setEnabled(bool)" |
||||
}, |
||||
{ |
||||
"sender": "cbBg", |
||||
"receiver": "bpBg", |
||||
"signal": "toggled(bool)", |
||||
"slot": "setEnabled(bool)" |
||||
} |
||||
] |
||||
} |
||||
Loading…
Reference in new issue