-
Notifications
You must be signed in to change notification settings - Fork 29
/
ms2_tool_gui.py
153 lines (131 loc) · 5.2 KB
/
ms2_tool_gui.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import time
import logging
from gui import widgets, startup, GuiOptions # Import widgets before everything except built-ins!
from generated.formats.ms2 import Ms2File
from generated.formats.ms2.versions import games
from typing import Optional
from PyQt5 import QtWidgets
class MainWindow(widgets.MainWindow):
def __init__(self, opts: GuiOptions):
widgets.MainWindow.__init__(self, "MS2 Editor", opts=opts)
self.resize(600, 600)
self.setAcceptDrops(True)
self.ms2_file = Ms2File()
self.filter = "Supported files (*ms2)"
self.file_widget = self.make_file_widget(ftype="MS2")
header_names = ["Name", "File Type", "LODs", "Objects", "Meshes", "Materials"]
self.game_choice = widgets.LabelCombo("Game", [g.value for g in games], editable=False,
changed_fn=self.game_changed)
# create the table
self.files_container = widgets.SortableTable(header_names, (), ignore_drop_type="MS2")
# connect the interaction functions
self.files_container.table.table_model.member_renamed.connect(self.rename_handle)
self.files_container.table.hideColumn(1)
# Configure table button row
self.btn_duplicate = widgets.SelectedItemsButton(self, icon=widgets.get_icon("duplicate_mesh"))
self.btn_duplicate.clicked.connect(self.duplicate)
self.btn_duplicate.setToolTip("Duplicate Selected Meshes")
self.btn_delete = widgets.SelectedItemsButton(self, icon=widgets.get_icon("delete_mesh"))
self.btn_delete.clicked.connect(self.remove)
self.btn_delete.setToolTip("Delete Selected Meshes")
# Add buttons to table
self.files_container.add_button(self.btn_duplicate)
self.files_container.add_button(self.btn_delete)
self.qgrid = QtWidgets.QGridLayout()
self.qgrid.addWidget(self.file_widget, 0, 0)
self.qgrid.addWidget(self.game_choice, 1, 0)
self.qgrid.addWidget(self.files_container, 2, 0)
self.qgrid.addWidget(self.progress, 3, 0)
self.central_widget.setLayout(self.qgrid)
self.add_to_menu(
*self.file_menu_functions,
(widgets.EDIT_MENU, "Append", self.append, "", "append"),
(widgets.EDIT_MENU, "Duplicate Selected", self.duplicate, "SHIFT+D", "duplicate_mesh"),
(widgets.EDIT_MENU, "Remove Selected", self.remove, "DEL", "delete_mesh"),
*self.help_menu_functions,
)
def game_changed(self, game: Optional[str] = None):
if game is None:
game = self.game_choice.entry.currentText()
logging.info(f"Setting MS2 version to {game}")
self.ms2_file.game = game
def rename_handle(self, old_name, new_name):
"""this manages the renaming of a single entry"""
# force new name to be lowercase
new_name = new_name.lower()
try:
if self.ms2_file.name_used(new_name):
self.showwarning(f"Model {new_name} already exists in ms2!")
# new name is new
else:
self.ms2_file.rename_file(old_name, new_name)
self.set_file_modified(True)
except:
self.handle_error("Renaming failed, see log!")
self.update_gui_table()
def remove(self):
selected_file_names = self.files_container.table.get_selected_files()
if selected_file_names:
try:
self.ms2_file.remove(selected_file_names)
self.set_file_modified(True)
except:
self.handle_error("Removing file failed, see log!")
self.update_gui_table()
def duplicate(self):
selected_file_names = self.files_container.table.get_selected_files()
if selected_file_names:
try:
self.ms2_file.duplicate(selected_file_names)
self.set_file_modified(True)
except:
self.handle_error("Duplicating file failed, see log!")
self.update_gui_table()
def open(self, filepath):
if filepath:
self.set_file_modified(False)
try:
self.ms2_file.load(filepath, read_editable=True, dump=True)
# print(self.ms2_file)
# for model_info in self.ms2_file.model_infos:
# # model_info.
# model = model_info.model
# print(model)
# break
except:
self.handle_error("Loading failed, see log!")
self.update_gui_table()
def append(self):
if self.file_widget.is_open():
append_path = self.file_widget.get_open_file_name(f'Append MS2')
if append_path:
try:
other_ms2_file = Ms2File()
other_ms2_file.load(append_path, read_editable=True)
# ensure that there are no name collisions
for model in other_ms2_file.model_infos:
self.ms2_file.make_name_unique(model)
self.ms2_file.model_infos.append(model)
self.set_file_modified(True)
except:
self.handle_error("Appending failed, see log!")
self.update_gui_table()
def update_gui_table(self, ):
start_time = time.time()
try:
logging.info(f"Loading {len(self.ms2_file.mdl_2_names)} files into GUI")
self.files_container.set_data([[m.name, ".mdl2", m.num_lods, m.num_objects, m.num_meshes, m.num_materials] for m in self.ms2_file.model_infos])
self.game_choice.entry.setText(self.ms2_file.game)
logging.info(f"Loaded GUI in {time.time() - start_time:.2f} seconds")
self.set_progress_message("Operation completed!")
except:
self.handle_error("GUI update failed, see log!")
def save(self, filepath) -> None:
try:
self.ms2_file.save(filepath)
self.set_file_modified(False)
self.set_progress_message(f"Saved {self.ms2_file.name}")
except:
self.handle_error("Saving MS2 failed, see log!")
if __name__ == '__main__':
startup(MainWindow, GuiOptions(log_name="ms2_tool_gui"))