Browse Source

Improved Drag'n Drop Pixmap, Added D&D demo, Basic HUE Manipulation in TTkImage, D&D Bugfix

pull/34/head 0.9.0a
Eugenio Parodi 4 years ago
parent
commit
d8a3722993
  1. 26
      TermTk/TTkCore/drag.py
  2. 4
      TermTk/TTkCore/helper.py
  3. 67
      TermTk/TTkWidgets/image.py
  4. 11
      demo/demo.py
  5. 97
      demo/showcase/dragndrop.py

26
TermTk/TTkCore/drag.py

@ -35,7 +35,9 @@ class _TTkDragDisplayWidget(TTkWidget):
self._x, self._y = TTkHelper.mousePos()
def setPixmap(self, pixmap):
w,h = pixmap.size()
self._pixmap = pixmap
self.resize(w,h)
def paintEvent(self):
_,_,w,h = self.geometry()
@ -58,7 +60,13 @@ class TTkDrag():
return self._data
def setPixmap(self, pixmap):
self._pixmap = pixmap
if issubclass(type(pixmap),TTkWidget):
pixmap.getCanvas().updateSize()
pixmap.paintEvent()
pixmap = pixmap.getCanvas()
if type(pixmap) is TTkCanvas:
pixmap.updateSize()
self._pixmap.setPixmap(pixmap)
def pixmap(self):
return self._pixmap
@ -85,25 +93,21 @@ class TTkDrag():
def getDragEnterEvent(self, evt):
ret = TTkDropEvent.copy(self)
ret._pos = (evt.x, evt.y)
ret.x = evt.x
ret.y = evt.y
return ret
def getDragLeaveEvent(self, evt):
ret = TTkDropEvent.copy(self)
ret._pos = (evt.x, evt.y)
return ret
return self.getDragEnterEvent(evt)
def getDragMoveEvent(self, evt):
ret = TTkDropEvent.copy(self)
ret._pos = (evt.x, evt.y)
return ret
return self.getDragEnterEvent(evt)
def getDropEvent(self, evt):
ret = TTkDropEvent.copy(self)
ret._pos = (evt.x, evt.y)
return ret
return self.getDragEnterEvent(evt)
class TTkDropEvent(TTkDrag):
__slots__ = ('_pos')
__slots__ = ('_pos', 'x', 'y')
def pos(self): return self._pos

4
TermTk/TTkCore/helper.py

@ -368,11 +368,11 @@ class TTkHelper:
@staticmethod
def dndGetDrag():
return TTkHelper._dnd['d']
return TTkHelper._dnd['d'] if TTkHelper._dnd else None
@staticmethod
def dndWidget():
return TTkHelper._dnd['w']
return TTkHelper._dnd['w'] if TTkHelper._dnd else None
@staticmethod
def dndEnter(widget):

67
TermTk/TTkWidgets/image.py

@ -101,6 +101,73 @@ class TTkImage(TTkWidget):
# Use Blue as splitter
return splitReduce(2)
@staticmethod
def _rgb2hsl(rgb):
r = rgb[0]/255
g = rgb[1]/255
b = rgb[2]/255
cmax = max(r,g,b)
cmin = min(r,g,b)
lum = (cmax-cmin)/2
if cmax == cmin:
return 0,0,lum
delta = cmax-cmin
if cmax == r:
hue = ((g-b)/delta)%6
elif cmax == g:
hue = (b-r)/delta+2
else:
hue = (r-g)/delta+4
sat = delta / (1 - abs(delta-1))
hue = int(hue*60) + ( 360 if hue < 0 else 0 )
sat = int(sat*100)
lum = int(lum*100)
return hue,sat,lum
@staticmethod
def _hsl2rgb(hsl):
hue = hsl[0]
sat = hsl[1] / 100
lum = hsl[2] / 100
c = (1-abs(2*lum-1))*sat
x = c*(1-abs((hue/60)%2-1))
m = lum-c/2
if 0 <= hue < 60:
r,g,b = c,x,0
elif 60 <= hue < 120:
r,g,b = x,c,0
elif 120 <= hue < 180:
r,g,b = 0,c,x
elif 180 <= hue < 240:
r,g,b = 0,x,c
elif 240 <= hue < 300:
r,g,b = x,0,c
elif 300 <= hue < 360:
r,g,b = c,0,x
r = int((r + m) * 255)
g = int((g + m) * 255)
b = int((b + m) * 255)
return r,g,b
def rotHue(self, deg):
old = self._data
self._data = [[p for p in l ] for l in old]
for row in self._data:
for i,pixel in enumerate(row):
h,s,l = self._rgb2hsl(pixel)
h += deg
#TTkLog.debug(f"{h=}")
if h >= 360: h-=360
row[i] = self._hsl2rgb((h,s,l))
def paintEvent(self):
img = self._data
for y in range(0, len(img)&(~1), 2):

11
demo/demo.py

