CreativePython 1.1.4__py3-none-any.whl → 1.1.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CreativePython/GuiHandler.py +15 -6
- CreativePython/GuiRenderer.py +22 -8
- CreativePython/__init__.py +6 -0
- {creativepython-1.1.4.dist-info → creativepython-1.1.5.dist-info}/METADATA +1 -1
- {creativepython-1.1.4.dist-info → creativepython-1.1.5.dist-info}/RECORD +14 -14
- gui.py +69 -12
- image.py +3 -2
- midi.py +345 -620
- music.py +83 -50
- osc.py +111 -295
- {creativepython-1.1.4.dist-info → creativepython-1.1.5.dist-info}/WHEEL +0 -0
- {creativepython-1.1.4.dist-info → creativepython-1.1.5.dist-info}/licenses/LICENSE +0 -0
- {creativepython-1.1.4.dist-info → creativepython-1.1.5.dist-info}/licenses/LICENSE-PSF +0 -0
- {creativepython-1.1.4.dist-info → creativepython-1.1.5.dist-info}/top_level.txt +0 -0
CreativePython/GuiHandler.py
CHANGED
|
@@ -86,11 +86,20 @@ def _launchRenderer(childCommandConnection, childPriorityConnection, parentPrior
|
|
|
86
86
|
|
|
87
87
|
parentPriorityConnection.close() # child must not hold the parent end open
|
|
88
88
|
|
|
89
|
-
#
|
|
90
|
-
#
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
89
|
+
# Set to True to redirect stderr to PENCIL_debug.log for diagnostics.
|
|
90
|
+
# When False, stderr is silenced (sent to /dev/null) to suppress Qt/Cocoa noise.
|
|
91
|
+
_DEBUG_LOG = False
|
|
92
|
+
|
|
93
|
+
if _DEBUG_LOG:
|
|
94
|
+
# Redirect stderr (fd 2) to a log file so both Python tracebacks and C-level
|
|
95
|
+
# output from Qt/Cocoa/XPC are captured for diagnostics.
|
|
96
|
+
# The log is removed on clean exit if nothing was written to it.
|
|
97
|
+
_logPath = os.path.join(os.getcwd(), "PENCIL_debug.log")
|
|
98
|
+
_logFile = open(_logPath, "w")
|
|
99
|
+
else:
|
|
100
|
+
_logPath = None
|
|
101
|
+
_logFile = open(os.devnull, "w")
|
|
102
|
+
|
|
94
103
|
os.dup2(_logFile.fileno(), 2)
|
|
95
104
|
sys.stderr = _logFile
|
|
96
105
|
|
|
@@ -103,7 +112,7 @@ def _launchRenderer(childCommandConnection, childPriorityConnection, parentPrior
|
|
|
103
112
|
raise
|
|
104
113
|
finally:
|
|
105
114
|
_logFile.flush()
|
|
106
|
-
if os.path.getsize(_logPath) == 0:
|
|
115
|
+
if _DEBUG_LOG and _logPath and os.path.getsize(_logPath) == 0:
|
|
107
116
|
try:
|
|
108
117
|
_logFile.close()
|
|
109
118
|
os.unlink(_logPath)
|
CreativePython/GuiRenderer.py
CHANGED
|
@@ -549,9 +549,10 @@ class _QtGraphicsItemEventMixin:
|
|
|
549
549
|
pos = event.scenePos()
|
|
550
550
|
args = [int(pos.x()), int(pos.y())]
|
|
551
551
|
self._send('mouseDown', args)
|
|
552
|
-
# register this item for drag delivery during subsequent mouse
|
|
552
|
+
# register this item for release and drag delivery during subsequent mouse events
|
|
553
553
|
view = self._qtview()
|
|
554
554
|
if view is not None:
|
|
555
|
+
view._pressedItems.append(self._mirror.objectId) # track for manual release delivery (see QtView.mouseReleaseEvent)
|
|
555
556
|
if (self._mirror.objectId, 'mouseDrag') in self._mirror.guiRenderer._registeredEvents:
|
|
556
557
|
view._draggingItems.append(self._mirror.objectId)
|
|
557
558
|
event.ignore() # allow cascade to items below
|
|
@@ -653,6 +654,7 @@ class QtView(QtWidgets.QGraphicsView):
|
|
|
653
654
|
self._display = displayMirror
|
|
654
655
|
self._pressPos = None # QPointF scene pos at last press
|
|
655
656
|
self._draggingItems = [] # objectIds wanting drag events
|
|
657
|
+
self._pressedItems = [] # objectIds of items that received the last mousePressEvent
|
|
656
658
|
|
|
657
659
|
# ── Helpers ────────────────────────────────────────────────────────────────
|
|
658
660
|
|
|
@@ -679,16 +681,28 @@ class QtView(QtWidgets.QGraphicsView):
|
|
|
679
681
|
|
|
680
682
|
def mouseReleaseEvent(self, event):
|
|
681
683
|
x, y = self._sceneXY(event)
|
|
682
|
-
|
|
684
|
+
|
|
685
|
+
# Items call event.ignore() in mousePressEvent to allow cascade, so Qt never
|
|
686
|
+
# sets a mouse grabber and mouseReleaseEvent is never routed to items normally.
|
|
687
|
+
# Manually deliver mouseUp and mouseClick using the objectIds tracked at press time,
|
|
688
|
+
# mirroring the _draggingItems pattern used for mouseDrag.
|
|
689
|
+
registered = self._display.guiRenderer._registeredEvents
|
|
690
|
+
pos = self.mapToScene(event.position().toPoint())
|
|
691
|
+
is_click = (self._pressPos is not None
|
|
692
|
+
and abs(pos.x() - self._pressPos.x()) <= _QtGraphicsItemEventMixin._CLICK_THRESHOLD
|
|
693
|
+
and abs(pos.y() - self._pressPos.y()) <= _QtGraphicsItemEventMixin._CLICK_THRESHOLD)
|
|
694
|
+
for objectId in self._pressedItems:
|
|
695
|
+
if (objectId, 'mouseUp') in registered:
|
|
696
|
+
self._display.guiRenderer.sendEvent('mouseUp', objectId, [x, y])
|
|
697
|
+
if is_click and (objectId, 'mouseClick') in registered:
|
|
698
|
+
self._display.guiRenderer.sendEvent('mouseClick', objectId, [x, y])
|
|
699
|
+
|
|
683
700
|
self._sendDisplay('mouseUp', [x, y])
|
|
684
|
-
if
|
|
685
|
-
|
|
686
|
-
dx = abs(pos.x() - self._pressPos.x())
|
|
687
|
-
dy = abs(pos.y() - self._pressPos.y())
|
|
688
|
-
if dx <= _QtGraphicsItemEventMixin._CLICK_THRESHOLD and dy <= _QtGraphicsItemEventMixin._CLICK_THRESHOLD:
|
|
689
|
-
self._sendDisplay('mouseClick', [x, y])
|
|
701
|
+
if is_click:
|
|
702
|
+
self._sendDisplay('mouseClick', [x, y])
|
|
690
703
|
self._pressPos = None
|
|
691
704
|
self._draggingItems = []
|
|
705
|
+
self._pressedItems = []
|
|
692
706
|
|
|
693
707
|
def mouseMoveEvent(self, event):
|
|
694
708
|
x, y = self._sceneXY(event)
|
CreativePython/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CreativePython
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.5
|
|
4
4
|
Summary: A Python-based software environment for developing algorithmic art projects.
|
|
5
5
|
Author-email: "Dr. Bill Manaris" <manaris@cofc.edu>, Taj Ballinger <ballingertj@g.cofc.edu>, Trevor Ritchie <ritchiets@g.cofc.edu>
|
|
6
6
|
License: MIT License
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
gui.py,sha256=
|
|
1
|
+
gui.py,sha256=U_mAXHFJeSyDPF0lz3vs2AExwsOEdK_slAImKKRm9eE,136824
|
|
2
2
|
iannix.py,sha256=jlBJhPzBcIl2iayG01ldoslAytxYOvP3z_vN-EgiJA4,17188
|
|
3
|
-
image.py,sha256
|
|
3
|
+
image.py,sha256=wohpTTZH6QzN3wRfXI5ac7VTRsOKcwqk8_d3yha8oDw,3763
|
|
4
4
|
markov.py,sha256=VhTXZfDDHETj6KhriFmOLHKNjgx08cWZvpLECuGRTG0,24653
|
|
5
|
-
midi.py,sha256=
|
|
6
|
-
music.py,sha256
|
|
7
|
-
osc.py,sha256=
|
|
5
|
+
midi.py,sha256=g5qezyjD--oj92uUR7g91V4-IiYWhjrHQuIwV8XfQR8,27282
|
|
6
|
+
music.py,sha256=H-4c03IZBmjaLeio6ZQTl0BZGGU-Ri6GdiOj2L-mmJI,268534
|
|
7
|
+
osc.py,sha256=yUIIvPZmEmaxnpP2Q9FBh-sCL9aXR-qFDQk4N7998vk,8553
|
|
8
8
|
timer.py,sha256=uQ1BHWTjZ6DpJo-leGhxgOJcVcd1Lj0jvQQodXx1kw4,16341
|
|
9
9
|
zipf.py,sha256=J6fWwUYz88LFAwanc0TmXJlU7VtpBM24_Rw5XJTOn9c,40312
|
|
10
|
-
CreativePython/GuiHandler.py,sha256=
|
|
11
|
-
CreativePython/GuiRenderer.py,sha256=
|
|
10
|
+
CreativePython/GuiHandler.py,sha256=ONnxhqivBrzCHQv7GcE4vkMgnONbuXXq7Fwe0Au5QPs,30974
|
|
11
|
+
CreativePython/GuiRenderer.py,sha256=jqoKD2XSNeDJ4lAmQXfaEbtVrsL-4LublHhbUHbJRkk,139445
|
|
12
12
|
CreativePython/RealtimeAudioPlayer.py,sha256=tjqBjSOvSvH1kP0t6q35xsbKHPr0wuLUvGdxdWAY73E,44590
|
|
13
|
-
CreativePython/__init__.py,sha256=
|
|
13
|
+
CreativePython/__init__.py,sha256=bT1nZ-Fp8-7uiKqhVdnFeOwL-8Jps2rvE6BfoOE8fZ0,451
|
|
14
14
|
CreativePython/notationRenderer.py,sha256=2KIMvInNLEUZyn_r1KMmyt7X2XDrfekVkggFeHLRu1M,35440
|
|
15
15
|
CreativePython/nevmuse/RunMetrics.py,sha256=wP5HeS7u5VmH9s-9yyF1EuvF8xFcU6oYTT90Qr16Mu0,4917
|
|
16
16
|
CreativePython/nevmuse/Surveyor.py,sha256=y5_GgTpfZl4IteymBD1-I1lduZuw-ap1mS9zgnOamUc,4794
|
|
@@ -77,9 +77,9 @@ CreativePython/nevmuse/utilities/CSVWriter.py,sha256=k2GccvzD5IwdkmFdN5qtRA2qZX1
|
|
|
77
77
|
CreativePython/nevmuse/utilities/PowerLawRandom.py,sha256=WIEI-p8wiiWhkkBR5pO9gJ2TwxZBw453T_xXzCNdKPY,3752
|
|
78
78
|
CreativePython/nevmuse/utilities/__init__.py,sha256=pAGIMMGfLvR2DQfxr8qkfKQJ-4fIkVqlhnGK657JPL8,166
|
|
79
79
|
bin/libportaudio.2.dylib,sha256=ooJlm7QeL7jYzc1c8YMmH-C8PhYHwDvBJZkNDVPFRbE,286592
|
|
80
|
-
creativepython-1.1.
|
|
81
|
-
creativepython-1.1.
|
|
82
|
-
creativepython-1.1.
|
|
83
|
-
creativepython-1.1.
|
|
84
|
-
creativepython-1.1.
|
|
85
|
-
creativepython-1.1.
|
|
80
|
+
creativepython-1.1.5.dist-info/licenses/LICENSE,sha256=tz38qDa5RhHMqzZR1Q5QafqWdXn_EhheXYBP7FjgtEM,1992
|
|
81
|
+
creativepython-1.1.5.dist-info/licenses/LICENSE-PSF,sha256=JN1jUPIsEUH1mq3AXxet-b1IdhAr-XzscXBZiz74c9c,3371
|
|
82
|
+
creativepython-1.1.5.dist-info/METADATA,sha256=jesD86ZrXoIlpqmWVilNd9KtPsNsQEeP9UmEfMZEuzE,8703
|
|
83
|
+
creativepython-1.1.5.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
84
|
+
creativepython-1.1.5.dist-info/top_level.txt,sha256=PzvvUyy-3YzTedVGnLS02ju1TCMuo76h1LuVd8XvHhA,69
|
|
85
|
+
creativepython-1.1.5.dist-info/RECORD,,
|
gui.py
CHANGED
|
@@ -197,24 +197,48 @@ class Color:
|
|
|
197
197
|
"""
|
|
198
198
|
return self.red
|
|
199
199
|
|
|
200
|
+
def setRed(self, red):
|
|
201
|
+
"""
|
|
202
|
+
Sets the Color's red value (0-255).
|
|
203
|
+
"""
|
|
204
|
+
self.red = int(red)
|
|
205
|
+
|
|
200
206
|
def getGreen(self):
|
|
201
207
|
"""
|
|
202
208
|
Returns the Color's green value (0-255).
|
|
203
209
|
"""
|
|
204
210
|
return self.green
|
|
205
211
|
|
|
212
|
+
def setGreen(self, green):
|
|
213
|
+
"""
|
|
214
|
+
Sets the Color's green value (0-255).
|
|
215
|
+
"""
|
|
216
|
+
self.green = int(green)
|
|
217
|
+
|
|
206
218
|
def getBlue(self):
|
|
207
219
|
"""
|
|
208
220
|
Returns the Color's blue value (0-255).
|
|
209
221
|
"""
|
|
210
222
|
return self.blue
|
|
211
223
|
|
|
224
|
+
def setBlue(self, blue):
|
|
225
|
+
"""
|
|
226
|
+
Sets the Color's blue value (0-255).
|
|
227
|
+
"""
|
|
228
|
+
self.blue = int(blue)
|
|
229
|
+
|
|
212
230
|
def getAlpha(self):
|
|
213
231
|
"""
|
|
214
232
|
Returns the Color's transparency value (0-255).
|
|
215
233
|
"""
|
|
216
234
|
return self.alpha
|
|
217
235
|
|
|
236
|
+
def setAlpha(self, alpha):
|
|
237
|
+
"""
|
|
238
|
+
Sets the Color's transparency value (0-255).
|
|
239
|
+
"""
|
|
240
|
+
self.alpha = int(alpha)
|
|
241
|
+
|
|
218
242
|
def getRGB(self):
|
|
219
243
|
"""
|
|
220
244
|
Returns the Color's values (0-255) as a list.
|
|
@@ -442,9 +466,9 @@ class Font:
|
|
|
442
466
|
"""
|
|
443
467
|
Creates a new Font object.
|
|
444
468
|
"""
|
|
445
|
-
self.
|
|
446
|
-
self.
|
|
447
|
-
self.
|
|
469
|
+
self.name = name
|
|
470
|
+
self.style = style
|
|
471
|
+
self.size = size
|
|
448
472
|
|
|
449
473
|
def __str__(self):
|
|
450
474
|
return f'Font(name = "{self.getName()}", style = {self.getStyle()}, size = {self.getSize()}")'
|
|
@@ -456,7 +480,13 @@ class Font:
|
|
|
456
480
|
"""
|
|
457
481
|
Returns the Font's family name as a string.
|
|
458
482
|
"""
|
|
459
|
-
return self.
|
|
483
|
+
return self.name
|
|
484
|
+
|
|
485
|
+
def setName(self, name):
|
|
486
|
+
"""
|
|
487
|
+
Sets the Font's family name.
|
|
488
|
+
"""
|
|
489
|
+
self.name = name
|
|
460
490
|
|
|
461
491
|
def getStyle(self):
|
|
462
492
|
"""
|
|
@@ -464,13 +494,25 @@ class Font:
|
|
|
464
494
|
The first value represents the Font's weight.
|
|
465
495
|
The second value represents whether the Font is italicized.
|
|
466
496
|
"""
|
|
467
|
-
return self.
|
|
497
|
+
return self.style
|
|
498
|
+
|
|
499
|
+
def setStyle(self, style):
|
|
500
|
+
"""
|
|
501
|
+
Sets the Font's style (e.g., Font.PLAIN, Font.BOLD, Font.ITALIC, Font.BOLDITALIC).
|
|
502
|
+
"""
|
|
503
|
+
self.style = style
|
|
468
504
|
|
|
469
505
|
def getSize(self):
|
|
470
506
|
"""
|
|
471
507
|
Returns the Font's point size.
|
|
472
508
|
"""
|
|
473
|
-
return self.
|
|
509
|
+
return self.size
|
|
510
|
+
|
|
511
|
+
def setSize(self, size):
|
|
512
|
+
"""
|
|
513
|
+
Sets the Font's point size.
|
|
514
|
+
"""
|
|
515
|
+
self.size = size
|
|
474
516
|
|
|
475
517
|
|
|
476
518
|
#######################################################################################
|
|
@@ -1071,6 +1113,15 @@ class Display(_Interactable):
|
|
|
1071
1113
|
'font': fontData,
|
|
1072
1114
|
})
|
|
1073
1115
|
|
|
1116
|
+
# ── Compatibility Aliases ─────────────────────────────────────────────────────────
|
|
1117
|
+
|
|
1118
|
+
def drawText(self, text, x, y, color=Color.BLACK, font=None):
|
|
1119
|
+
"""
|
|
1120
|
+
Paints a text label onto the display's draw layer.
|
|
1121
|
+
Unlike add(), this is a one-time paint — no object is created or returned.
|
|
1122
|
+
The result is permanent until clearDrawing() is called.
|
|
1123
|
+
"""
|
|
1124
|
+
self.drawLabel(text, x, y, color, font)
|
|
1074
1125
|
|
|
1075
1126
|
#######################################################################################
|
|
1076
1127
|
# Drawable - items that can be added to a Display
|
|
@@ -2179,6 +2230,7 @@ class Icon(_Graphics):
|
|
|
2179
2230
|
self._height = height if height is not None else 0
|
|
2180
2231
|
self._originalWidth = self._width
|
|
2181
2232
|
self._originalHeight = self._height
|
|
2233
|
+
self._pixelCache = None # lazily populated on getPixel/getPixels; invalidated by crop/setPixel/setPixels
|
|
2182
2234
|
|
|
2183
2235
|
_handler().sendCommand('create', self._objectId, {
|
|
2184
2236
|
'type': 'Icon',
|
|
@@ -2224,8 +2276,9 @@ class Icon(_Graphics):
|
|
|
2224
2276
|
"""
|
|
2225
2277
|
Crop the icon to the specified rectangle, relative to the icon's position.
|
|
2226
2278
|
"""
|
|
2227
|
-
self._width
|
|
2228
|
-
self._height
|
|
2279
|
+
self._width = int(width)
|
|
2280
|
+
self._height = int(height)
|
|
2281
|
+
self._pixelCache = None # invalidate local cache
|
|
2229
2282
|
_handler().sendCommand('crop', self._objectId, {'x': x, 'y': y, 'width': width, 'height': height})
|
|
2230
2283
|
|
|
2231
2284
|
# ── Pixel Manipulation ────────────────────────────────────────────────────────────
|
|
@@ -2234,27 +2287,31 @@ class Icon(_Graphics):
|
|
|
2234
2287
|
"""
|
|
2235
2288
|
Returns the [r, g, b] color of a given pixel in the icon.
|
|
2236
2289
|
"""
|
|
2237
|
-
|
|
2238
|
-
|
|
2290
|
+
if self._pixelCache is None: # fetch local cache, if needed
|
|
2291
|
+
self._pixelCache = _handler().sendQuery('getPixels', self._objectId)
|
|
2292
|
+
return self._pixelCache[row][column]
|
|
2239
2293
|
|
|
2240
2294
|
def setPixel(self, column, row, color):
|
|
2241
2295
|
"""
|
|
2242
2296
|
Sets the [r, g, b] color of a given pixel in the icon.
|
|
2243
2297
|
"""
|
|
2244
2298
|
r, g, b = color
|
|
2299
|
+
self._pixelCache = None # invalidate local cache
|
|
2245
2300
|
_handler().sendCommand('setPixel', self._objectId, {'column': column, 'row': row, 'color': [r, g, b]})
|
|
2246
2301
|
|
|
2247
2302
|
def getPixels(self):
|
|
2248
2303
|
"""
|
|
2249
2304
|
Returns the [r, g, b] color of all pixels in the icon as a 2-dimensional array.
|
|
2250
2305
|
"""
|
|
2251
|
-
|
|
2252
|
-
|
|
2306
|
+
if self._pixelCache is None: # fetch local cache, if needed
|
|
2307
|
+
self._pixelCache = _handler().sendQuery('getPixels', self._objectId)
|
|
2308
|
+
return self._pixelCache
|
|
2253
2309
|
|
|
2254
2310
|
def setPixels(self, pixels):
|
|
2255
2311
|
"""
|
|
2256
2312
|
Sets the [r, g, b] color of all pixels in the icon from a 2-dimensional array.
|
|
2257
2313
|
"""
|
|
2314
|
+
self._pixelCache = None # invalidate local cache
|
|
2258
2315
|
_handler().sendCommand('setPixels', self._objectId, {'pixels': pixels})
|
|
2259
2316
|
|
|
2260
2317
|
|
image.py
CHANGED
|
@@ -24,8 +24,9 @@ class Image:
|
|
|
24
24
|
# (int, None) -> the width of a square, blank canvas
|
|
25
25
|
# (int, int) -> the width and height of a blank canvas
|
|
26
26
|
|
|
27
|
-
self._display = Display() #
|
|
28
|
-
self.
|
|
27
|
+
self._display = Display() # the display the image is on
|
|
28
|
+
self._icon = None # the icon that holds the image data (created in read())
|
|
29
|
+
self.read(arg1, arg2) # read() loads the icon and sets Display properties
|
|
29
30
|
|
|
30
31
|
def show(self):
|
|
31
32
|
"""
|