salabim 23.3.7__tar.gz → 23.3.8__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {salabim-23.3.7 → salabim-23.3.8}/PKG-INFO +1 -1
- {salabim-23.3.7 → salabim-23.3.8}/salabim/changelog.txt +60 -2
- {salabim-23.3.7 → salabim-23.3.8}/salabim/salabim.py +205 -90
- {salabim-23.3.7 → salabim-23.3.8}/salabim.egg-info/PKG-INFO +1 -1
- {salabim-23.3.7 → salabim-23.3.8}/setup.py +1 -1
- {salabim-23.3.7 → salabim-23.3.8}/MANIFEST.in +0 -0
- {salabim-23.3.7 → salabim-23.3.8}/README.rst +0 -0
- {salabim-23.3.7 → salabim-23.3.8}/salabim/DejaVuSansMono.ttf +0 -0
- {salabim-23.3.7 → salabim-23.3.8}/salabim/README.rst +0 -0
- {salabim-23.3.7 → salabim-23.3.8}/salabim/__init__.py +0 -0
- {salabim-23.3.7 → salabim-23.3.8}/salabim/calibri.ttf +0 -0
- {salabim-23.3.7 → salabim-23.3.8}/salabim/mplus-1m-regular.ttf +0 -0
- {salabim-23.3.7 → salabim-23.3.8}/salabim.egg-info/SOURCES.txt +0 -0
- {salabim-23.3.7 → salabim-23.3.8}/salabim.egg-info/dependency_links.txt +0 -0
- {salabim-23.3.7 → salabim-23.3.8}/salabim.egg-info/top_level.txt +0 -0
- {salabim-23.3.7 → salabim-23.3.8}/setup.cfg +0 -0
@@ -1,12 +1,70 @@
|
|
1
1
|
salabim changelog
|
2
2
|
|
3
|
-
version 23.3.
|
3
|
+
version 23.3.8 2023-09-05
|
4
|
+
==========================
|
5
|
+
Enhanced UI functionality (0)
|
6
|
+
-----------------------------
|
7
|
+
The UI window layout has been changed to be more useful with
|
8
|
+
narrower windows.
|
9
|
+
Some more updates to the appearance.
|
10
|
+
|
11
|
+
When the UI is started, the time in the animation window is no longer disabled.
|
12
|
+
The user can always switch that off with Environment.show_time(False).
|
13
|
+
|
14
|
+
Environment.start_ui() now has useful defaults for window_size and window_position.
|
15
|
+
|
16
|
+
Environment.start_ui() now has a parameter default_actions, which is True by default.
|
17
|
+
If False, there are no actions like, pause/go, speed, etc. defined, so the user has to
|
18
|
+
specify the required actions with the actions parameter.
|
19
|
+
This is useful to use a different layout or leave out certain elements. Be sure to
|
20
|
+
use the same keys to be able to use the programmed interactions. However, you
|
21
|
+
can leave out elements.
|
22
|
+
|
23
|
+
It is recommended to use the standard actions as a template:
|
24
|
+
|
25
|
+
[sg.Text("", key="-TIME-", metadata=[1, 2], size=200)],
|
26
|
+
[sg.Button("Pause", key="-PAUSE-GO-", metadata=[1, 2]), sg.Button("Stop", key="-STOP-", button_color=("white", "firebrick3"), metadata=[1, 2])],
|
27
|
+
[sg.Checkbox("Pause at each step", False, key="-PAUSE-AT-EACH-STEP-", enable_events=True, metadata=[1, 2])],
|
28
|
+
[sg.Text(f"Pause at{env.get_time_unit(template='(t)')}", key="-PAUSE-AT-TEXT-", size=17), sg.Input("", key="-PAUSE-AT-", size=(10, 20))],
|
29
|
+
[sg.Text(f"Pause each{env.get_time_unit(template='(d)')}", key="-PAUSE-EACH-TEXT-", size=17), sg.Input("", key="-PAUSE-EACH-", size=(10, 20))],
|
30
|
+
[
|
31
|
+
sg.Text("Speed", key="-SPEED-TEXT-", metadata=[1]),
|
32
|
+
sg.Button("/2", key="-SPEED/2-", metadata=[1]),
|
33
|
+
sg.Button("*2", key="-SPEED*2-", metadata=[1]),
|
34
|
+
sg.Input("", key="-SPEED-", size=(7, 10)),
|
35
|
+
],
|
36
|
+
[sg.Checkbox("Trace", env.trace(), key="-TRACE-", metadata=[1, 2], enable_events=True)],
|
37
|
+
[sg.Checkbox("Synced", env.synced(), key="-SYNCED-", metadata=[1], enable_events=True)],
|
38
|
+
[sg.Checkbox("Animate", True, key="-ANIMATE-", metadata=[1, 2], enable_events=True)],
|
39
|
+
|
40
|
+
|
41
|
+
The simulation did not stop exactly at the time given in 'Pause at'. Fixed.
|
42
|
+
|
43
|
+
Added demos (0)
|
44
|
+
---------------
|
45
|
+
The program demo_ui.py shows a pretty standard UI with some extra elements.
|
46
|
+
|
47
|
+
The program demo_horizontal_ui.py demonstrates the same functionality, but now
|
48
|
+
with a horizontal UI window. Note that this requires quite a bit more
|
49
|
+
code than the standard one.
|
50
|
+
But it demonstrates what is possible.
|
51
|
+
|
52
|
+
Bug fix (0)
|
53
|
+
-----------
|
54
|
+
Component.to_store_store did not always return the right store. Fixed.
|
55
|
+
Thanks to Florian Förster for reporting this bug and the fix.
|
56
|
+
|
57
|
+
Bug fix (1)
|
58
|
+
-----------
|
59
|
+
Store.to_store_requesters() returned the wrong queue. Fixed.
|
60
|
+
|
61
|
+
version 23.3.7 2023-08-22
|
4
62
|
==========================
|
5
63
|
Bug fix (0)
|
6
64
|
-----------
|
7
65
|
Environment.paused(True) did not call set_start_animation(), which is required. Fixed.
|
8
66
|
|
9
|
-
|
67
|
+
Bug fix (1)
|
10
68
|
-----------
|
11
69
|
Removing and showing an animated monitor did not restore the labels and label lines. Fixed.
|
12
70
|
|
@@ -1,13 +1,13 @@
|
|
1
|
-
# _ _ _ ____ _____ _____
|
2
|
-
# ___ __ _ | | __ _ | |__ (_) _ __ ___ |___ \ |___ / |___ /
|
3
|
-
# / __| / _` || | / _` || '_ \ | || '_ ` _ \ __) | |_ \ |_ \
|
4
|
-
# \__ \| (_| || || (_| || |_) || || | | | | | / __/ ___) | _ ___) | _
|
5
|
-
# |___/ \__,_||_| \__,_||_.__/ |_||_| |_| |_| |_____||____/ (_)|____/ (_) /
|
1
|
+
# _ _ _ ____ _____ _____ ___
|
2
|
+
# ___ __ _ | | __ _ | |__ (_) _ __ ___ |___ \ |___ / |___ / ( _ )
|
3
|
+
# / __| / _` || | / _` || '_ \ | || '_ ` _ \ __) | |_ \ |_ \ / _ \
|
4
|
+
# \__ \| (_| || || (_| || |_) || || | | | | | / __/ ___) | _ ___) | _ | (_) |
|
5
|
+
# |___/ \__,_||_| \__,_||_.__/ |_||_| |_| |_| |_____||____/ (_)|____/ (_) \___/
|
6
6
|
# Discrete event simulation in Python
|
7
7
|
#
|
8
8
|
# see www.salabim.org for more information, the documentation and license information
|
9
9
|
|
10
|
-
__version__ = "23.3.
|
10
|
+
__version__ = "23.3.8"
|
11
11
|
|
12
12
|
import heapq
|
13
13
|
import random
|
@@ -3923,11 +3923,10 @@ class AnimateMonitor(DynamicClass):
|
|
3923
3923
|
self.ao_now_line.remove()
|
3924
3924
|
for ao in self.ao_label_texts:
|
3925
3925
|
ao.remove()
|
3926
|
-
self.ao_label_texts=[]
|
3926
|
+
self.ao_label_texts = []
|
3927
3927
|
for ao in self.ao_label_lines:
|
3928
3928
|
ao.remove()
|
3929
|
-
self.ao_label_lines=[]
|
3930
|
-
|
3929
|
+
self.ao_label_lines = []
|
3931
3930
|
|
3932
3931
|
self.env.sys_objects.discard(self)
|
3933
3932
|
|
@@ -5627,7 +5626,7 @@ class Store(Queue):
|
|
5627
5626
|
-------
|
5628
5627
|
queue holding all from_store requesting components : Queue
|
5629
5628
|
"""
|
5630
|
-
return self.
|
5629
|
+
return self._to_store_requesters
|
5631
5630
|
|
5632
5631
|
def rescan(self):
|
5633
5632
|
"""
|
@@ -7099,7 +7098,7 @@ by adding at the end:
|
|
7099
7098
|
"""
|
7100
7099
|
size_x = 50
|
7101
7100
|
size_y = 50
|
7102
|
-
ao0 = AnimateRectangle(text=str(self.sequence_number()), textcolor="bg", spec=(-20, -20, 20, 20), linewidth=0, fillcolor="fg")
|
7101
|
+
ao0 = AnimateRectangle(text=str(self.sequence_number()), textcolor="bg", spec=(-20, -20, 20, 20), linewidth=0, fillcolor="fg")
|
7103
7102
|
return (size_x, size_y, ao0)
|
7104
7103
|
|
7105
7104
|
def animation3d_objects(self, id: Any) -> Tuple:
|
@@ -9421,7 +9420,7 @@ by adding:
|
|
9421
9420
|
requester.status._value = scheduled
|
9422
9421
|
requester._reschedule(requester.env._now, 0, False, f"to_store ({store.name()}) honor ", False, s0=requester.env.last_s0)
|
9423
9422
|
requester._to_store_item = None
|
9424
|
-
requester._to_store_store =
|
9423
|
+
requester._to_store_store = store
|
9425
9424
|
return self
|
9426
9425
|
|
9427
9426
|
def priority(self, q: "Queue", priority: float = None) -> float:
|
@@ -9698,7 +9697,7 @@ by adding:
|
|
9698
9697
|
if self.isdata():
|
9699
9698
|
return "N/A"
|
9700
9699
|
if self._process is None:
|
9701
|
-
s0 = ""
|
9700
|
+
s0 = ""
|
9702
9701
|
frame = _get_caller_frame()
|
9703
9702
|
lineno = inspect.getframeinfo(frame).lineno
|
9704
9703
|
s0 = rpad(str(lineno) + "+", 6)
|
@@ -23620,7 +23619,7 @@ class Environment:
|
|
23620
23619
|
if animate != self._animate:
|
23621
23620
|
frame_changed = True
|
23622
23621
|
self._animate = animate
|
23623
|
-
if self._ui:
|
23622
|
+
if self._ui and "-ANIMATE-" in self._ui_keys:
|
23624
23623
|
self._ui_window["-ANIMATE-"].update(animate)
|
23625
23624
|
|
23626
23625
|
self._scale = self._width / (self._x1 - self._x0)
|
@@ -23735,8 +23734,11 @@ class Environment:
|
|
23735
23734
|
g.animation_env._animate = self._animate
|
23736
23735
|
if not Pythonista:
|
23737
23736
|
if g.animation_env.root is not None: # for blind animation to work properly
|
23738
|
-
|
23739
|
-
|
23737
|
+
if self._ui:
|
23738
|
+
self.root.withdraw()
|
23739
|
+
else:
|
23740
|
+
g.animation_env.root.destroy()
|
23741
|
+
g.animation_env.root = None
|
23740
23742
|
g.animation_env = None
|
23741
23743
|
|
23742
23744
|
if self._blind_animation:
|
@@ -25054,8 +25056,9 @@ class Environment:
|
|
25054
25056
|
if not self.animate():
|
25055
25057
|
if value:
|
25056
25058
|
self.animate(True)
|
25057
|
-
self._paused = True
|
25058
|
-
|
25059
|
+
self._paused = True
|
25060
|
+
if "-ANIMATE-" in self._ui_keys:
|
25061
|
+
self.env._ui_window["-ANIMATE-"].update(False) # this is required as the self.animate() also sets the value
|
25059
25062
|
|
25060
25063
|
return self._paused
|
25061
25064
|
|
@@ -25556,7 +25559,6 @@ class Environment:
|
|
25556
25559
|
screen_coordinates=True,
|
25557
25560
|
xy_anchor="ne",
|
25558
25561
|
env=self,
|
25559
|
-
visible=lambda: not self._ui,
|
25560
25562
|
)
|
25561
25563
|
ao.text = self.clocktext
|
25562
25564
|
|
@@ -25640,7 +25642,6 @@ class Environment:
|
|
25640
25642
|
else:
|
25641
25643
|
fps = 0
|
25642
25644
|
s += f"fps={fps:.1f}"
|
25643
|
-
|
25644
25645
|
if self._show_time:
|
25645
25646
|
if s != "":
|
25646
25647
|
s += " "
|
@@ -26003,15 +26004,50 @@ class Environment:
|
|
26003
26004
|
"""
|
26004
26005
|
return self._sequence_number
|
26005
26006
|
|
26006
|
-
def get_time_unit(self) -> str:
|
26007
|
+
def get_time_unit(self, template: str = None) -> str:
|
26007
26008
|
"""
|
26008
26009
|
gets time unit
|
26009
26010
|
|
26011
|
+
Parameters
|
26012
|
+
----------
|
26013
|
+
template : str
|
26014
|
+
normally only used in UI functions
|
26015
|
+
|
26016
|
+
default: just return time_unit (including n/a)
|
26017
|
+
|
26018
|
+
if "d", time_unit as duration
|
26019
|
+
|
26020
|
+
if "t", time_unit as time
|
26021
|
+
|
26022
|
+
if "(d)", time_unit as (duration)
|
26023
|
+
|
26024
|
+
if "(t)", time_unit as (time)
|
26025
|
+
|
26026
|
+
Note that n/a is suppressed and an extra space is added at the front
|
26027
|
+
if result is not the null strinf
|
26028
|
+
|
26010
26029
|
Returns
|
26011
26030
|
-------
|
26012
26031
|
Current time unit dimension (default "n/a") : str
|
26013
26032
|
"""
|
26014
|
-
|
26033
|
+
if template is None:
|
26034
|
+
return self._time_unit_name
|
26035
|
+
if template not in "d t (d) (t)".split():
|
26036
|
+
raise ValueError
|
26037
|
+
|
26038
|
+
result = ""
|
26039
|
+
if "t" in template and self._datetime0:
|
26040
|
+
if "(" in template:
|
26041
|
+
result = "yyyy-mm-dd"
|
26042
|
+
else:
|
26043
|
+
if self._time_unit_name != "n/a":
|
26044
|
+
result = self._time_unit_name
|
26045
|
+
if result:
|
26046
|
+
if "(" in template:
|
26047
|
+
result = f" ({result})"
|
26048
|
+
else:
|
26049
|
+
result = f" {result}"
|
26050
|
+
return result
|
26015
26051
|
|
26016
26052
|
def years(self, t: float) -> float:
|
26017
26053
|
"""
|
@@ -26751,19 +26787,56 @@ class Environment:
|
|
26751
26787
|
def stop_ui(self):
|
26752
26788
|
if self._ui:
|
26753
26789
|
animate = self.animate()
|
26754
|
-
self.pauser.
|
26790
|
+
if not self.pauser.isdata():
|
26791
|
+
self.pauser.cancel()
|
26755
26792
|
self._ui = False
|
26756
26793
|
self._ui_window.close()
|
26757
26794
|
self.animate(animate)
|
26758
26795
|
self._ui = False
|
26759
26796
|
|
26760
|
-
def start_ui(
|
26797
|
+
def start_ui(
|
26798
|
+
self,
|
26799
|
+
window_size: Tuple = (None, None),
|
26800
|
+
window_position: Tuple = (None, None),
|
26801
|
+
elements: List = None,
|
26802
|
+
user_handle_event: Callable = None,
|
26803
|
+
default_elements: bool = True,
|
26804
|
+
actions: List = None,
|
26805
|
+
):
|
26806
|
+
"""
|
26807
|
+
start the PySimpleGUI UI
|
26808
|
+
|
26809
|
+
Parameters
|
26810
|
+
----------
|
26811
|
+
window_size : tuple
|
26812
|
+
width (int) ; default (None): 300
|
26813
|
+
|
26814
|
+
height (int) ; default (None): 600
|
26815
|
+
|
26816
|
+
window_position : tuple
|
26817
|
+
x (int) ; default (None): width of animation
|
26818
|
+
|
26819
|
+
y (int) ; default (None): 0
|
26820
|
+
|
26821
|
+
elements : list
|
26822
|
+
extra elements to add (refer to PySimpleGUI reference)
|
26823
|
+
|
26824
|
+
user_handle_event : callable
|
26825
|
+
default: no handler
|
26826
|
+
|
26827
|
+
default_elements : bool
|
26828
|
+
if True (default), UI will start with the standard elements
|
26829
|
+
|
26830
|
+
if False, no standard elements will be used. Use elements
|
26831
|
+
to add required standard elements
|
26832
|
+
"""
|
26761
26833
|
global sg
|
26762
26834
|
|
26763
26835
|
try:
|
26764
26836
|
import PySimpleGUI as sg
|
26765
26837
|
except ImportError:
|
26766
26838
|
raise ImportError("PySimpleGUI required for ui. Install with pip install PySimpleGUI")
|
26839
|
+
self.remove_topleft_buttons()
|
26767
26840
|
|
26768
26841
|
self.animation_parameters(use_toplevel=True)
|
26769
26842
|
self.pauser = _Pauser(at=inf)
|
@@ -26775,35 +26848,56 @@ class Environment:
|
|
26775
26848
|
else:
|
26776
26849
|
self.user_handle_event = user_handle_event
|
26777
26850
|
|
26778
|
-
|
26779
|
-
|
26780
|
-
|
26781
|
-
|
26782
|
-
sg.Checkbox("Pause at each step", False, key="-PAUSE-AT-EACH-STEP-", enable_events=True, metadata=[1, 2]),
|
26783
|
-
sg.Text("Pause at", key="-PAUSE-AT-TEXT-"),
|
26784
|
-
sg.Input("", key="-PAUSE-
|
26785
|
-
|
26786
|
-
|
26787
|
-
|
26788
|
-
|
26789
|
-
|
26790
|
-
|
26791
|
-
sg.
|
26792
|
-
sg.
|
26793
|
-
|
26794
|
-
|
26795
|
-
|
26796
|
-
|
26797
|
-
|
26851
|
+
if default_elements:
|
26852
|
+
frame0 = [
|
26853
|
+
[sg.Text("", key="-TIME-", metadata=[1, 2], size=200)],
|
26854
|
+
[sg.Button("Pause", key="-PAUSE-GO-", metadata=[1, 2]), sg.Button("Stop", key="-STOP-", button_color=("white", "firebrick3"), metadata=[1, 2])],
|
26855
|
+
[sg.Checkbox("Pause at each step", False, key="-PAUSE-AT-EACH-STEP-", enable_events=True, metadata=[1, 2])],
|
26856
|
+
[sg.Text(f"Pause at{self.get_time_unit(template='(t)')}", key="-PAUSE-AT-TEXT-", size=17), sg.Input("", key="-PAUSE-AT-", size=(10, 20))],
|
26857
|
+
[sg.Text(f"Pause each{self.get_time_unit(template='(d)')}", key="-PAUSE-EACH-TEXT-", size=17), sg.Input("", key="-PAUSE-EACH-", size=(10, 20))],
|
26858
|
+
[
|
26859
|
+
sg.Text("Speed", key="-SPEED-TEXT-", metadata=[1]),
|
26860
|
+
sg.Button("/2", key="-SPEED/2-", metadata=[1]),
|
26861
|
+
sg.Button("*2", key="-SPEED*2-", metadata=[1]),
|
26862
|
+
sg.Input("", key="-SPEED-", size=(7, 10)),
|
26863
|
+
],
|
26864
|
+
[sg.Checkbox("Trace", self.trace(), key="-TRACE-", metadata=[1, 2], enable_events=True)],
|
26865
|
+
[sg.Checkbox("Synced", self.synced(), key="-SYNCED-", metadata=[1], enable_events=True)],
|
26866
|
+
[sg.Checkbox("Animate", True, key="-ANIMATE-", metadata=[1, 2], enable_events=True)],
|
26867
|
+
]
|
26868
|
+
else:
|
26869
|
+
frame0 = []
|
26870
|
+
|
26871
|
+
if elements:
|
26872
|
+
if frame0:
|
26873
|
+
frame0.append([sg.HorizontalSeparator()])
|
26874
|
+
frame0.extend(elements)
|
26875
|
+
|
26798
26876
|
if actions:
|
26799
|
-
frame0
|
26877
|
+
if frame0:
|
26878
|
+
frame0.append([sg.HorizontalSeparator()])
|
26800
26879
|
frame0.extend(actions)
|
26801
|
-
|
26880
|
+
|
26881
|
+
layout = [[sg.Frame("", frame0, pad=((0, 0), (20, 0)))]]
|
26882
|
+
|
26883
|
+
window_size = list(window_size)
|
26884
|
+
if window_size[0] is None:
|
26885
|
+
window_size[0] = 300
|
26886
|
+
if window_size[1] is None:
|
26887
|
+
window_size[1] = self.height() + 33
|
26888
|
+
|
26889
|
+
window_position = list(window_position)
|
26890
|
+
|
26891
|
+
if window_position[0] is None:
|
26892
|
+
window_position[0] = self.width() + 10
|
26893
|
+
if window_position[1] is None:
|
26894
|
+
window_position[1] = 0
|
26802
26895
|
|
26803
26896
|
self._last_animate = "?"
|
26804
26897
|
self._last_paused = "?"
|
26805
|
-
self._ui_window = sg.Window("
|
26898
|
+
self._ui_window = sg.Window("", no_titlebar=True, layout=layout, size=window_size, location=window_position)
|
26806
26899
|
self._ui_window.finalize()
|
26900
|
+
self._ui_keys = {key.key for key in self._ui_window.element_list()}
|
26807
26901
|
|
26808
26902
|
self.pause_at = inf
|
26809
26903
|
self._pause_at_each_step = False
|
@@ -26813,7 +26907,8 @@ class Environment:
|
|
26813
26907
|
return self._ui_window
|
26814
26908
|
|
26815
26909
|
def set_pause_go_button(self):
|
26816
|
-
|
26910
|
+
if "-PAUSE-GO-" in self._ui_keys:
|
26911
|
+
self._ui_window["-PAUSE-GO-"].Update("Go" if self._paused else "Pause")
|
26817
26912
|
|
26818
26913
|
def _handle_ui_event(self):
|
26819
26914
|
if self._last_animate != self._animate or self._last_paused != self._paused:
|
@@ -26833,42 +26928,47 @@ class Environment:
|
|
26833
26928
|
|
26834
26929
|
event, values = self._ui_window.read(timeout=0)
|
26835
26930
|
|
26836
|
-
t = self.pauser.scheduled_time()
|
26837
|
-
s = [self.clocktext(self.t())]
|
26838
|
-
if t != inf and not self._paused:
|
26839
|
-
s.append(f" | Pause at {self.clocktext(t)}")
|
26840
|
-
if self.animate():
|
26841
|
-
s.append(f" | Speed={self.speed():.3f}")
|
26842
|
-
|
26843
26931
|
if values is None:
|
26844
26932
|
return
|
26845
26933
|
|
26846
|
-
if
|
26847
|
-
|
26934
|
+
if "-SPEED-" in self._ui_keys:
|
26935
|
+
if values["-SPEED-"] == "":
|
26936
|
+
self._ui_window["-SPEED-"].update(str(self.speed()))
|
26848
26937
|
|
26849
|
-
|
26938
|
+
if "-TIME-" in self._ui_keys:
|
26939
|
+
t = self.pauser.scheduled_time()
|
26940
|
+
s = [f"t={self.time_to_str(self.t()).lstrip()}{self.get_time_unit(template='t')}"]
|
26941
|
+
if t != inf and not self._paused:
|
26942
|
+
s.append(f" | Pause at {self.time_to_str(t).lstrip()}{self.get_time_unit(template='t')}")
|
26943
|
+
if self.animate():
|
26944
|
+
s.append(f" | Speed={self.speed():.3f}")
|
26945
|
+
|
26946
|
+
self._ui_window["-TIME-"].Update("".join(s))
|
26850
26947
|
|
26851
26948
|
if event in ("__TIMEOUT__", sg.WIN_CLOSED, "Exit"):
|
26852
26949
|
return
|
26853
26950
|
|
26854
26951
|
if event == "-STOP-":
|
26855
|
-
ch = sg.popup_yes_no(f"{chr(160):>50}",
|
26952
|
+
ch = sg.popup_yes_no(f"{chr(160):>50}", title="Stop?") # chr(160) is a non breaking blank, equivalent to "\0xA0")
|
26856
26953
|
if ch == "Yes":
|
26857
26954
|
sys.exit()
|
26858
26955
|
|
26859
26956
|
if event == "-PAUSE-GO-":
|
26860
|
-
if not self.animate():
|
26861
|
-
|
26862
|
-
|
26863
|
-
|
26864
|
-
|
26865
|
-
|
26957
|
+
# if not self.animate():
|
26958
|
+
# self.animate(True)
|
26959
|
+
# self.paused(False)
|
26960
|
+
# if "-ANIMATE-" in self._ui_keys:
|
26961
|
+
# self._ui_window["-ANIMATE-"].update(animate) # this is required as the self.animate() also sets the value
|
26962
|
+
|
26866
26963
|
self.set_start_animation()
|
26867
26964
|
if self._paused:
|
26868
|
-
|
26965
|
+
if "-PAUSE-AT-" in self._ui_keys:
|
26966
|
+
pause_at_str = values["-PAUSE-AT-"]
|
26967
|
+
else:
|
26968
|
+
pause_at_str = ""
|
26869
26969
|
if pause_at_str != "":
|
26870
26970
|
try:
|
26871
|
-
self.pause_at = self.spec_to_time(pause_at_str)
|
26971
|
+
self.pause_at = self.spec_to_time(pause_at_str)
|
26872
26972
|
except ValueError:
|
26873
26973
|
self.pause_at = None
|
26874
26974
|
else:
|
@@ -26877,7 +26977,10 @@ class Environment:
|
|
26877
26977
|
if self.pause_at is None:
|
26878
26978
|
sg.popup(f"Pause not valid")
|
26879
26979
|
else:
|
26880
|
-
|
26980
|
+
if "-PAUSE-EACH-" in self._ui_keys:
|
26981
|
+
pause_each_str = values["-PAUSE-EACH-"]
|
26982
|
+
else:
|
26983
|
+
pause_each_str = ""
|
26881
26984
|
if pause_each_str.strip() != "":
|
26882
26985
|
try:
|
26883
26986
|
pause_each = self.spec_to_duration(pause_each_str)
|
@@ -26891,46 +26994,54 @@ class Environment:
|
|
26891
26994
|
sg.popup(f"Pause interval not valid")
|
26892
26995
|
else:
|
26893
26996
|
if self.pause_at > self.t():
|
26894
|
-
|
26997
|
+
if "-ANIMATE-" in self._ui_keys:
|
26998
|
+
self.animate(values["-ANIMATE-"])
|
26895
26999
|
self.paused(False)
|
26896
27000
|
if self.pauser.scheduled_time() != self.pause_at:
|
26897
27001
|
self.pauser.activate(at=self.pause_at)
|
26898
27002
|
else:
|
26899
|
-
sg.popup(f"Pause at should be > {self.
|
27003
|
+
sg.popup(f"Pause at should be > {self.time_to_str(self.t()).lstrip()}")
|
26900
27004
|
else:
|
26901
27005
|
self.paused(True)
|
26902
27006
|
self._ui_window[event].Update("Pause")
|
26903
27007
|
|
26904
|
-
|
26905
|
-
|
26906
|
-
self.speed(
|
26907
|
-
|
27008
|
+
if "-SPEED-" in self._ui_keys:
|
27009
|
+
new_speed = float(values["-SPEED-"])
|
27010
|
+
if new_speed != self.speed():
|
27011
|
+
self.speed(new_speed)
|
27012
|
+
self.set_start_animation()
|
26908
27013
|
|
26909
27014
|
if event == "-SPEED*2-":
|
26910
27015
|
self.speed(self.speed() * 2)
|
26911
|
-
|
27016
|
+
if "-SPEED-" in self._ui_keys:
|
27017
|
+
self._ui_window["-SPEED-"].update(str(self.speed()))
|
26912
27018
|
self.set_start_animation()
|
26913
27019
|
|
26914
27020
|
if event == "-SPEED/2-":
|
26915
27021
|
self.speed(self.speed() / 2)
|
26916
|
-
|
27022
|
+
if "-SPEED-" in self._ui_keys:
|
27023
|
+
self._ui_window["-SPEED-"].update(str(self.speed()))
|
26917
27024
|
self.set_start_animation()
|
26918
27025
|
|
26919
27026
|
if event == "-SYNCED-":
|
26920
|
-
|
27027
|
+
if "-SYNCED-" in self._ui_keys:
|
27028
|
+
self.synced(values["-SYNCED-"])
|
26921
27029
|
|
26922
27030
|
if event == "-PAUSE-AT-EACH-STEP-":
|
26923
|
-
|
27031
|
+
if "-PAUSE-AT-EACH-STEP-" in self._ui_keys:
|
27032
|
+
self._pause_at_each_step = values["-PAUSE-AT-EACH-STEP-"]
|
26924
27033
|
|
26925
27034
|
if event == "-TRACE-":
|
26926
|
-
|
27035
|
+
if "-TRACE-" in self._ui_keys:
|
27036
|
+
self.trace(values["-TRACE-"])
|
26927
27037
|
|
26928
27038
|
if event == "-ANIMATE-":
|
26929
|
-
if
|
26930
|
-
|
26931
|
-
|
26932
|
-
|
26933
|
-
|
27039
|
+
if "-ANIMATE-" in self._ui_keys:
|
27040
|
+
if values["-ANIMATE-"]:
|
27041
|
+
self.animate(True)
|
27042
|
+
self.paused(True)
|
27043
|
+
else:
|
27044
|
+
_AnimateOff(urgent=True)
|
26934
27045
|
|
26935
27046
|
self.user_handle_event(env=self, window=self._ui_window, event=event, values=values)
|
26936
27047
|
|
@@ -26938,14 +27049,18 @@ class Environment:
|
|
26938
27049
|
class _Pauser(Component):
|
26939
27050
|
def process(self):
|
26940
27051
|
event, values = self.env._ui_window.read(timeout=0)
|
26941
|
-
|
27052
|
+
if "-ANIMATE-" in self.env._ui_keys:
|
27053
|
+
animate = values["-ANIMATE-"]
|
26942
27054
|
self.env.animation_start_time = self.env._now
|
27055
|
+
self.env._t = self.env._now
|
26943
27056
|
self.env.animate(True)
|
26944
27057
|
self.env.paused(True)
|
26945
27058
|
self.env.set_pause_go_button()
|
26946
|
-
if
|
26947
|
-
self.env.
|
26948
|
-
|
27059
|
+
if "-PAUSE-AT-" in self.env._ui_keys:
|
27060
|
+
if values["-PAUSE-AT-"] != "" and self.env._now >= self.env.spec_to_time(values["-PAUSE-AT-"]):
|
27061
|
+
self.env._ui_window["-PAUSE-AT-"].Update("")
|
27062
|
+
if "-ANIMATE-" in self.env._ui_keys:
|
27063
|
+
self.env._ui_window["-ANIMATE-"].update(animate) # this is required as the self.animate() also sets the value
|
26949
27064
|
|
26950
27065
|
|
26951
27066
|
class _AnimateOff(Component):
|
@@ -29826,7 +29941,7 @@ class AnimateQueue(DynamicClass):
|
|
29826
29941
|
dimx = _call(animation_objects[0], t, c)
|
29827
29942
|
dimy = _call(animation_objects[1], t, c)
|
29828
29943
|
for ao in animation_objects[2:]:
|
29829
|
-
ao.screen_coordinates = self.screen_coordinates
|
29944
|
+
ao.screen_coordinates = self.screen_coordinates
|
29830
29945
|
if isinstance(ao, AnimateClassic):
|
29831
29946
|
if direction == "t":
|
29832
29947
|
ao.x0 = xt + trajectory.x(t=x * 1.00, _t0=0)
|
@@ -29836,7 +29951,7 @@ class AnimateQueue(DynamicClass):
|
|
29836
29951
|
ao.y0 = y
|
29837
29952
|
else:
|
29838
29953
|
if direction == "t":
|
29839
|
-
ao.x = xt + trajectory.x(t=x * 1.00, _t0=0)
|
29954
|
+
ao.x = xt + trajectory.x(t=x * 1.00, _t0=0)
|
29840
29955
|
ao.y = yt + trajectory.y(t=x * 1.00, _t0=0)
|
29841
29956
|
ao.angle = trajectory.angle(t=x * 1.00, _t0=0)
|
29842
29957
|
else:
|
@@ -3,7 +3,7 @@ from setuptools import setup
|
|
3
3
|
setup(
|
4
4
|
name="salabim",
|
5
5
|
packages=["salabim"],
|
6
|
-
version="23.3.
|
6
|
+
version="23.3.8",
|
7
7
|
include_package_data=True,
|
8
8
|
long_description="salabim\n\nsalabim is a discrete event simulation package in Python\nwith builtin *animation*.",
|
9
9
|
description="discrete event simulation in Python",
|
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
|
File without changes
|
File without changes
|