diff --git a/tools/dumbPaintTool/app/canvaslayer.py b/tools/dumbPaintTool/app/canvaslayer.py index 8240f230..be645f27 100644 --- a/tools/dumbPaintTool/app/canvaslayer.py +++ b/tools/dumbPaintTool/app/canvaslayer.py @@ -134,6 +134,13 @@ class CanvasLayer(): self._snapVersion += 1 self._name = name + def glyphColorAt(self, x, y): + ox,oy = self._offset + w,h = self._size + data = self._data + colors = self._colors + return data[oy+y][ox+x], colors[oy+y][ox+x] + def isOpaque(self,x,y): if not self._visible: return False ox,oy = self._offset @@ -203,6 +210,10 @@ class CanvasLayer(): self._snapVersion += 1 self.changed.emit() + def cleanPreview(self): + self._preview = None + self.changed.emit() + def toTTkString(self): ret = [] pw,ph = self._size @@ -245,13 +256,16 @@ class CanvasLayer(): ya,yb = min(y,ya),max(y,yb) if (xa,xb,ya,yb) == (0x10000,0,0x10000,0): xa=xb=ya=yb=0 + else: + xb+=1 + yb+=1 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 + vw,vh = vxb-vxa, vyb-vya outData = { 'version':'1.1.0', @@ -293,7 +307,18 @@ class CanvasLayer(): def _import_v1_1_0(self, dd): self._import_v1_0_0(dd) - self._offset = dd.get('offset',(0,0)) + # Fix the correct size if the data has been trimmed in the wrong save + ox,oy = self._offset = dd.get('offset',(0,0)) + ttk.TTkLog.debug(f"{self._offset=} {self._size=} {self._pos=}") + ttk.TTkLog.debug(f"{len(self._data[0])=}") + w,h = self._size + dw = len(self._data[0]) + dh = len(self._data) + w = min(w,dw-ox) + h = min(h,dh-oy) + self._size = w,h + # px,py = self._pos + # self.superResize(x,y,w,h) def _import_v1_0_0(self, dd): self._pos = dd['pos'] diff --git a/tools/dumbPaintTool/app/const.py b/tools/dumbPaintTool/app/const.py index ebbd80ed..fcc54524 100644 --- a/tools/dumbPaintTool/app/const.py +++ b/tools/dumbPaintTool/app/const.py @@ -31,5 +31,7 @@ class ToolType(int): CLONE = 0x0020 AREA = 0x0040 GLYPH = 0x0080 - PICK = 0x0100 + PICKAREA = 0x0100 + PICKGLYPH = 0x0400 + PICKMASK = PICKAREA|PICKGLYPH TRANSPARENT = 0x0200 \ No newline at end of file diff --git a/tools/dumbPaintTool/app/paintarea.py b/tools/dumbPaintTool/app/paintarea.py index f183ddd1..a24063c3 100644 --- a/tools/dumbPaintTool/app/paintarea.py +++ b/tools/dumbPaintTool/app/paintarea.py @@ -175,6 +175,8 @@ class PaintArea(ttk.TTkAbstractScrollView): def leaveEvent(self, evt): self._mouseMove = None self._moveData = None + if current := glbls.layers.selected(): + current.cleanPreview() self.update() return super().leaveEvent(evt) @@ -195,7 +197,35 @@ class PaintArea(ttk.TTkAbstractScrollView): l = glbls.layers.selected() lx,ly = l.pos() - if self._tool & ToolType.MOVE and mp and not md: + if self._tool & ToolType.PICKGLYPH: + if mp: + mpx,mpy = mp + color = None + glyph = None + for lm in glbls.layers.layers(): + lmx,lmy = lm.pos() + if lm.isOpaque(mpx-lmx-dx,mpy-lmy-dy): + _gl, _co = lm.glyphColorAt(mpx-lmx-dx,mpy-lmy-dy) + if not glyph and not color: + glyph = _gl + color = _co + elif not color.background(): + if _co.background(): + if _fg:=color.foreground(): + color = _fg + _co.background() + else: + color = _co.background() + else: + break + glbls.brush.setColor(color) + glbls.brush.setGlyph(glyph) + if mr: + glbls.brush.setToolType(self._tool & ~ToolType.PICKGLYPH) + self._mousePress = None + self._mouseMove = None + self._mouseDrag = None + self._mouseRelease = None + elif self._tool & ToolType.MOVE and mp and not md: if self._tool & ToolType.RESIZE and not md: mpx,mpy = mp self._resizeData = None @@ -256,8 +286,8 @@ class PaintArea(ttk.TTkAbstractScrollView): self._retuneGeometry() elif self._tool & ToolType.BRUSH: - if mp and self._tool & ToolType.PICK: - glbls.brush.setToolType(self._tool & ~ToolType.PICK) + if mp and self._tool & ToolType.PICKAREA: + glbls.brush.setToolType(self._tool & ~ToolType.PICKAREA) mpx,mpy = mp for lm in glbls.layers.layers(): lmx,lmy = lm.pos() @@ -268,7 +298,7 @@ class PaintArea(ttk.TTkAbstractScrollView): self._mouseMove = None self._mouseDrag = None self._mouseRelease = None - elif self._tool & ToolType.PICK: + elif self._tool & ToolType.PICKAREA: pass # Do not show any preview if we are in picking mode elif mp or md: if md: mx,my = md diff --git a/tools/dumbPaintTool/app/painttoolkit.py b/tools/dumbPaintTool/app/painttoolkit.py index 6ab33bea..5e6d4ffd 100644 --- a/tools/dumbPaintTool/app/painttoolkit.py +++ b/tools/dumbPaintTool/app/painttoolkit.py @@ -28,9 +28,11 @@ import TermTk as ttk from .paintarea import * from .glbls import glbls +from .const import ToolType class PaintToolKit(ttk.TTkContainer): __slots__ = ('_rSelect', '_rPaint', '_lgliph', + '_btnPick', '_cbFg', '_cbBg', '_bpFg', '_bpBg', '_bpDef', '_sbDx','_sbDy','_sbDw','_sbDh', @@ -56,6 +58,8 @@ class PaintToolKit(ttk.TTkContainer): self._sbLw = self.getWidgetByName("sbLw") self._sbLh = self.getWidgetByName("sbLh") + self._btnPick = self.getWidgetByName("btnPick") + self._bpDef.setColor(ttk.TTkColor.bg('#FF00FF')) self._cbFg.toggled.connect(self._refreshColor) self._cbBg.toggled.connect(self._refreshColor) @@ -80,6 +84,13 @@ class PaintToolKit(ttk.TTkContainer): self._refreshColor(emit=False) + @ttk.pyTTkSlot() + def _pick(): + ttType = glbls.brush.toolType() & ~ToolType.PICKMASK + glbls.brush.setToolType( ttType | ToolType.PICKGLYPH ) + + self._btnPick.clicked.connect(_pick) + @ttk.pyTTkSlot() def _pushLayerValues(self): if not (layer := glbls.layers.selected()): return diff --git a/tools/dumbPaintTool/app/toolspanel.py b/tools/dumbPaintTool/app/toolspanel.py index 7b6c5115..548fcebc 100644 --- a/tools/dumbPaintTool/app/toolspanel.py +++ b/tools/dumbPaintTool/app/toolspanel.py @@ -134,8 +134,8 @@ class ToolsPanel(ttk.TTkVBoxLayout): def _pick(): glbls.brush.setToolType( ToolType.BRUSH | - ToolType.AREA | - ToolType.PICK ) + ToolType.AREA | + ToolType.PICKAREA ) btn_pick_a.clicked.connect(_pick) diff --git a/tools/dumbPaintTool/tui/paintToolKit.tui.json b/tools/dumbPaintTool/tui/paintToolKit.tui.json index 757ec06e..bd922812 100644 --- a/tools/dumbPaintTool/tui/paintToolKit.tui.json +++ b/tools/dumbPaintTool/tui/paintToolKit.tui.json @@ -1,5 +1,6 @@ { - "version": "2.0.0", + "type": "TTkUi/Document", + "version": "2.0.2", "tui": { "class": "TTkContainer", "params": { @@ -9,7 +10,7 @@ 2 ], "Size": [ - 78, + 87, 2 ], "Min Width": 50, @@ -33,7 +34,7 @@ "Geometry": [ 0, 0, - 78, + 87, 2 ] }, @@ -182,34 +183,6 @@ "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": { @@ -273,9 +246,9 @@ { "class": "TTkLabel", "params": { - "Name": "TTkLabel-4", + "Name": "TTkLabel-6", "Position": [ - 29, + 47, 0 ], "Size": [ @@ -289,7 +262,7 @@ "Visible": true, "Enabled": true, "ToolTip": "", - "Text": "x", + "Text": "w", "Color": "\u001b[0m", "Alignment": 0 }, @@ -301,9 +274,9 @@ { "class": "TTkLabel", "params": { - "Name": "TTkLabel-5", + "Name": "TTkLabel-7", "Position": [ - 29, + 47, 1 ], "Size": [ @@ -317,7 +290,7 @@ "Visible": true, "Enabled": true, "ToolTip": "", - "Text": "y", + "Text": "h", "Color": "\u001b[0m", "Alignment": 0 }, @@ -329,9 +302,9 @@ { "class": "TTkSpinBox", "params": { - "Name": "sbDx", + "Name": "sbDw", "Position": [ - 31, + 49, 0 ], "Size": [ @@ -353,8 +326,8 @@ ], "Layout": "TTkGridLayout", "Value": 0, - "Minimum": -100, - "Maximum": 100 + "Minimum": 0, + "Maximum": 99 }, "layout": { "class": "TTkGridLayout", @@ -376,9 +349,9 @@ { "class": "TTkSpinBox", "params": { - "Name": "sbDy", + "Name": "sbDh", "Position": [ - 31, + 49, 1 ], "Size": [ @@ -400,8 +373,8 @@ ], "Layout": "TTkGridLayout", "Value": 0, - "Minimum": -100, - "Maximum": 100 + "Minimum": 0, + "Maximum": 99 }, "layout": { "class": "TTkGridLayout", @@ -423,9 +396,37 @@ { "class": "TTkLabel", "params": { - "Name": "TTkLabel-6", + "Name": "TTkLabel-3", "Position": [ - 38, + 57, + 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": [ + 63, 0 ], "Size": [ @@ -439,7 +440,7 @@ "Visible": true, "Enabled": true, "ToolTip": "", - "Text": "w", + "Text": "x", "Color": "\u001b[0m", "Alignment": 0 }, @@ -451,9 +452,9 @@ { "class": "TTkLabel", "params": { - "Name": "TTkLabel-7", + "Name": "TTkLabel-9", "Position": [ - 38, + 63, 1 ], "Size": [ @@ -467,7 +468,7 @@ "Visible": true, "Enabled": true, "ToolTip": "", - "Text": "h", + "Text": "y", "Color": "\u001b[0m", "Alignment": 0 }, @@ -479,9 +480,9 @@ { "class": "TTkSpinBox", "params": { - "Name": "sbDw", + "Name": "sbLx", "Position": [ - 40, + 65, 0 ], "Size": [ @@ -503,8 +504,8 @@ ], "Layout": "TTkGridLayout", "Value": 0, - "Minimum": 0, - "Maximum": 99 + "Minimum": -100, + "Maximum": 100 }, "layout": { "class": "TTkGridLayout", @@ -526,9 +527,9 @@ { "class": "TTkSpinBox", "params": { - "Name": "sbDh", + "Name": "sbLy", "Position": [ - 40, + 65, 1 ], "Size": [ @@ -550,8 +551,8 @@ ], "Layout": "TTkGridLayout", "Value": 0, - "Minimum": 0, - "Maximum": 99 + "Minimum": -100, + "Maximum": 100 }, "layout": { "class": "TTkGridLayout", @@ -573,23 +574,23 @@ { "class": "TTkLabel", "params": { - "Name": "TTkLabel-3", + "Name": "TTkLabel-10", "Position": [ - 48, + 72, 0 ], "Size": [ - 5, + 1, 1 ], - "Min Width": 5, + "Min Width": 1, "Min Height": 1, "Max Width": 65536, "Max Height": 65536, "Visible": true, "Enabled": true, "ToolTip": "", - "Text": "Layer", + "Text": "w", "Color": "\u001b[0m", "Alignment": 0 }, @@ -601,10 +602,10 @@ { "class": "TTkLabel", "params": { - "Name": "TTkLabel-8", + "Name": "TTkLabel-11", "Position": [ - 54, - 0 + 72, + 1 ], "Size": [ 1, @@ -617,7 +618,7 @@ "Visible": true, "Enabled": true, "ToolTip": "", - "Text": "x", + "Text": "h", "Color": "\u001b[0m", "Alignment": 0 }, @@ -627,27 +628,93 @@ "colspan": 1 }, { - "class": "TTkLabel", + "class": "TTkSpinBox", "params": { - "Name": "TTkLabel-9", + "Name": "sbLw", + "Position": [ + 74, + 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": [ - 54, + 74, 1 ], "Size": [ - 1, + 6, 1 ], - "Min Width": 1, + "Min Width": 4, "Min Height": 1, "Max Width": 65536, "Max Height": 65536, "Visible": true, "Enabled": true, "ToolTip": "", - "Text": "y", - "Color": "\u001b[0m", - "Alignment": 0 + "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, @@ -657,9 +724,9 @@ { "class": "TTkSpinBox", "params": { - "Name": "sbLx", + "Name": "sbDx", "Position": [ - 56, + 40, 0 ], "Size": [ @@ -704,9 +771,9 @@ { "class": "TTkSpinBox", "params": { - "Name": "sbLy", + "Name": "sbDy", "Position": [ - 56, + 40, 1 ], "Size": [ @@ -751,9 +818,9 @@ { "class": "TTkLabel", "params": { - "Name": "TTkLabel-10", + "Name": "TTkLabel-4", "Position": [ - 63, + 38, 0 ], "Size": [ @@ -767,7 +834,7 @@ "Visible": true, "Enabled": true, "ToolTip": "", - "Text": "w", + "Text": "x", "Color": "\u001b[0m", "Alignment": 0 }, @@ -779,9 +846,9 @@ { "class": "TTkLabel", "params": { - "Name": "TTkLabel-11", + "Name": "TTkLabel-5", "Position": [ - 63, + 38, 1 ], "Size": [ @@ -795,7 +862,7 @@ "Visible": true, "Enabled": true, "ToolTip": "", - "Text": "h", + "Text": "y", "Color": "\u001b[0m", "Alignment": 0 }, @@ -805,46 +872,27 @@ "colspan": 1 }, { - "class": "TTkSpinBox", + "class": "TTkLabel", "params": { - "Name": "sbLw", + "Name": "TTkLabel-2", "Position": [ - 65, + 34, 0 ], "Size": [ - 6, + 3, 1 ], - "Min Width": 4, + "Min Width": 3, "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": [] + "Text": "Doc", + "Color": "\u001b[0m", + "Alignment": 0 }, "row": 0, "col": 0, @@ -852,46 +900,28 @@ "colspan": 1 }, { - "class": "TTkSpinBox", + "class": "TTkButton", "params": { - "Name": "sbLh", + "Name": "btnPick", "Position": [ - 65, - 1 + 23, + 0 ], "Size": [ - 6, + 9, 1 ], - "Min Width": 4, + "Min Width": 9, "Min Height": 1, "Max Width": 65536, - "Max Height": 65536, + "Max Height": 1, "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": [] + "Text": "Pick \ud83d\uded2", + "Border": false, + "Checkable": false, + "Checked": false }, "row": 0, "col": 0,