quickmacapp 2025.4.15__tar.gz → 2025.7.22__tar.gz
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.
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/PKG-INFO +1 -1
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/pyproject.toml +1 -1
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/src/quickmacapp/__init__.py +2 -1
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/src/quickmacapp/_quickapp.py +95 -23
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/src/quickmacapp.egg-info/PKG-INFO +1 -1
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/LICENSE +0 -0
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/README.rst +0 -0
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/setup.cfg +0 -0
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/src/quickmacapp/_background.py +0 -0
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/src/quickmacapp/_interactions.py +0 -0
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/src/quickmacapp/_notifications.py +0 -0
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/src/quickmacapp/notifications.py +0 -0
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/src/quickmacapp/py.typed +0 -0
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/src/quickmacapp.egg-info/SOURCES.txt +0 -0
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/src/quickmacapp.egg-info/dependency_links.txt +0 -0
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/src/quickmacapp.egg-info/requires.txt +0 -0
- {quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/src/quickmacapp.egg-info/top_level.txt +0 -0
|
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
|
|
|
9
9
|
name = "quickmacapp"
|
|
10
10
|
description = "Make it easier to write Mac apps in Python"
|
|
11
11
|
readme = "README.rst"
|
|
12
|
-
version = "2025.
|
|
12
|
+
version = "2025.07.22"
|
|
13
13
|
dependencies = [
|
|
14
14
|
"pyobjc-framework-Cocoa",
|
|
15
15
|
"pyobjc-framework-ExceptionHandling",
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
from ._quickapp import Actionable, Status, mainpoint, menu, quit
|
|
1
|
+
from ._quickapp import Actionable, ItemState, Status, mainpoint, menu, quit
|
|
2
2
|
from ._interactions import ask, choose, answer, getpass
|
|
3
3
|
from ._background import dockIconWhenVisible
|
|
4
4
|
|
|
5
5
|
__all__ = [
|
|
6
6
|
"Actionable",
|
|
7
|
+
"ItemState",
|
|
7
8
|
"Status",
|
|
8
9
|
"mainpoint",
|
|
9
10
|
"menu",
|
|
@@ -3,31 +3,48 @@ from __future__ import annotations
|
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
5
5
|
import traceback
|
|
6
|
-
from
|
|
7
|
-
|
|
8
|
-
from
|
|
9
|
-
|
|
10
|
-
from Foundation import (
|
|
11
|
-
NSObject,
|
|
12
|
-
NSException,
|
|
13
|
-
)
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from types import FunctionType
|
|
8
|
+
from typing import Any, Callable, Iterable, Protocol, Sequence, Literal
|
|
14
9
|
|
|
15
10
|
from AppKit import (
|
|
16
11
|
NSApp,
|
|
17
12
|
NSApplication,
|
|
18
13
|
NSEvent,
|
|
19
|
-
NSResponder,
|
|
20
|
-
NSMenu,
|
|
21
14
|
NSImage,
|
|
15
|
+
NSMenu,
|
|
22
16
|
NSMenuItem,
|
|
17
|
+
NSResponder,
|
|
23
18
|
NSStatusBar,
|
|
24
19
|
NSVariableStatusItemLength,
|
|
20
|
+
NSControlStateValueOn,
|
|
21
|
+
NSControlStateValueOff,
|
|
25
22
|
)
|
|
26
|
-
|
|
23
|
+
from ExceptionHandling import NSStackTraceKey # type:ignore
|
|
24
|
+
from Foundation import NSException, NSObject
|
|
25
|
+
from objc import IBAction, ivar, super
|
|
27
26
|
from PyObjCTools.Debugging import _run_atos, isPythonException
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def asSelectorString(f: FunctionType) -> str:
|
|
30
|
+
"""
|
|
31
|
+
Convert a method on a PyObjC class into a selector string.
|
|
32
|
+
"""
|
|
33
|
+
return f.__name__.replace("_", ":")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass(kw_only=True)
|
|
37
|
+
class ItemState:
|
|
38
|
+
"""
|
|
39
|
+
The state of a menu item.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
enabled: bool = True
|
|
43
|
+
"Should the menu item be disabled? True if not, False if so."
|
|
44
|
+
checked: bool = False
|
|
45
|
+
"Should the menu item display a check-mark next to itself? True if so, False if not."
|
|
46
|
+
key: str | None = None
|
|
47
|
+
"Should the menu shortcut mnemonic key be set, blank, or derived from the item's title?"
|
|
31
48
|
|
|
32
49
|
|
|
33
50
|
class Actionable(NSObject):
|
|
@@ -35,15 +52,29 @@ class Actionable(NSObject):
|
|
|
35
52
|
Wrap a Python no-argument function call in an NSObject with a C{doIt:}
|
|
36
53
|
method.
|
|
37
54
|
"""
|
|
38
|
-
|
|
55
|
+
|
|
56
|
+
_thunk: Callable[[], object]
|
|
57
|
+
_state: ItemState
|
|
39
58
|
|
|
40
59
|
def initWithFunction_(self, thunk: Callable[[], None]) -> Actionable:
|
|
41
60
|
"""
|
|
42
|
-
|
|
61
|
+
Backwards compatibility initializer, creating this L{Actionable} in the
|
|
62
|
+
default L{ItemState}.
|
|
63
|
+
"""
|
|
64
|
+
return self.initWithFunction_andState_(thunk, ItemState())
|
|
65
|
+
|
|
66
|
+
def initWithFunction_andState_(
|
|
67
|
+
self, thunk: Callable[[], None], state: ItemState
|
|
68
|
+
) -> Actionable:
|
|
69
|
+
"""
|
|
70
|
+
Remember the given callable, and the given menu state.
|
|
43
71
|
|
|
44
72
|
@param thunk: the callable to run in L{doIt_}.
|
|
73
|
+
|
|
74
|
+
@param state: the initial state of the menu item presentation
|
|
45
75
|
"""
|
|
46
76
|
self._thunk = thunk
|
|
77
|
+
self._state = state
|
|
47
78
|
return self
|
|
48
79
|
|
|
49
80
|
@IBAction
|
|
@@ -52,10 +83,41 @@ class Actionable(NSObject):
|
|
|
52
83
|
Call the given callable; exposed as an C{IBAction} in case you want IB
|
|
53
84
|
to be able to see it.
|
|
54
85
|
"""
|
|
55
|
-
self._thunk()
|
|
86
|
+
result = self._thunk()
|
|
87
|
+
if isinstance(result, ItemState):
|
|
88
|
+
self._state = result
|
|
89
|
+
|
|
90
|
+
def validateMenuItem_(self, item: NSMenuItem) -> bool:
|
|
91
|
+
item.setState_(
|
|
92
|
+
NSControlStateValueOn if self._state.checked else NSControlStateValueOff
|
|
93
|
+
)
|
|
94
|
+
return self._state.enabled
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
ACTION_METHOD = asSelectorString(Actionable.doIt_)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _adjust(
|
|
101
|
+
items: Iterable[
|
|
102
|
+
tuple[str, Callable[[], object]] | tuple[str, Callable[[], object], ItemState]
|
|
103
|
+
],
|
|
104
|
+
) -> Iterable[tuple[str, Callable[[], object], ItemState]]:
|
|
105
|
+
for item in items:
|
|
106
|
+
if len(item) == 3:
|
|
107
|
+
yield item
|
|
108
|
+
else:
|
|
109
|
+
yield (*item, ItemState())
|
|
56
110
|
|
|
57
111
|
|
|
58
|
-
|
|
112
|
+
ItemSeq = Sequence[
|
|
113
|
+
tuple[str, Callable[[], object]] | tuple[str, Callable[[], object], ItemState]
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def menu(
|
|
118
|
+
title: str,
|
|
119
|
+
items: ItemSeq,
|
|
120
|
+
) -> NSMenu:
|
|
59
121
|
"""
|
|
60
122
|
Construct an NSMenu from a list of tuples describing it.
|
|
61
123
|
|
|
@@ -68,11 +130,16 @@ def menu(title: str, items: list[tuple[str, Callable[[], object]]]) -> NSMenu:
|
|
|
68
130
|
@return: a new Menu tha is not attached to anything.
|
|
69
131
|
"""
|
|
70
132
|
result = NSMenu.alloc().initWithTitle_(title)
|
|
71
|
-
for
|
|
133
|
+
for subtitle, thunk, state in _adjust(items):
|
|
134
|
+
initialKeyEquivalent = subtitle[0].lower()
|
|
72
135
|
item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
|
|
73
|
-
subtitle,
|
|
136
|
+
subtitle,
|
|
137
|
+
ACTION_METHOD,
|
|
138
|
+
initialKeyEquivalent if state.key is None else state.key,
|
|
139
|
+
)
|
|
140
|
+
item.setTarget_(
|
|
141
|
+
Actionable.alloc().initWithFunction_andState_(thunk, state).retain()
|
|
74
142
|
)
|
|
75
|
-
item.setTarget_(Actionable.alloc().initWithFunction_(thunk).retain())
|
|
76
143
|
result.addItem_(item)
|
|
77
144
|
result.update()
|
|
78
145
|
return result
|
|
@@ -97,11 +164,12 @@ class Status:
|
|
|
97
164
|
self.item.button().setImage_(image)
|
|
98
165
|
elif text is None:
|
|
99
166
|
from __main__ import __file__ as default
|
|
167
|
+
|
|
100
168
|
text = os.path.basename(default)
|
|
101
169
|
if text is not None:
|
|
102
170
|
self.item.button().setTitle_(text)
|
|
103
171
|
|
|
104
|
-
def menu(self, items:
|
|
172
|
+
def menu(self, items: ItemSeq) -> None:
|
|
105
173
|
"""
|
|
106
174
|
Set the status drop-down menu.
|
|
107
175
|
|
|
@@ -183,6 +251,7 @@ class QuickApplication(NSApplication):
|
|
|
183
251
|
be more complicated in LSUIElement apps, but there might be a better
|
|
184
252
|
way to do this.)
|
|
185
253
|
"""
|
|
254
|
+
|
|
186
255
|
keyEquivalentHandler: NSResponder = ivar()
|
|
187
256
|
|
|
188
257
|
def sendEvent_(self, event: NSEvent) -> None:
|
|
@@ -210,6 +279,7 @@ class MainRunner(Protocol):
|
|
|
210
279
|
"""
|
|
211
280
|
A function which has been decorated with a runMain attribute.
|
|
212
281
|
"""
|
|
282
|
+
|
|
213
283
|
def __call__(self, reactor: Any) -> None:
|
|
214
284
|
"""
|
|
215
285
|
@param reactor: A Twisted reactor, which provides the usual suspects of
|
|
@@ -218,6 +288,7 @@ class MainRunner(Protocol):
|
|
|
218
288
|
|
|
219
289
|
runMain: Callable[[], None]
|
|
220
290
|
|
|
291
|
+
|
|
221
292
|
def mainpoint() -> Callable[[Callable[[Any], None]], MainRunner]:
|
|
222
293
|
"""
|
|
223
294
|
Add a .runMain attribute to function
|
|
@@ -227,10 +298,11 @@ def mainpoint() -> Callable[[Callable[[Any], None]], MainRunner]:
|
|
|
227
298
|
The runMain attribute starts a reactor and calls the original function
|
|
228
299
|
with a running, initialized, reactor.
|
|
229
300
|
"""
|
|
301
|
+
|
|
230
302
|
def wrapup(appmain: Callable[[Any], None]) -> MainRunner:
|
|
231
303
|
def doIt() -> None:
|
|
232
|
-
from twisted.internet import cfreactor
|
|
233
304
|
import PyObjCTools.AppHelper
|
|
305
|
+
from twisted.internet import cfreactor
|
|
234
306
|
|
|
235
307
|
QuickApplication.sharedApplication()
|
|
236
308
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quickmacapp-2025.4.15 → quickmacapp-2025.7.22}/src/quickmacapp.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|