v2sim 1.3.0__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.
- v2sim/__init__.py +21 -0
- v2sim/gui/cmpbox/__init__.py +152 -0
- v2sim/gui/cmpbox/_lang/en_US.lang +14 -0
- v2sim/gui/cmpbox/_lang/zh_CN.lang +14 -0
- v2sim/gui/com_no_vx.py +33 -0
- v2sim/gui/common.py +5 -0
- v2sim/gui/evtq.py +100 -0
- v2sim/gui/langhelper.py +34 -0
- v2sim/gui/mainbox/__init__.py +991 -0
- v2sim/gui/mainbox/_lang/en.lang +157 -0
- v2sim/gui/mainbox/_lang/zh_CN.lang +157 -0
- v2sim/gui/mainbox/controls/__init__.py +9 -0
- v2sim/gui/mainbox/controls/_lang/en.lang +34 -0
- v2sim/gui/mainbox/controls/_lang/zh_CN.lang +34 -0
- v2sim/gui/mainbox/controls/lipad.py +57 -0
- v2sim/gui/mainbox/controls/network.py +710 -0
- v2sim/gui/mainbox/controls/pdfe.py +65 -0
- v2sim/gui/mainbox/controls/prope.py +82 -0
- v2sim/gui/mainbox/controls/rle.py +82 -0
- v2sim/gui/mainbox/controls/scrtv.py +290 -0
- v2sim/gui/mainbox/controls/sfe.py +79 -0
- v2sim/gui/mainbox/controls/sid.py +48 -0
- v2sim/gui/mainbox/controls/utils.py +40 -0
- v2sim/gui/mainbox/cscsveditor.py +80 -0
- v2sim/gui/mainbox/cseditor.py +375 -0
- v2sim/gui/mainbox/loadingbox.py +33 -0
- v2sim/gui/mainbox/plugin.py +68 -0
- v2sim/gui/mainbox/utils.py +42 -0
- v2sim/gui/parabox/__init__.py +172 -0
- v2sim/gui/parabox/_lang/en.lang +51 -0
- v2sim/gui/parabox/_lang/zh_CN.lang +51 -0
- v2sim/gui/parabox/lgb.py +78 -0
- v2sim/gui/parabox/pareditor.py +53 -0
- v2sim/gui/parabox/utils.py +33 -0
- v2sim/gui/plgbox/__init__.py +150 -0
- v2sim/gui/plgbox/_lang/en_US.lang +19 -0
- v2sim/gui/plgbox/_lang/zh_CN.lang +19 -0
- v2sim/gui/progbox/__init__.py +45 -0
- v2sim/gui/v2sim.png +0 -0
- v2sim/gui/viewerbox/__init__.py +465 -0
- v2sim/gui/viewerbox/_lang/en_US.lang +95 -0
- v2sim/gui/viewerbox/_lang/zh_CN.lang +95 -0
- v2sim/gui/viewerbox/gridpage.py +89 -0
- v2sim/gui/viewerbox/optbox.py +46 -0
- v2sim/gui/viewerbox/plotpad.py +45 -0
- v2sim/gui/viewerbox/plotpage.py +225 -0
- v2sim/gui/viewerbox/srd.py +39 -0
- v2sim/gui/viewerbox/statepage.py +104 -0
- v2sim/gui/viewerbox/trips.py +284 -0
- v2sim/gui/welcomebox/__init__.py +225 -0
- v2sim/gui/welcomebox/_lang/en_US.lang +22 -0
- v2sim/gui/welcomebox/_lang/zh_CN.lang +22 -0
- v2sim/gui/welcomebox/v2sim.png +0 -0
- v2sim/locale/__init__.py +1 -0
- v2sim/locale/lang.py +264 -0
- v2sim/locale/zh_CN.py +207 -0
- v2sim/osmhelper/__init__.py +1 -0
- v2sim/osmhelper/osmBuild.py +140 -0
- v2sim/osmhelper/osmGet.py +324 -0
- v2sim/osmhelper/osmWebWizard.py +551 -0
- v2sim/osmhelper/ptlines2flows.py +610 -0
- v2sim/osmhelper/readme.md +2 -0
- v2sim/osmhelper/tileGet.py +283 -0
- v2sim/osmhelper/typemap/navteqPolyconvert.typ.xml +9 -0
- v2sim/osmhelper/typemap/opendriveNetconvert.typ.xml +35 -0
- v2sim/osmhelper/typemap/opendriveNetconvertBicycle.typ.xml +3 -0
- v2sim/osmhelper/typemap/opendriveNetconvertPedestrians.typ.xml +3 -0
- v2sim/osmhelper/typemap/osmNetconvert.typ.xml +45 -0
- v2sim/osmhelper/typemap/osmNetconvertAerialway.typ.xml +5 -0
- v2sim/osmhelper/typemap/osmNetconvertAirport.typ.xml +9 -0
- v2sim/osmhelper/typemap/osmNetconvertBicycle.typ.xml +6 -0
- v2sim/osmhelper/typemap/osmNetconvertBidiRail.typ.xml +7 -0
- v2sim/osmhelper/typemap/osmNetconvertExtraRail.typ.xml +5 -0
- v2sim/osmhelper/typemap/osmNetconvertPedestrians.typ.xml +10 -0
- v2sim/osmhelper/typemap/osmNetconvertPedestriansNES.typ.xml +11 -0
- v2sim/osmhelper/typemap/osmNetconvertRailUsage.typ.xml +17 -0
- v2sim/osmhelper/typemap/osmNetconvertShips.typ.xml +5 -0
- v2sim/osmhelper/typemap/osmNetconvertUrbanDe.typ.xml +13 -0
- v2sim/osmhelper/typemap/osmPolyconvert.typ.xml +66 -0
- v2sim/osmhelper/typemap/osmPolyconvertRail.typ.xml +50 -0
- v2sim/osmhelper/typemap/visumPolyconvert.typ.xml +8 -0
- v2sim/osmhelper/webWizard/SimpleWebSocketServer.py +716 -0
- v2sim/osmhelper/webWizard/__init__.py +17 -0
- v2sim/osmhelper/webWizard/images/bicycle.png +0 -0
- v2sim/osmhelper/webWizard/images/bus.png +0 -0
- v2sim/osmhelper/webWizard/images/favicon.ico +0 -0
- v2sim/osmhelper/webWizard/images/generate.png +0 -0
- v2sim/osmhelper/webWizard/images/map.png +0 -0
- v2sim/osmhelper/webWizard/images/motorcycle.png +0 -0
- v2sim/osmhelper/webWizard/images/passenger.png +0 -0
- v2sim/osmhelper/webWizard/images/pedestrian.png +0 -0
- v2sim/osmhelper/webWizard/images/rail.png +0 -0
- v2sim/osmhelper/webWizard/images/rail_urban.png +0 -0
- v2sim/osmhelper/webWizard/images/road.png +0 -0
- v2sim/osmhelper/webWizard/images/ship.png +0 -0
- v2sim/osmhelper/webWizard/images/tram.png +0 -0
- v2sim/osmhelper/webWizard/images/truck.png +0 -0
- v2sim/osmhelper/webWizard/index.html +138 -0
- v2sim/osmhelper/webWizard/jquery-3.5.1.min.js +2 -0
- v2sim/osmhelper/webWizard/lib.js +62 -0
- v2sim/osmhelper/webWizard/script.js +540 -0
- v2sim/osmhelper/webWizard/style.css +214 -0
- v2sim/plotkit/__init__.py +2 -0
- v2sim/plotkit/example.txt +16 -0
- v2sim/plotkit/plot.py +728 -0
- v2sim/plotkit/reader.py +251 -0
- v2sim/plugins/__init__.py +9 -0
- v2sim/plugins/base.py +278 -0
- v2sim/plugins/ocur.py +94 -0
- v2sim/plugins/pdn.py +182 -0
- v2sim/plugins/pool.py +158 -0
- v2sim/plugins/v2g.py +91 -0
- v2sim/probtable/duration_of_parking/H.csv +96 -0
- v2sim/probtable/duration_of_parking/H_spr.csv +96 -0
- v2sim/probtable/duration_of_parking/H_spr_weekday.csv +96 -0
- v2sim/probtable/duration_of_parking/H_spr_weekend.csv +96 -0
- v2sim/probtable/duration_of_parking/O_spr.csv +96 -0
- v2sim/probtable/duration_of_parking/O_spr_weekday.csv +96 -0
- v2sim/probtable/duration_of_parking/O_spr_weekend.csv +96 -0
- v2sim/probtable/duration_of_parking/R_spr.csv +96 -0
- v2sim/probtable/duration_of_parking/R_spr_weekday.csv +96 -0
- v2sim/probtable/duration_of_parking/R_spr_weekend.csv +96 -0
- v2sim/probtable/duration_of_parking/W_spr.csv +96 -0
- v2sim/probtable/duration_of_parking/W_spr_weekday.csv +96 -0
- v2sim/probtable/duration_of_parking/W_spr_weekend.csv +96 -0
- v2sim/probtable/ev_types.csv +7 -0
- v2sim/probtable/soc_dist.csv +101 -0
- v2sim/probtable/space_transfer_probability/H_spr_weekday.csv +5 -0
- v2sim/probtable/space_transfer_probability/H_spr_weekend.csv +5 -0
- v2sim/probtable/space_transfer_probability/O_spr_weekday.csv +5 -0
- v2sim/probtable/space_transfer_probability/O_spr_weekend.csv +5 -0
- v2sim/probtable/space_transfer_probability/R_spr_weekday.csv +5 -0
- v2sim/probtable/space_transfer_probability/R_spr_weekend.csv +5 -0
- v2sim/probtable/space_transfer_probability/W_spr_weekday.csv +5 -0
- v2sim/probtable/space_transfer_probability/W_spr_weekend.csv +5 -0
- v2sim/sim_core.py +744 -0
- v2sim/statistics/__init__.py +10 -0
- v2sim/statistics/base.py +81 -0
- v2sim/statistics/logcs.py +75 -0
- v2sim/statistics/logev.py +45 -0
- v2sim/statistics/loggr.py +174 -0
- v2sim/statistics/manager.py +210 -0
- v2sim/tools/cmd_advplot.py +24 -0
- v2sim/tools/cmd_csquery.py +24 -0
- v2sim/tools/cmd_gen_cs.py +27 -0
- v2sim/tools/cmd_gen_trip.py +29 -0
- v2sim/tools/cmd_plot.py +198 -0
- v2sim/tools/gui_cmp.py +6 -0
- v2sim/tools/gui_main.py +44 -0
- v2sim/tools/gui_osm.py +7 -0
- v2sim/tools/gui_para.py +5 -0
- v2sim/tools/gui_plgman.py +10 -0
- v2sim/tools/gui_viewer.py +5 -0
- v2sim/tools/sim_para.py +278 -0
- v2sim/tools/sim_single.py +122 -0
- v2sim/traffic/__init__.py +9 -0
- v2sim/traffic/cs.py +672 -0
- v2sim/traffic/cslist.py +336 -0
- v2sim/traffic/ev.py +460 -0
- v2sim/traffic/evdict.py +85 -0
- v2sim/traffic/inst.py +712 -0
- v2sim/traffic/net.py +390 -0
- v2sim/traffic/params.py +81 -0
- v2sim/traffic/seg.py +231 -0
- v2sim/traffic/trip.py +435 -0
- v2sim/traffic/utils.py +345 -0
- v2sim/traffic/win_vis.py +1 -0
- v2sim/trafficgen/__init__.py +9 -0
- v2sim/trafficgen/core.py +508 -0
- v2sim/trafficgen/csquery.py +213 -0
- v2sim/trafficgen/misc.py +214 -0
- v2sim/trafficgen/poly.py +67 -0
- v2sim/trafficgen/tripgen.py +440 -0
- v2sim-1.3.0.dist-info/METADATA +73 -0
- v2sim-1.3.0.dist-info/RECORD +178 -0
- v2sim-1.3.0.dist-info/WHEEL +4 -0
- v2sim-1.3.0.dist-info/entry_points.txt +11 -0
- v2sim-1.3.0.dist-info/licenses/LICENSE +29 -0
v2sim/__init__.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .locale import *
|
|
2
|
+
from .traffic import *
|
|
3
|
+
from .trafficgen import *
|
|
4
|
+
from .plotkit import *
|
|
5
|
+
from .plugins import *
|
|
6
|
+
from .statistics import *
|
|
7
|
+
from .sim_core import (
|
|
8
|
+
load_external_components,
|
|
9
|
+
get_sim_params,
|
|
10
|
+
simulate_multi,
|
|
11
|
+
simulate_single,
|
|
12
|
+
V2SimInstance,
|
|
13
|
+
MsgPack,
|
|
14
|
+
PLUGINS_FILE,
|
|
15
|
+
RESULTS_FOLDER,
|
|
16
|
+
TRIP_EVENT_LOG,
|
|
17
|
+
SIM_INFO_LOG,
|
|
18
|
+
PLUGINS_DIR,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__version__ = "1.3.0"
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
from v2sim.gui.com_no_vx import *
|
|
2
|
+
from v2sim.gui.langhelper import *
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
from PIL import Image, ImageTk
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
_ = LangLib.Load(__file__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CmpBox(Tk):
|
|
12
|
+
def __init__(self):
|
|
13
|
+
super().__init__()
|
|
14
|
+
|
|
15
|
+
self.title(_("TITLE"))
|
|
16
|
+
self.geometry("1024x768")
|
|
17
|
+
self.bind("<Configure>", self.on_resize)
|
|
18
|
+
|
|
19
|
+
self.folder1 = None
|
|
20
|
+
self.folder2 = None
|
|
21
|
+
self.original_image1 = None
|
|
22
|
+
self.original_image2 = None
|
|
23
|
+
self.folder_buf = "./results"
|
|
24
|
+
|
|
25
|
+
self.create_widgets()
|
|
26
|
+
|
|
27
|
+
def create_widgets(self):
|
|
28
|
+
self.menu = Menu(self)
|
|
29
|
+
self.config(menu=self.menu)
|
|
30
|
+
self.filemenu = Menu(self.menu, tearoff=0)
|
|
31
|
+
self.filemenu.add_command(label=_("OPEN_FOLDER1"), command=self.open_folder1)
|
|
32
|
+
self.filemenu.add_command(label=_("OPEN_FOLDER2"), command=self.open_folder2)
|
|
33
|
+
self.filemenu.add_separator()
|
|
34
|
+
self.filemenu.add_command(label=_("EXIT"), command=self.destroy)
|
|
35
|
+
self.menu.add_cascade(label=_("FILE"), menu=self.filemenu)
|
|
36
|
+
add_lang_menu(self.menu)
|
|
37
|
+
|
|
38
|
+
self.sidebar = Frame(self)
|
|
39
|
+
self.sidebar.pack(side=LEFT, fill=Y)
|
|
40
|
+
|
|
41
|
+
self.folder1_button = Button(self.sidebar, text=_("OPEN_FOLDER1"), command=self.open_folder1)
|
|
42
|
+
self.folder1_button.pack(pady=10)
|
|
43
|
+
|
|
44
|
+
self.folder2_button = Button(self.sidebar, text=_("OPEN_FOLDER2"), command=self.open_folder2)
|
|
45
|
+
self.folder2_button.pack(pady=10)
|
|
46
|
+
|
|
47
|
+
self.folder1_label = Label(self.sidebar, text=_("LB_FOLDER1").format(_("TO_BE_SELECTED")))
|
|
48
|
+
self.folder1_label.pack(pady=10)
|
|
49
|
+
|
|
50
|
+
self.folder2_label = Label(self.sidebar, text=_("LB_FOLDER2").format(_("TO_BE_SELECTED")))
|
|
51
|
+
self.folder2_label.pack(pady=10)
|
|
52
|
+
|
|
53
|
+
self.file_listbox = Listbox(self.sidebar)
|
|
54
|
+
self.file_listbox.pack(fill=BOTH, expand=True, pady=10)
|
|
55
|
+
self.file_listbox.bind("<<ListboxSelect>>", self.on_file_select)
|
|
56
|
+
|
|
57
|
+
self.image_frame = Frame(self)
|
|
58
|
+
self.image_frame.pack(side=RIGHT, fill=X, expand=True)
|
|
59
|
+
|
|
60
|
+
self.image1_label = Label(self.image_frame)
|
|
61
|
+
self.image1_label.pack(side=TOP, padx=10, pady=10)
|
|
62
|
+
|
|
63
|
+
self.image2_label = Label(self.image_frame)
|
|
64
|
+
self.image2_label.pack(side=TOP, padx=10, pady=10)
|
|
65
|
+
|
|
66
|
+
def open_folder1(self):
|
|
67
|
+
new_folder = filedialog.askdirectory(initialdir=self.folder_buf, title=_("AD_TITLE1"))
|
|
68
|
+
if new_folder:
|
|
69
|
+
folder_fig = os.path.join(new_folder, "figures")
|
|
70
|
+
if os.path.exists(folder_fig):
|
|
71
|
+
self.folder1 = folder_fig
|
|
72
|
+
self.folder1_label.config(text=_("LB_FOLDER1").format(os.path.basename(new_folder)))
|
|
73
|
+
self.update_file_list()
|
|
74
|
+
self.folder_buf = str(Path(new_folder).parent)
|
|
75
|
+
else:
|
|
76
|
+
MB.showerror(_("ERROR"), _("NO_FIG"))
|
|
77
|
+
|
|
78
|
+
def open_folder2(self):
|
|
79
|
+
new_folder = filedialog.askdirectory(initialdir=self.folder_buf, title=_("AD_TITLE2"))
|
|
80
|
+
if new_folder:
|
|
81
|
+
folder_fig = os.path.join(new_folder, "figures")
|
|
82
|
+
if os.path.exists(folder_fig):
|
|
83
|
+
self.folder2 = folder_fig
|
|
84
|
+
self.folder2_label.config(text=_("LB_FOLDER2").format(os.path.basename(new_folder)))
|
|
85
|
+
self.update_file_list()
|
|
86
|
+
self.folder_buf = str(Path(new_folder).parent)
|
|
87
|
+
else:
|
|
88
|
+
MB.showerror(_("ERROR"), _("NO_FIG"))
|
|
89
|
+
|
|
90
|
+
def update_file_list(self):
|
|
91
|
+
self.file_listbox.delete(0, END)
|
|
92
|
+
if self.folder1 and self.folder2:
|
|
93
|
+
files1 = set(os.listdir(self.folder1))
|
|
94
|
+
files2 = set(os.listdir(self.folder2))
|
|
95
|
+
common_files = files1.union(files2)
|
|
96
|
+
for file in sorted(common_files):
|
|
97
|
+
if file.lower().endswith(('png', 'jpg', 'jpeg', 'gif')): # 只列出图片文件
|
|
98
|
+
self.file_listbox.insert(END, file)
|
|
99
|
+
|
|
100
|
+
def on_file_select(self, event):
|
|
101
|
+
selected_index = self.file_listbox.curselection()
|
|
102
|
+
if selected_index:
|
|
103
|
+
file_name = self.file_listbox.get(selected_index)
|
|
104
|
+
self.display_images(file_name)
|
|
105
|
+
|
|
106
|
+
def resize(self):
|
|
107
|
+
sz = (self.winfo_width() - 200, self.winfo_height() // 2 - 20)
|
|
108
|
+
if self.original_image1 is not None:
|
|
109
|
+
resized_image1 = self.original_image1.copy()
|
|
110
|
+
resized_image1.thumbnail(sz)
|
|
111
|
+
image1 = ImageTk.PhotoImage(resized_image1)
|
|
112
|
+
|
|
113
|
+
self.image1_label.config(image=image1,text="")
|
|
114
|
+
self.image1 = image1
|
|
115
|
+
else:
|
|
116
|
+
self.image1_label.config(image='',text=_("NO_IMAGE"))
|
|
117
|
+
self.image1 = None
|
|
118
|
+
|
|
119
|
+
if self.original_image2 is not None:
|
|
120
|
+
resized_image2 = self.original_image2.copy()
|
|
121
|
+
resized_image2.thumbnail(sz)
|
|
122
|
+
image2 = ImageTk.PhotoImage(resized_image2)
|
|
123
|
+
|
|
124
|
+
self.image2_label.config(image=image2,text="")
|
|
125
|
+
self.image2 = image2
|
|
126
|
+
else:
|
|
127
|
+
self.image2_label.config(image='',text=_("NO_IMAGE"))
|
|
128
|
+
self.image2 = None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def on_resize(self, event):
|
|
132
|
+
self.resize()
|
|
133
|
+
|
|
134
|
+
def display_images(self, file_name:str):
|
|
135
|
+
if self.folder1 is None: return
|
|
136
|
+
img1_path = os.path.join(self.folder1, file_name)
|
|
137
|
+
if self.folder2 is None: return
|
|
138
|
+
img2_path = os.path.join(self.folder2, file_name)
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
if os.path.exists(img1_path):
|
|
142
|
+
self.original_image1 = Image.open(img1_path)
|
|
143
|
+
else:
|
|
144
|
+
self.original_image1 = None
|
|
145
|
+
if os.path.exists(img2_path):
|
|
146
|
+
self.original_image2 = Image.open(img2_path)
|
|
147
|
+
else:
|
|
148
|
+
self.original_image2 = None
|
|
149
|
+
except Exception as e:
|
|
150
|
+
MB.showerror(_("ERROR"), _("LOAD_FAILED").format(str(e)))
|
|
151
|
+
|
|
152
|
+
self.resize()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
TITLE=Case comparer
|
|
2
|
+
ERROR=Error
|
|
3
|
+
OPEN_FOLDER1=Open folder 1
|
|
4
|
+
OPEN_FOLDER2=Open folder 2
|
|
5
|
+
TO_BE_SELECTED=(To be selected)
|
|
6
|
+
LB_FOLDER1=Folder 1: {}
|
|
7
|
+
LB_FOLDER2=Folder 2: {}
|
|
8
|
+
AD_TITLE1=Select folder 1
|
|
9
|
+
AD_TITLE2=Select folder 2
|
|
10
|
+
NO_FIG=No 'figures' folder in the selected folder! Please plot the data with gui_viewer.py first!
|
|
11
|
+
LOAD_FAILED=Cannot load image: {}
|
|
12
|
+
NO_IMAGE=(No image)
|
|
13
|
+
EXIT=Exit
|
|
14
|
+
FILE=File
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
TITLE=案例比较器
|
|
2
|
+
ERROR=错误
|
|
3
|
+
OPEN_FOLDER1=打开文件夹1
|
|
4
|
+
OPEN_FOLDER2=打开文件夹2
|
|
5
|
+
TO_BE_SELECTED=未选择
|
|
6
|
+
LB_FOLDER1=文件夹1: {}
|
|
7
|
+
LB_FOLDER2=文件夹2: {}
|
|
8
|
+
AD_TITLE1=选择文件夹1
|
|
9
|
+
AD_TITLE2=选择文件夹2
|
|
10
|
+
NO_FIG=所选文件夹中没有figures文件夹! 请先使用gui_viewer.py画图!
|
|
11
|
+
LOAD_FAILED=无法加载图片: {}
|
|
12
|
+
NO_IMAGE=无图像
|
|
13
|
+
EXIT=退出
|
|
14
|
+
FILE=文件
|
v2sim/gui/com_no_vx.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Load Path
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
# Load Event Queue
|
|
5
|
+
from .evtq import EventQueue
|
|
6
|
+
|
|
7
|
+
# Load Language Library
|
|
8
|
+
from feasytools import LangLib, LangConfig
|
|
9
|
+
LangConfig.SetAppName("v2sim")
|
|
10
|
+
|
|
11
|
+
# High DPI awareness for Windows
|
|
12
|
+
import platform
|
|
13
|
+
if platform.system() == "Windows":
|
|
14
|
+
import ctypes
|
|
15
|
+
ctypes.windll.shcore.SetProcessDpiAwareness(1)
|
|
16
|
+
|
|
17
|
+
# Load Tk controls
|
|
18
|
+
from tkinter import (
|
|
19
|
+
Toplevel, messagebox as MB, BooleanVar, StringVar, IntVar, Canvas, Event, Tk, Menu, filedialog, Text, Listbox, PhotoImage, Widget,
|
|
20
|
+
NO, YES, NORMAL, DISABLED, END, BOTH, X, Y, LEFT, RIGHT, TOP, BOTTOM, W, E
|
|
21
|
+
)
|
|
22
|
+
from tkinter.ttk import Treeview, Button, LabelFrame, Checkbutton, Combobox, Frame, Label, Entry, Spinbox, Scrollbar, Radiobutton, Notebook, OptionMenu
|
|
23
|
+
|
|
24
|
+
# Load Type Hints
|
|
25
|
+
from typing import Dict, List, Set, Tuple, Any, Union, Optional, Iterable, Callable, Literal
|
|
26
|
+
|
|
27
|
+
# Set exports
|
|
28
|
+
__all__ = [
|
|
29
|
+
"LangLib", "LangConfig", "EventQueue", "Path", "Dict", "List", "Set", "Tuple", "Any", "Union", "Optional", "Iterable", "Callable", "Literal",
|
|
30
|
+
"Toplevel", "MB", "BooleanVar", "StringVar", "IntVar", "Canvas", "Event", "Tk", "Menu", "filedialog", "Text", "Listbox", "PhotoImage", "Widget",
|
|
31
|
+
"NO", "YES", "NORMAL", "DISABLED", "END", "X", "Y", "BOTH", "LEFT", "RIGHT", "TOP", "BOTTOM", "W", "E", "platform",
|
|
32
|
+
"Treeview", "Button", "LabelFrame", "Checkbutton", "Combobox", "Frame", "Label", "Entry", "Spinbox", "Scrollbar", "Radiobutton", "Notebook", "OptionMenu",
|
|
33
|
+
]
|
v2sim/gui/common.py
ADDED
v2sim/gui/evtq.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
import time
|
|
3
|
+
import traceback
|
|
4
|
+
from collections import deque
|
|
5
|
+
from queue import Queue
|
|
6
|
+
from typing import Callable, Dict, Tuple
|
|
7
|
+
|
|
8
|
+
class EventQueue:
|
|
9
|
+
def __init__(self, parent, maxsize:int = 0, interval_ms:int = 100, max_proc_ms:int = 90):
|
|
10
|
+
self._Q = Queue(maxsize)
|
|
11
|
+
self._parent = parent
|
|
12
|
+
self._evt:Dict[str, Callable] = {}
|
|
13
|
+
self._interval_ms = interval_ms
|
|
14
|
+
self._max_proc_ns = max_proc_ms * 1e6 # Convert to nanoseconds
|
|
15
|
+
self._delegates:deque[Tuple[Callable, Tuple, Dict]] = deque()
|
|
16
|
+
self.do() # Start processing events immediately
|
|
17
|
+
|
|
18
|
+
def do(self):
|
|
19
|
+
"""Process all events in the queue."""
|
|
20
|
+
prod_next = True
|
|
21
|
+
st = time.time_ns()
|
|
22
|
+
|
|
23
|
+
cnt = 0
|
|
24
|
+
while self._delegates:
|
|
25
|
+
func, args, kwargs = self._delegates.popleft()
|
|
26
|
+
try:
|
|
27
|
+
func(*args, **kwargs)
|
|
28
|
+
except Exception as e:
|
|
29
|
+
print(f"Error in delegate function '{func.__name__}': {e}")
|
|
30
|
+
|
|
31
|
+
cnt = 0
|
|
32
|
+
while not self._Q.empty() and (time.time_ns() - st < self._max_proc_ns) and cnt < 100:
|
|
33
|
+
name, args, kwargs = self._Q.get()
|
|
34
|
+
if name == "__quit__":
|
|
35
|
+
self._Q.task_done()
|
|
36
|
+
prod_next = False
|
|
37
|
+
break
|
|
38
|
+
if name in self._evt and self._evt[name] is not None:
|
|
39
|
+
try:
|
|
40
|
+
self._evt[name](*args, **kwargs)
|
|
41
|
+
except Exception as e:
|
|
42
|
+
traceback.print_exc()
|
|
43
|
+
print(f"Error processing event '{name}': {e}")
|
|
44
|
+
else:
|
|
45
|
+
print(f"Event '{name}' is not registered.")
|
|
46
|
+
self._Q.task_done()
|
|
47
|
+
self._parent.update() # Ensure the GUI updates after processing each event
|
|
48
|
+
cnt += 1
|
|
49
|
+
if prod_next:
|
|
50
|
+
intv = self._interval_ms
|
|
51
|
+
if cnt >= 100:
|
|
52
|
+
intv = max(intv // 10, 1)
|
|
53
|
+
self._parent.after(intv, self.do)
|
|
54
|
+
|
|
55
|
+
def register(self, name:str, callback:Callable):
|
|
56
|
+
"""Register an event handler for a specific event name."""
|
|
57
|
+
if name in self._evt:
|
|
58
|
+
raise ValueError(f"Event '{name}' is already registered.")
|
|
59
|
+
self._evt[name] = callback
|
|
60
|
+
|
|
61
|
+
def setcallback(self, name:str, callback:Callable):
|
|
62
|
+
"""Set or update the callback for an event."""
|
|
63
|
+
if name not in self._evt:
|
|
64
|
+
raise ValueError(f"Event '{name}' is not registered.")
|
|
65
|
+
self._evt[name] = callback
|
|
66
|
+
|
|
67
|
+
def trigger(self, name:str, *args, **kwargs):
|
|
68
|
+
"""Trigger an event by its name with optional arguments."""
|
|
69
|
+
if name not in self._evt:
|
|
70
|
+
raise ValueError(f"Event '{name}' is not registered.")
|
|
71
|
+
self._Q.put((name, args, kwargs))
|
|
72
|
+
|
|
73
|
+
def submit(self, name:str, func:Callable, *args, **kwargs):
|
|
74
|
+
"""Run a function asychoronously and submit the results to trigger an event."""
|
|
75
|
+
def _run_and_trigger(name, func, *args, **kwargs):
|
|
76
|
+
try:
|
|
77
|
+
result = func(*args, **kwargs)
|
|
78
|
+
if result is None:
|
|
79
|
+
result = ()
|
|
80
|
+
elif not isinstance(result, tuple):
|
|
81
|
+
result = (result,)
|
|
82
|
+
self.trigger(name, *result)
|
|
83
|
+
except Exception as e:
|
|
84
|
+
traceback.print_exc()
|
|
85
|
+
print(f"Error in submitting function '{func.__name__}' for event '{name}': {e}")
|
|
86
|
+
threading.Thread(target=_run_and_trigger, args=(name, func, *args), kwargs=kwargs).start()
|
|
87
|
+
|
|
88
|
+
def asyncrun(self, func:Callable, *args, **kwargs):
|
|
89
|
+
"""Run a no-return function asynchronously"""
|
|
90
|
+
def _run(func, *args, **kwargs):
|
|
91
|
+
try:
|
|
92
|
+
func(*args, **kwargs)
|
|
93
|
+
except Exception as e:
|
|
94
|
+
traceback.print_exc()
|
|
95
|
+
print(f"Error in delegating function '{func.__name__}': {e}")
|
|
96
|
+
threading.Thread(target=_run, args=(func, *args), kwargs=kwargs).start()
|
|
97
|
+
|
|
98
|
+
def delegate(self, func:Callable, *args, **kwargs):
|
|
99
|
+
"""Run a no-return function on the main thread."""
|
|
100
|
+
self._delegates.append((func, args, kwargs))
|
v2sim/gui/langhelper.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from v2sim.gui.com_no_vx import *
|
|
2
|
+
|
|
3
|
+
_ = LangLib(["zh_CN", "en_US"])
|
|
4
|
+
_.SetLangLib("zh_CN",
|
|
5
|
+
MB_INFO = "信息",
|
|
6
|
+
MENU_LANG = "语言",
|
|
7
|
+
MENU_LANG_AUTO = "(自动检测)",
|
|
8
|
+
LANG_RESTART = "语言已更改,请重启程序以应用更改。",
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
_.SetLangLib("en_US",
|
|
12
|
+
MB_INFO = "Information",
|
|
13
|
+
MENU_LANG = "Language",
|
|
14
|
+
MENU_LANG_AUTO = "(Auto Detect)",
|
|
15
|
+
LANG_RESTART = "Language has been changed. Please restart the application to apply the changes.",
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
def setLang(lang_code:str):
|
|
19
|
+
title = _["MB_INFO"]
|
|
20
|
+
info = _["LANG_RESTART"]
|
|
21
|
+
def _f():
|
|
22
|
+
nonlocal lang_code, title, info
|
|
23
|
+
LangConfig.SetLangCode(lang_code)
|
|
24
|
+
MB.showinfo(title, info)
|
|
25
|
+
return _f
|
|
26
|
+
|
|
27
|
+
def add_lang_menu(parent: Menu):
|
|
28
|
+
menuLang = Menu(parent, tearoff=False)
|
|
29
|
+
parent.add_cascade(label=_["MENU_LANG"], menu=menuLang)
|
|
30
|
+
menuLang.add_command(label=_["MENU_LANG_AUTO"], command=setLang("<auto>"))
|
|
31
|
+
menuLang.add_command(label="English (United States)", command=setLang("en_US"))
|
|
32
|
+
menuLang.add_command(label="中文 (简体)", command=setLang("zh_CN"))
|
|
33
|
+
|
|
34
|
+
__all__ = ["add_lang_menu"]
|