@ -47,6 +47,7 @@ from showcase.tree import demoTree
from showcase.fancytable import demoFancyTable
from showcase.fancytree import demoFancyTree
from showcase.textedit import demoTextEdit
from showcase.dragndrop import demoDnD
words = ["Lorem", "ipsum", "dolor", "sit", "amet,", "consectetur", "adipiscing", "elit,", "sed", "do", "eiusmod", "tempor", "incididunt", "ut", "labore", "et", "dolore", "magna", "aliqua.", "Ut", "enim", "ad", "minim", "veniam,", "quis", "nostrud", "exercitation", "ullamco", "laboris", "nisi", "ut", "aliquip", "ex", "ea", "commodo", "consequat.", "Duis", "aute", "irure", "dolor", "in", "reprehenderit", "in", "voluptate", "velit", "esse", "cillum", "dolore", "eu", "fugiat", "nulla", "pariatur.", "Excepteur", "sint", "occaecat", "cupidatat", "non", "proident,", "sunt", "in", "culpa", "qui", "officia", "deserunt", "mollit", "anim", "id", "est", "laborum."]
def getWord():
@ -187,12 +188,16 @@ def demoShowcase(root=None, border=True):
tabWindowsSources = [ 'showcase/windows.py' ]
tabWindows.addMenu("[Sources]", ttk.TTkK.RIGHT).menuButtonClicked.connect(lambda x : showSource(tabWindowsSources[tabWindows.currentIndex()]))
listMenu.addItem(f"Area")
listMenu.addItem(f"Extra")
tabArea = ttk.TTkTabWidget(parent=mainFrame, border=False, visible=False)
tabArea.addTab(demoScrollArea(), " Scroll Area ")
tabAreaSources = [ 'showcase/scrollarea.py' ]
tabArea.addTab(demoDnD(), " Drag'n Drop ")
tabAreaSources = [
'showcase/scrollarea.py',
'showcase/dragndrop.py' ]
tabArea.addMenu("[Sources]", ttk.TTkK.RIGHT).menuButtonClicked.connect(lambda x : showSource(tabAreaSources[tabArea.currentIndex()]))
@ttk.pyTTkSlot(str)
def _listCallback(label):
widget = None
@ -203,7 +208,7 @@ def demoShowcase(root=None, border=True):
elif label == "Pickers": widget = tabPickers
elif label == "Graphs": widget = tabGraphs
elif label == "Windows": widget = tabWindows
elif label == "Area": widget = tabArea
elif label == "Extra": widget = tabArea
if widget:
if _listCallback.active:
_listCallback.active.hide()

97
demo/showcase/dragndrop.py

@ -0,0 +1,97 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2021 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.
import os
import sys
import random
import argparse
sys.path.append(os.path.join(sys.path[0],'../..'))
import TermTk as ttk
class DragThing(ttk.TTkFrame):
def __init__(self, *args, **kwargs):
ttk.TTkFrame.__init__(self, *args, **kwargs)
# Define and place 4 images with different Hue Color rotation
ttk.TTkImage(parent=self, pos=( 0, 0), data=ttk.TTkAbout.peppered)
ttk.TTkImage(parent=self, pos=( 0,10), data=ttk.TTkAbout.peppered).rotHue(60)
ttk.TTkImage(parent=self, pos=(15, 0), data=ttk.TTkAbout.peppered).rotHue(90)
ttk.TTkImage(parent=self, pos=(15,10), data=ttk.TTkAbout.peppered).rotHue(200)
self.setMaximumWidth(30)
self.setMinimumWidth(30)
def mouseDragEvent(self, evt) -> bool:
ttk.TTkLog.debug("Start DnD")
drag = ttk.TTkDrag()
data = ttk.TTkImage(data=ttk.TTkAbout.peppered)
# Change color if the drag start over the side images,
# based on the same Hue rotation defined in the init
if evt.x <= 15 and evt.y > 10: data.rotHue(60)
elif evt.x > 15 and evt.y <= 10: data.rotHue(90)
elif evt.x > 15 and evt.y > 10: data.rotHue(200)
drag.setPixmap(data)
drag.setData(data)
drag.exec()
return True
class DropThings(ttk.TTkFrame):
def dropEvent(self, evt) -> bool:
ttk.TTkLog.debug(f"Drop ({self.title()}) -> pos={evt.pos()}")
data = evt.data()
self.addWidget(data)
data.move(evt.x,evt.y)
self.update()
return True
def demoDnD(root=None):
dndlayout = ttk.TTkGridLayout()
frame = ttk.TTkFrame(parent=root, layout=dndlayout, border=0)
dndlayout.addWidget(DragThing( title="Drag") ,0,0,2,1)
dndlayout.addWidget(DropThings(title="Drop 1"),0,1,1,2)
dndlayout.addWidget(DropThings(title="Drop 2"),0,3,1,1)
dndlayout.addWidget(DropThings(title="Drop 3"),1,1,1,1)
dndlayout.addWidget(DropThings(title="Drop 4"),1,2,1,2)
# Add a debug window at the bottom to display the messages
dndlayout.addWidget(ttk.TTkLogViewer(follow=True),2,0,1,4)
return frame
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-f', help='Full Screen', action='store_true')
args = parser.parse_args()
ttk.TTkLog.use_default_file_logging()
root = ttk.TTk()
if args.f:
rootTree = root
root.setLayout(ttk.TTkGridLayout())
else:
rootTree = ttk.TTkWindow(parent=root,pos = (0,0), size=(70,40), title="Test Drag'n Drop", layout=ttk.TTkGridLayout(), border=True)
demoDnD(rootTree)
root.mainloop()
if __name__ == "__main__":
main()
Loading…
Cancel
Save