File: DockDrop.py

package info (click to toggle)
python-pyqtgraph 0.13.7-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 8,068 kB
  • sloc: python: 54,043; makefile: 129; ansic: 40; sh: 2
file content (139 lines) | stat: -rw-r--r-- 4,468 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
__all__ = ["DockDrop"]

from ..Qt import QtCore, QtGui, QtWidgets


class DockDrop:
    """Provides dock-dropping methods"""
    def __init__(self, dndWidget):
        self.dndWidget = dndWidget
        self.allowedAreas = {'center', 'right', 'left', 'top', 'bottom'}
        self.dndWidget.setAcceptDrops(True)
        self.dropArea = None
        self.overlay = DropAreaOverlay(dndWidget)
        self.overlay.raise_()

    def addAllowedArea(self, area):
        self.allowedAreas.update(area)

    def removeAllowedArea(self, area):
        self.allowedAreas.discard(area)

    def resizeOverlay(self, size):
        self.overlay.resize(size)
        
    def raiseOverlay(self):
        self.overlay.raise_()
    
    def dragEnterEvent(self, ev):
        src = ev.source()
        if hasattr(src, 'implements') and src.implements('dock'):
            #print "drag enter accept"
            ev.accept()
        else:
            #print "drag enter ignore"
            ev.ignore()
        
    def dragMoveEvent(self, ev):
        #print "drag move"
        # QDragMoveEvent inherits QDropEvent which provides posF()
        # PyQt6 provides only position()
        width, height = self.dndWidget.width(), self.dndWidget.height()
        posF = ev.posF() if hasattr(ev, 'posF') else ev.position()
        ld = posF.x()
        rd = width - ld
        td = posF.y()
        bd = height - td
        
        mn = min(ld, rd, td, bd)
        if mn > 30:
            self.dropArea = "center"
        elif (ld == mn or td == mn) and mn > height/3:
            self.dropArea = "center"
        elif (rd == mn or ld == mn) and mn > width/3:
            self.dropArea = "center"
            
        elif rd == mn:
            self.dropArea = "right"
        elif ld == mn:
            self.dropArea = "left"
        elif td == mn:
            self.dropArea = "top"
        elif bd == mn:
            self.dropArea = "bottom"
            
        if ev.source() is self.dndWidget and self.dropArea == 'center':
            #print "  no self-center"
            self.dropArea = None
            ev.ignore()
        elif self.dropArea not in self.allowedAreas:
            #print "  not allowed"
            self.dropArea = None
            ev.ignore()
        else:
            #print "  ok"
            ev.accept()
        self.overlay.setDropArea(self.dropArea)
            
    def dragLeaveEvent(self, ev):
        self.dropArea = None
        self.overlay.setDropArea(self.dropArea)
    
    def dropEvent(self, ev):
        area = self.dropArea
        if area is None:
            return
        if area == 'center':
            area = 'above'
        self.dndWidget.area.moveDock(ev.source(), area, self.dndWidget)
        self.dropArea = None
        self.overlay.setDropArea(self.dropArea)

        

class DropAreaOverlay(QtWidgets.QWidget):
    """Overlay widget that draws drop areas during a drag-drop operation"""
    
    def __init__(self, parent):
        QtWidgets.QWidget.__init__(self, parent)
        self.dropArea = None
        self.hide()
        self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TransparentForMouseEvents)
        
    def setDropArea(self, area):
        self.dropArea = area
        if area is None:
            self.hide()
        else:
            ## Resize overlay to just the region where drop area should be displayed.
            ## This works around a Qt bug--can't display transparent widgets over QGLWidget
            prgn = self.parent().rect()
            rgn = QtCore.QRect(prgn)
            w = min(30, int(prgn.width() / 3))
            h = min(30, int(prgn.height() / 3))
            
            if self.dropArea == 'left':
                rgn.setWidth(w)
            elif self.dropArea == 'right':
                rgn.setLeft(rgn.left() + prgn.width() - w)
            elif self.dropArea == 'top':
                rgn.setHeight(h)
            elif self.dropArea == 'bottom':
                rgn.setTop(rgn.top() + prgn.height() - h)
            elif self.dropArea == 'center':
                rgn.adjust(w, h, -w, -h)
            self.setGeometry(rgn)
            self.show()

        self.update()
    
    def paintEvent(self, ev):
        if self.dropArea is None:
            return
        p = QtGui.QPainter(self)
        rgn = self.rect()

        p.setBrush(QtGui.QBrush(QtGui.QColor(100, 100, 255, 50)))
        p.setPen(QtGui.QPen(QtGui.QColor(50, 50, 150), 3))
        p.drawRect(rgn)
        p.end()