chartflow 0.1__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.
- chartflow/__init__.py +28 -0
- chartflow/_verify_importexport.py +169 -0
- chartflow/edit/__init__.py +119 -0
- chartflow/edit/code_editor.py +1007 -0
- chartflow/edit/code_folder.py +523 -0
- chartflow/edit/completer.py +2652 -0
- chartflow/edit/context_analyzer.py +521 -0
- chartflow/edit/demo.py +469 -0
- chartflow/edit/line_number_area.py +548 -0
- chartflow/edit/minimap.py +581 -0
- chartflow/edit/python_editor.py +509 -0
- chartflow/edit/syntax_highlighter.py +291 -0
- chartflow/edit/test_editor.py +190 -0
- chartflow/flow/__init__.py +31 -0
- chartflow/flow/_demo.py +98 -0
- chartflow/flow/chart.py +1101 -0
- chartflow/flow/editor.py +375 -0
- chartflow/flow/flow.py +6 -0
- chartflow/flow/qchart.py +1250 -0
- chartflow/flow/test/__init__.py +0 -0
- chartflow/flow/test/test_chart.py +537 -0
- chartflow/flow/test_decorator_sync.py +102 -0
- chartflow/fsm/__init__.py +84 -0
- chartflow/fsm/decorators.py +395 -0
- chartflow/fsm/demo.py +381 -0
- chartflow/fsm/demo_pyqt6.py +881 -0
- chartflow/fsm/demo_tree.py +46 -0
- chartflow/fsm/logic.py +447 -0
- chartflow/fsm/meta.py +569 -0
- chartflow/fsm/scheduler.py +427 -0
- chartflow/fsm/stage.py +2079 -0
- chartflow/fsm/stdio.py +66 -0
- chartflow/fsm/test/__init__.py +7 -0
- chartflow/fsm/test/test_decorators.py +210 -0
- chartflow/fsm/test/test_events.py +202 -0
- chartflow/fsm/test/test_integration.py +596 -0
- chartflow/fsm/test/test_logic.py +371 -0
- chartflow/fsm/test/test_meta.py +192 -0
- chartflow/fsm/test/test_runtime_param.py +336 -0
- chartflow/fsm/test/test_scheduler.py +280 -0
- chartflow/fsm/test/test_stage.py +314 -0
- chartflow/fsm/test_behavior_events.py +263 -0
- chartflow/fsm/test_nested_parallel.py +80 -0
- chartflow/fsm/test_stage_spec.py +448 -0
- chartflow/fsm/utils.py +34 -0
- chartflow/node/__init__.py +66 -0
- chartflow/node/_node_base.py +727 -0
- chartflow/node/_node_interaction.py +488 -0
- chartflow/node/_node_interface.py +426 -0
- chartflow/node/_node_markers.py +648 -0
- chartflow/node/_node_ports.py +536 -0
- chartflow/node/_port_interface.py +111 -0
- chartflow/node/arrow_item.py +287 -0
- chartflow/node/color_utils.py +113 -0
- chartflow/node/connection_item.py +939 -0
- chartflow/node/demo.py +258 -0
- chartflow/node/demo_arrow_drag.py +46 -0
- chartflow/node/demo_decorator.py +63 -0
- chartflow/node/demo_ports.py +69 -0
- chartflow/node/enums.py +35 -0
- chartflow/node/example.py +84 -0
- chartflow/node/layout_utils.py +307 -0
- chartflow/node/main_window.py +196 -0
- chartflow/node/menu_bar.py +240 -0
- chartflow/node/node_canvas.py +1730 -0
- chartflow/node/node_item.py +754 -0
- chartflow/node/popmenu.py +472 -0
- chartflow/node/port_item.py +591 -0
- chartflow/node/qnode_editor.py +73 -0
- chartflow/node/selection_rect.py +53 -0
- chartflow/node/style_panel.py +615 -0
- chartflow/node/styles.py +63 -0
- chartflow/node/test_qnode.py +2336 -0
- chartflow/showcase.py +528 -0
- chartflow/theme.py +508 -0
- chartflow-0.1.dist-info/METADATA +23 -0
- chartflow-0.1.dist-info/RECORD +79 -0
- chartflow-0.1.dist-info/WHEEL +5 -0
- chartflow-0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import time
|
|
3
|
+
from random import random
|
|
4
|
+
from chartflow.fsm import *
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MyLogic(Logic):
|
|
8
|
+
NAME = "My"
|
|
9
|
+
|
|
10
|
+
@sequence("second", "third")
|
|
11
|
+
def first(self, it):
|
|
12
|
+
it.now = self.now # 在 BlackBoard 上动态添加 now 属性
|
|
13
|
+
return random() < 0.7
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def second(self, it):
|
|
17
|
+
if it.now == self.now:
|
|
18
|
+
return None
|
|
19
|
+
return random() > 0.5
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@selector("A", "B")
|
|
23
|
+
def third(self, it):
|
|
24
|
+
return random() < 0.5
|
|
25
|
+
|
|
26
|
+
def A(self, it):
|
|
27
|
+
if random() < 0.25: return
|
|
28
|
+
return random() < 0.5
|
|
29
|
+
|
|
30
|
+
def B(self, it):
|
|
31
|
+
if random() < 0.25: return
|
|
32
|
+
return random() < 0.5
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@listen("system")
|
|
36
|
+
def my_handle(self, data):
|
|
37
|
+
print(f"{self.name} recv event: {data}")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# 创建调度器
|
|
41
|
+
sch = Scheduler()
|
|
42
|
+
cl0 = Logic("My") # inst 默认是 BlackBoard()
|
|
43
|
+
|
|
44
|
+
for i in range(10):
|
|
45
|
+
print("TICK{}".format(sch.tick))
|
|
46
|
+
sch.handle()
|
chartflow/fsm/logic.py
ADDED
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
"""
|
|
3
|
+
qfsm Logic Module - Scheduled state machine instances
|
|
4
|
+
|
|
5
|
+
This module provides the Logic class which extends Stage with scheduler
|
|
6
|
+
integration, lifecycle management, and instance referencing capabilities.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
from typing import Any, ClassVar, Self
|
|
11
|
+
|
|
12
|
+
from chartflow.fsm.stage import Stage
|
|
13
|
+
from chartflow.fsm.scheduler import Scheduler
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Logic(Stage):
|
|
17
|
+
"""
|
|
18
|
+
Scheduled state machine instance with lifecycle management.
|
|
19
|
+
|
|
20
|
+
Logic extends Stage with:
|
|
21
|
+
- Automatic registration with the Scheduler singleton
|
|
22
|
+
- 4-phase lifecycle (_check, _enter, _step, _exit)
|
|
23
|
+
- Instance referencing (ref, refLast, refNext, etc.)
|
|
24
|
+
- Priority-based execution
|
|
25
|
+
|
|
26
|
+
Class Attributes:
|
|
27
|
+
NAME: The display name for this logic type (required)
|
|
28
|
+
PRIORITY: Execution priority (higher = earlier, default: 0)
|
|
29
|
+
LOG: Whether to log state transitions (default: True)
|
|
30
|
+
|
|
31
|
+
Instance Attributes:
|
|
32
|
+
alive: Whether instance should continue processing
|
|
33
|
+
enabled: Whether instance is currently enabled
|
|
34
|
+
uid: Unique instance identifier
|
|
35
|
+
priority: Execution priority for this instance
|
|
36
|
+
|
|
37
|
+
Example:
|
|
38
|
+
class EnemyAI(Logic):
|
|
39
|
+
NAME = "EnemyAI"
|
|
40
|
+
PRIORITY = 10
|
|
41
|
+
|
|
42
|
+
def __init__(self, enemy):
|
|
43
|
+
super().__init__(enemy)
|
|
44
|
+
self.health = 100
|
|
45
|
+
|
|
46
|
+
def idle(self):
|
|
47
|
+
if self._inst.player_nearby:
|
|
48
|
+
return "chase"
|
|
49
|
+
|
|
50
|
+
def chase(self):
|
|
51
|
+
if not self._inst.player_nearby:
|
|
52
|
+
return "idle"
|
|
53
|
+
self._inst.move_toward_player()
|
|
54
|
+
|
|
55
|
+
Lifecycle:
|
|
56
|
+
1. __init__ -> auto-registers with Scheduler
|
|
57
|
+
2. _check -> validate if should run
|
|
58
|
+
3. _enter -> first-time initialization (calls onStart)
|
|
59
|
+
4. _step -> per-tick execution (calls handleStage, onStep)
|
|
60
|
+
5. _exit -> cleanup when dead (calls onStop)
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
# Class attributes
|
|
64
|
+
NAME: ClassVar[str] = "Logic"
|
|
65
|
+
PRIORITY: ClassVar[int] = 0
|
|
66
|
+
LOG: ClassVar[bool] = True
|
|
67
|
+
|
|
68
|
+
# Class-level instance tracking by name (name -> {uid: instance})
|
|
69
|
+
# Using explicit mangled name to allow tests to reset state
|
|
70
|
+
_Logic__names__: ClassVar[dict[str, dict[int, Logic]]] = {}
|
|
71
|
+
|
|
72
|
+
def __init__(self, inst: Any = None) -> None:
|
|
73
|
+
"""
|
|
74
|
+
Initialize Logic and auto-register with Scheduler.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
inst: The bound instance (e.g., game entity)
|
|
78
|
+
|
|
79
|
+
Note:
|
|
80
|
+
Automatically calls Scheduler().add(self) to register
|
|
81
|
+
for scheduled execution.
|
|
82
|
+
"""
|
|
83
|
+
# Instance lifecycle attributes
|
|
84
|
+
self._alive: bool = True
|
|
85
|
+
self._enabled: bool = True
|
|
86
|
+
self._isEntered: bool = False
|
|
87
|
+
|
|
88
|
+
super().__init__(inst)
|
|
89
|
+
|
|
90
|
+
# Register in __names__ dictionary for instance referencing
|
|
91
|
+
if self.NAME not in Logic._Logic__names__:
|
|
92
|
+
Logic._Logic__names__[self.NAME] = {}
|
|
93
|
+
Logic._Logic__names__[self.NAME][self.uid] = self
|
|
94
|
+
|
|
95
|
+
# Auto-register with scheduler
|
|
96
|
+
Scheduler().add(self)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# ========================================================================
|
|
100
|
+
# Lifecycle Methods (called by Scheduler)
|
|
101
|
+
# ========================================================================
|
|
102
|
+
|
|
103
|
+
def _check(self, is_seek: bool) -> bool:
|
|
104
|
+
"""
|
|
105
|
+
Check if instance should run this tick.
|
|
106
|
+
|
|
107
|
+
Called by Scheduler during the check phase.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
is_seek: Whether this is a seek/check-only pass
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
True if instance should continue processing
|
|
114
|
+
|
|
115
|
+
Override this to add custom validation logic.
|
|
116
|
+
Example:
|
|
117
|
+
def _check(self, is_seek):
|
|
118
|
+
# Only run if entity is active
|
|
119
|
+
return self._alive and self._inst.is_active
|
|
120
|
+
"""
|
|
121
|
+
return self._alive and self._enabled
|
|
122
|
+
|
|
123
|
+
def _enter(self) -> None:
|
|
124
|
+
"""
|
|
125
|
+
Called on first entry (before first _step).
|
|
126
|
+
|
|
127
|
+
Called by Scheduler during the enter phase.
|
|
128
|
+
Override onStart() for custom initialization.
|
|
129
|
+
"""
|
|
130
|
+
self._isEntered = True
|
|
131
|
+
self.onStart(self._inst)
|
|
132
|
+
|
|
133
|
+
def _step(self) -> None:
|
|
134
|
+
"""
|
|
135
|
+
Called each tick during execution.
|
|
136
|
+
|
|
137
|
+
Called by Scheduler during the step phase.
|
|
138
|
+
Executes handleStage() and calls onStep().
|
|
139
|
+
"""
|
|
140
|
+
self.handleStage(log=self.LOG)
|
|
141
|
+
self.onStep(self._inst)
|
|
142
|
+
|
|
143
|
+
def _exit(self) -> None:
|
|
144
|
+
"""
|
|
145
|
+
Called when instance is removed (alive=False).
|
|
146
|
+
|
|
147
|
+
Called by Scheduler during the exit phase.
|
|
148
|
+
Unregisters instance and calls onStop().
|
|
149
|
+
"""
|
|
150
|
+
self.onStop(self._inst)
|
|
151
|
+
|
|
152
|
+
# ========================================================================
|
|
153
|
+
# Lifecycle Hooks (override in subclasses)
|
|
154
|
+
# ========================================================================
|
|
155
|
+
|
|
156
|
+
def onStart(self, inst:Any) -> None:
|
|
157
|
+
"""Hook called on first entry. Override for initialization."""
|
|
158
|
+
pass
|
|
159
|
+
|
|
160
|
+
def onStep(self, inst:Any) -> None:
|
|
161
|
+
"""Hook called each tick after handleStage. Override for per-tick logic."""
|
|
162
|
+
pass
|
|
163
|
+
|
|
164
|
+
def onStop(self, inst:Any) -> None:
|
|
165
|
+
"""Hook called on removal. Override for cleanup."""
|
|
166
|
+
pass
|
|
167
|
+
|
|
168
|
+
def onKilled(self, inst:Any) -> None:
|
|
169
|
+
"""Hook called when instance is killed. Override for death handling."""
|
|
170
|
+
pass
|
|
171
|
+
|
|
172
|
+
# ========================================================================
|
|
173
|
+
# Reference Methods
|
|
174
|
+
# ========================================================================
|
|
175
|
+
|
|
176
|
+
def ref(self, name: str) -> Logic | list[Logic] | None:
|
|
177
|
+
"""
|
|
178
|
+
Get instance(s) by name.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
name: The NAME of the Logic class to find
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
- Single Logic instance if only one exists
|
|
185
|
+
- List of Logic instances if multiple exist
|
|
186
|
+
- None if no instances exist
|
|
187
|
+
|
|
188
|
+
Example:
|
|
189
|
+
>>> enemy = self.ref("EnemyAI")
|
|
190
|
+
>>> players = self.ref("PlayerController") # May return list
|
|
191
|
+
"""
|
|
192
|
+
# First try to find by NAME (e.g., "TestLogic")
|
|
193
|
+
instances = Logic._Logic__names__.get(name, {})
|
|
194
|
+
if instances:
|
|
195
|
+
values = list(instances.values())
|
|
196
|
+
if len(values) == 1:
|
|
197
|
+
return values[0]
|
|
198
|
+
return values.copy()
|
|
199
|
+
|
|
200
|
+
# If not found, try to find by full name (e.g., "TestLogic0")
|
|
201
|
+
# Parse name to extract NAME and uid
|
|
202
|
+
for name_key, name_instances in Logic._Logic__names__.items():
|
|
203
|
+
for uid, instance in name_instances.items():
|
|
204
|
+
if instance.name == name:
|
|
205
|
+
return instance
|
|
206
|
+
|
|
207
|
+
return None
|
|
208
|
+
|
|
209
|
+
def refLast(self) -> Logic | None:
|
|
210
|
+
"""
|
|
211
|
+
Get the previous instance with the same NAME.
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
Previous instance in the same NAME group, or None
|
|
215
|
+
|
|
216
|
+
Example:
|
|
217
|
+
>>> prev = self.refLast() # Get previous EnemyAI instance
|
|
218
|
+
"""
|
|
219
|
+
instances = Logic._Logic__names__.get(self.NAME, {})
|
|
220
|
+
if not instances:
|
|
221
|
+
return None
|
|
222
|
+
|
|
223
|
+
# Get sorted list of uids to find previous
|
|
224
|
+
uids = sorted(instances.keys())
|
|
225
|
+
try:
|
|
226
|
+
idx = uids.index(self.uid)
|
|
227
|
+
if idx > 0:
|
|
228
|
+
return instances[uids[idx - 1]]
|
|
229
|
+
except ValueError:
|
|
230
|
+
pass
|
|
231
|
+
return None
|
|
232
|
+
|
|
233
|
+
def refNext(self) -> Logic | None:
|
|
234
|
+
"""
|
|
235
|
+
Get the next instance with the same NAME.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Next instance in the same NAME group, or None
|
|
239
|
+
|
|
240
|
+
Example:
|
|
241
|
+
>>> next_enemy = self.refNext() # Get next EnemyAI instance
|
|
242
|
+
"""
|
|
243
|
+
instances = Logic._Logic__names__.get(self.NAME, {})
|
|
244
|
+
if not instances:
|
|
245
|
+
return None
|
|
246
|
+
|
|
247
|
+
# Get sorted list of uids to find next
|
|
248
|
+
uids = sorted(instances.keys())
|
|
249
|
+
try:
|
|
250
|
+
idx = uids.index(self.uid)
|
|
251
|
+
if idx < len(uids) - 1:
|
|
252
|
+
return instances[uids[idx + 1]]
|
|
253
|
+
except ValueError:
|
|
254
|
+
pass
|
|
255
|
+
return None
|
|
256
|
+
|
|
257
|
+
def refAdjacent(self) -> tuple[Logic | None, Logic | None]:
|
|
258
|
+
"""
|
|
259
|
+
Get both previous and next instances with the same NAME.
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
Tuple of (previous_instance, next_instance)
|
|
263
|
+
|
|
264
|
+
Example:
|
|
265
|
+
>>> prev, next = self.refAdjacent()
|
|
266
|
+
>>> if prev:
|
|
267
|
+
... print(f"Previous: {prev.uid}")
|
|
268
|
+
>>> if next:
|
|
269
|
+
... print(f"Next: {next.uid}")
|
|
270
|
+
"""
|
|
271
|
+
return (self.refLast(), self.refNext())
|
|
272
|
+
|
|
273
|
+
def refHead(self) -> Logic | None:
|
|
274
|
+
"""
|
|
275
|
+
Get the first instance with the same NAME.
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
First instance in the NAME group, or None
|
|
279
|
+
|
|
280
|
+
Example:
|
|
281
|
+
>>> first_enemy = self.refHead() # Get first EnemyAI
|
|
282
|
+
"""
|
|
283
|
+
instances = Logic._Logic__names__.get(self.NAME, {})
|
|
284
|
+
if not instances:
|
|
285
|
+
return None
|
|
286
|
+
# Return instance with smallest uid
|
|
287
|
+
min_uid = min(instances.keys())
|
|
288
|
+
return instances[min_uid]
|
|
289
|
+
|
|
290
|
+
def refEnd(self) -> Logic | None:
|
|
291
|
+
"""
|
|
292
|
+
Get the last instance with the same NAME.
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
Last instance in the NAME group, or None
|
|
296
|
+
|
|
297
|
+
Example:
|
|
298
|
+
>>> last_enemy = self.refEnd() # Get last EnemyAI
|
|
299
|
+
"""
|
|
300
|
+
instances = Logic._Logic__names__.get(self.NAME, {})
|
|
301
|
+
if not instances:
|
|
302
|
+
return None
|
|
303
|
+
# Return instance with largest uid
|
|
304
|
+
max_uid = max(instances.keys())
|
|
305
|
+
return instances[max_uid]
|
|
306
|
+
|
|
307
|
+
# ========================================================================
|
|
308
|
+
# Properties
|
|
309
|
+
# ========================================================================
|
|
310
|
+
|
|
311
|
+
@property
|
|
312
|
+
def scheduler(self):
|
|
313
|
+
return Scheduler()
|
|
314
|
+
|
|
315
|
+
@property
|
|
316
|
+
def alive(self) -> bool:
|
|
317
|
+
"""Whether instance should continue processing."""
|
|
318
|
+
return self._alive
|
|
319
|
+
|
|
320
|
+
@alive.setter
|
|
321
|
+
def alive(self, value: bool) -> None:
|
|
322
|
+
"""Set alive state. Setting to False triggers removal."""
|
|
323
|
+
self._alive = value
|
|
324
|
+
if not value:
|
|
325
|
+
self.onKilled(self._inst)
|
|
326
|
+
|
|
327
|
+
@property
|
|
328
|
+
def enabled(self) -> bool:
|
|
329
|
+
"""Whether instance is currently enabled."""
|
|
330
|
+
return self._enabled
|
|
331
|
+
|
|
332
|
+
@enabled.setter
|
|
333
|
+
def enabled(self, value: bool) -> None:
|
|
334
|
+
"""Enable or disable instance processing."""
|
|
335
|
+
self._enabled = value
|
|
336
|
+
|
|
337
|
+
@property
|
|
338
|
+
def priority(self) -> int:
|
|
339
|
+
"""Execution priority (higher = earlier)."""
|
|
340
|
+
return self.PRIORITY
|
|
341
|
+
|
|
342
|
+
# ========================================================================
|
|
343
|
+
# Control Methods
|
|
344
|
+
# ========================================================================
|
|
345
|
+
|
|
346
|
+
def kill(self) -> None:
|
|
347
|
+
"""Mark instance for removal (sets alive=False)."""
|
|
348
|
+
self._alive = False
|
|
349
|
+
# Remove from __names__ registry
|
|
350
|
+
if self.NAME in Logic._Logic__names__:
|
|
351
|
+
if self.uid in Logic._Logic__names__[self.NAME]:
|
|
352
|
+
del Logic._Logic__names__[self.NAME][self.uid]
|
|
353
|
+
# Clean up empty dicts
|
|
354
|
+
if not Logic._Logic__names__[self.NAME]:
|
|
355
|
+
del Logic._Logic__names__[self.NAME]
|
|
356
|
+
|
|
357
|
+
def enable(self) -> None:
|
|
358
|
+
"""Enable instance processing."""
|
|
359
|
+
self._enabled = True
|
|
360
|
+
|
|
361
|
+
def disable(self) -> None:
|
|
362
|
+
"""Disable instance processing."""
|
|
363
|
+
self._enabled = False
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
# ========================================================================
|
|
367
|
+
# Scheduling Methods
|
|
368
|
+
# ========================================================================
|
|
369
|
+
|
|
370
|
+
def schedule(self, delay: int, callback: Any) -> None:
|
|
371
|
+
"""
|
|
372
|
+
Schedule a callback to run after a delay.
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
delay: Number of ticks to wait
|
|
376
|
+
callback: Function to call
|
|
377
|
+
"""
|
|
378
|
+
# Store scheduled callback (implementation depends on scheduler)
|
|
379
|
+
if not hasattr(self, '_scheduled'):
|
|
380
|
+
self._scheduled: list[tuple[int, Any]] = []
|
|
381
|
+
self._scheduled.append((delay, callback))
|
|
382
|
+
|
|
383
|
+
def cancelSchedule(self, callback: Any | None = None) -> bool:
|
|
384
|
+
"""
|
|
385
|
+
Cancel scheduled callbacks.
|
|
386
|
+
|
|
387
|
+
Args:
|
|
388
|
+
callback: Specific callback to cancel (None = all)
|
|
389
|
+
|
|
390
|
+
Returns:
|
|
391
|
+
True if any callbacks were cancelled
|
|
392
|
+
"""
|
|
393
|
+
if not hasattr(self, '_scheduled'):
|
|
394
|
+
return False
|
|
395
|
+
|
|
396
|
+
if callback is None:
|
|
397
|
+
removed = len(self._scheduled) > 0
|
|
398
|
+
self._scheduled.clear()
|
|
399
|
+
return removed
|
|
400
|
+
|
|
401
|
+
original_len = len(self._scheduled)
|
|
402
|
+
self._scheduled = [(d, cb) for d, cb in self._scheduled if cb != callback]
|
|
403
|
+
return len(self._scheduled) < original_len
|
|
404
|
+
|
|
405
|
+
# ========================================================================
|
|
406
|
+
# Queue Methods (for priority queue manipulation)
|
|
407
|
+
# ========================================================================
|
|
408
|
+
|
|
409
|
+
def productQueue(self) -> None:
|
|
410
|
+
"""Move to front of priority queue (highest priority)."""
|
|
411
|
+
# This would be implemented by the scheduler
|
|
412
|
+
pass
|
|
413
|
+
|
|
414
|
+
def showQueue(self) -> None:
|
|
415
|
+
"""Show current position in queue (for debugging)."""
|
|
416
|
+
scheduler = Scheduler()
|
|
417
|
+
if self in scheduler.updates:
|
|
418
|
+
idx = scheduler.updates.index(self)
|
|
419
|
+
print(f"{self._name} at position {idx}")
|
|
420
|
+
|
|
421
|
+
def jumpQueue(self, target: Logic) -> None:
|
|
422
|
+
"""Jump to position relative to target instance."""
|
|
423
|
+
# Implementation depends on scheduler internals
|
|
424
|
+
pass
|
|
425
|
+
|
|
426
|
+
def accelerate(self, amount: int = 1) -> None:
|
|
427
|
+
"""Increase priority temporarily."""
|
|
428
|
+
# Implementation depends on scheduler internals
|
|
429
|
+
pass
|
|
430
|
+
|
|
431
|
+
def __repr__(self) -> str:
|
|
432
|
+
"""Detailed string representation."""
|
|
433
|
+
return (
|
|
434
|
+
f"{self.__class__.__name__}("
|
|
435
|
+
f"name='{self._name}', "
|
|
436
|
+
f"uid={self._uid}, "
|
|
437
|
+
f"alive={self._alive}, "
|
|
438
|
+
f"enabled={self._enabled}, "
|
|
439
|
+
f"state={self._current}, "
|
|
440
|
+
f"priority={self.PRIORITY}"
|
|
441
|
+
f")"
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
__all__ = [
|
|
446
|
+
'Logic',
|
|
447
|
+
]
|