forked from albertz/music-player
-
Notifications
You must be signed in to change notification settings - Fork 0
/
guiCocoaCommon.py
226 lines (206 loc) · 7.2 KB
/
guiCocoaCommon.py
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# MusicPlayer, https://github.com/albertz/music-player
# Copyright (c) 2012, Albert Zeyer, www.az2000.de
# All rights reserved.
# This code is under the 2-clause BSD license, see License.txt in the root directory of this project.
import objc
from AppKit import *
import utils
from collections import deque
try: pools
except NameError: pools = deque()
# just in case that we are not the main thread
pools.append(NSAutoreleasePool.alloc().init())
# we have some native code in a dylib.
# later, maybe most of the code here can be recoded natively.
# this is a work-in-progress.
import ctypes, os
l = ctypes.CDLL(os.path.dirname(__file__) + "/_guiCocoaCommon.dylib")
try:
_NSFlippedView = objc.lookUpClass("_NSFlippedView")
class NSFlippedView(_NSFlippedView):
control = None
onBecomeFirstResponder = None
onResignFirstResponder = None
onKeyDown = None
onKeyUp = None
onMouseDown = None
onMouseDragged = None
onMouseUp = None
onDraggingEntered = None
onDraggingUpdated = None
onDraggingExited = None
onPerformDragOperation = None
def acceptsFirstResponder(self):
return utils.attrChain(self, "control", "attr", "canHaveFocus", default=False)
def becomeFirstResponder(self):
if NSView.becomeFirstResponder(self):
if self.onBecomeFirstResponder: self.onBecomeFirstResponder()
return True
else:
return False
def resignFirstResponder(self):
if NSView.resignFirstResponder(self):
if self.onResignFirstResponder: self.onResignFirstResponder()
return True
else:
return False
def keyDown_(self, ev):
if not self.onKeyDown or not self.onKeyDown(ev):
NSView.keyDown_(self, ev)
def keyUp_(self, ev):
if not self.onKeyUp or not self.onKeyUp(ev):
NSView.keyUp_(self, ev)
def mouseDown_(self, ev):
if not self.onMouseDown or not self.onMouseDown(ev):
NSView.mouseDown_(self, ev)
def mouseDragged_(self, ev):
if not self.onMouseDragged or not self.onMouseDragged(ev):
NSView.mouseDragged_(self, ev)
def mouseUp_(self, ev):
if not self.onMouseUp or not self.onMouseUp(ev):
NSView.mouseUp_(self, ev)
def draggingEntered_(self, sender):
if self.onDraggingEntered: self.onDraggingEntered(sender)
return self.draggingUpdated_(sender)
def draggingUpdated_(self, sender):
if self.onDraggingUpdated: self.onDraggingUpdated(sender)
return NSDragOperationGeneric
def draggingExited_(self, sender):
if self.onDraggingExited: self.onDraggingExited(sender)
def prepareForDragOperation_(self, sender):
return True
def performDragOperation_(self, sender):
if self.onPerformDragOperation and self.onPerformDragOperation(sender):
return True
return False
except:
NSFlippedView = objc.lookUpClass("NSFlippedView")
try:
class NSExtendedTextField(NSTextField):
onMouseEntered = None
onMouseExited = None
onMouseDown = None
onMouseDragged = None
onMouseUp = None
onTextChange = None
def mouseEntered_(self, ev):
if self.onMouseEntered: self.onMouseEntered(ev)
else: NSTextField.mouseEntered_(self, ev)
def mouseExited_(self, ev):
if self.onMouseExited: self.onMouseExited(ev)
else: NSTextField.mouseExited_(self, ev)
def mouseDown_(self, ev):
if not self.onMouseDown or not self.onMouseDown(ev):
NSView.mouseDown_(self, ev)
def mouseDragged_(self, ev):
if not self.onMouseDragged or not self.onMouseDragged(ev):
NSView.mouseDragged_(self, ev)
def mouseUp_(self, ev):
if not self.onMouseUp or not self.onMouseUp(ev):
NSView.mouseUp_(self, ev)
def textDidChange_(self, notif):
NSTextField.textDidChange_(self, notif)
if self.onTextChange:
self.onTextChange()
except:
NSExtendedTextField = objc.lookUpClass("NSExtendedTextField")
try:
class NSExtendedSlider(NSSlider):
onValueChange = None
def initWithFrame_(self, frame):
NSSlider.initWithFrame_(self, frame)
self.setTarget_(self)
self.setAction_("valueChange")
return self
def valueChange(self, sender):
if self.onValueChange:
self.onValueChange(self.doubleValue())
except:
NSExtendedSlider = objc.lookUpClass("NSExtendedSlider")
try:
class TableViewDataSource(NSObject):
data = ()
formaters = {}
def numberOfRowsInTableView_(self, tableView):
return len(self.data)
def tableView_objectValueForTableColumn_row_(self, tableView, tableColumn, rowIndex):
key = str(tableColumn.identifier())
v = self.data[rowIndex].get(key, None)
if key in self.formaters: v = self.formaters[key](v)
if isinstance(v, str): v = utils.convertToUnicode(v)
return v
def resort(self, tableView):
sortDescs = list(tableView.sortDescriptors())
def itemIter(item):
for d in sortDescs:
value = item.get(d.key(), None)
if isinstance(value, (str,unicode)):
value = value.lower()
yield value
def key(item):
item = tuple(itemIter(item))
return item
if sortDescs:
firstAsc = sortDescs[0].ascending()
else:
# sort descriptors hasn't been set yet
firstAsc = True
self.data.sort(key=key, reverse=not firstAsc)
tableView.reloadData()
def tableView_sortDescriptorsDidChange_(self, tableView, oldDescriptors):
self.resort(tableView)
def tableView_writeRowsWithIndexes_toPasteboard_(self, tableView, rowIndexes, pboard):
possibleSources = []
def handleRowIndex(index, stop):
url = self.data[index].get("url", None)
if url:
url = utils.convertToUnicode(url)
possibleSources.append(url)
rowIndexes.enumerateIndexesUsingBlock_(handleRowIndex)
if not possibleSources: return False
pboard.declareTypes_owner_([NSFilenamesPboardType], None)
pboard.setPropertyList_forType_(possibleSources, NSFilenamesPboardType)
return True
except:
TableViewDataSource = objc.lookUpClass("TableViewDataSource")
try:
class TableViewDelegate(NSObject):
onSelectionChange = None
def tableViewSelectionDidChange_(self, notif):
if self.onSelectionChange:
tableView = notif.object()
selection = []
def handleRowIndex(index, stop):
selection.append(tableView.dataSource().data[index])
tableView.selectedRowIndexes().enumerateIndexesUsingBlock_(handleRowIndex)
self.onSelectionChange(selection)
except:
TableViewDelegate = objc.lookUpClass("TableViewDelegate")
try:
class ButtonActionHandler(NSObject):
def initWithArgs(self, userAttr, inst):
self.init()
self.userAttr = userAttr
self.inst = inst
return self
def click(self, sender):
attr = self.userAttr.__get__(self.inst)
utils.daemonThreadCall(attr, name="%r click handler" % (self.userAttr))
except:
ButtonActionHandler = objc.lookUpClass("ButtonActionHandler") # already defined earlier
try:
class DragSource(NSObject):
onDragEnded = None
onInternalDrag = None
@objc.typedSelector('i@:@i')
def draggingSession_sourceOperationMaskForDraggingContext_(self, session, context):
return NSDragOperationAll
@objc.typedSelector('v@:@{CGPoint=dd}i')
def draggingSession_endedAtPoint_operation_(self, session, screenPoint, operation):
if self.onDragEnded: self.onDragEnded(operation)
@objc.typedSelector('v@:@{CGPoint=dd}i')
def draggedImage_endedAt_operation_(self, img, pt, operation):
if self.onDragEnded: self.onDragEnded(operation)
except:
DragSource = objc.lookUpClass("DragSource")
# keep old pools. there is no real safe way to know whether we still have some refs to objects