pyscreeps-arena 0.5.9b6__tar.gz → 0.5.9.2__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.
Files changed (61) hide show
  1. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/PKG-INFO +1 -1
  2. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/compiler.py +2 -1
  3. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/core/const.py +1 -1
  4. pyscreeps_arena-0.5.9.2/pyscreeps_arena/project.7z +0 -0
  5. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/project_ui.py +1 -1
  6. pyscreeps_arena-0.5.9.2/pyscreeps_arena/ui/qprefabs/__init__.py +0 -0
  7. pyscreeps_arena-0.5.9.2/pyscreeps_arena/ui/qprefabs/model.py +87 -0
  8. pyscreeps_arena-0.5.9.2/pyscreeps_arena/ui/qprefabs/qprefabs.py +536 -0
  9. pyscreeps_arena-0.5.9.2/pyscreeps_arena/ui/qprefabs/test.py +53 -0
  10. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena.egg-info/PKG-INFO +1 -1
  11. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena.egg-info/SOURCES.txt +4 -0
  12. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/setup.py +1 -1
  13. pyscreeps_arena-0.5.9b6/pyscreeps_arena/project.7z +0 -0
  14. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/__init__.py +0 -0
  15. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/afters/__init__.py +0 -0
  16. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/afters/after_config.py +0 -0
  17. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/afters/after_custom.py +0 -0
  18. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/afters/after_empty.py +0 -0
  19. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/afters/after_prefab.py +0 -0
  20. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/build.py +0 -0
  21. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/core/__init__.py +0 -0
  22. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/core/basic.py +0 -0
  23. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/core/config.py +0 -0
  24. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/core/core.py +0 -0
  25. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/core/main.py +0 -0
  26. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/core/utils.py +0 -0
  27. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/localization.py +0 -0
  28. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/P2PY.py +0 -0
  29. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/__init__.py +0 -0
  30. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/creeplogic_edit.py +0 -0
  31. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/map_render.py +0 -0
  32. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/mapviewer.py +0 -0
  33. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qcreeplogic/__init__.py +0 -0
  34. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qcreeplogic/model.py +0 -0
  35. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qcreeplogic/qcreeplogic.py +0 -0
  36. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapker/__init__.py +0 -0
  37. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapker/qmapmarker.py +0 -0
  38. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapker/qvariable.py +0 -0
  39. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapker/test_compact_variable.py +0 -0
  40. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapker/test_qmapmarker.py +0 -0
  41. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapker/test_qvariable.py +0 -0
  42. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapker/to_code.py +0 -0
  43. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapv/__init__.py +0 -0
  44. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapv/qcinfo.py +0 -0
  45. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapv/qco.py +0 -0
  46. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapv/qmapv.py +0 -0
  47. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapv/test_array_drag.py +0 -0
  48. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapv/test_drag.py +0 -0
  49. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapv/test_qcinfo.py +0 -0
  50. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapv/test_qco_drag.py +0 -0
  51. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapv/test_qmapv.py +0 -0
  52. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qmapv/test_simple_array.py +0 -0
  53. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qrecipe/__init__.py +0 -0
  54. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qrecipe/model.py +0 -0
  55. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/qrecipe/qrecipe.py +0 -0
  56. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena/ui/rs_icon.py +0 -0
  57. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena.egg-info/dependency_links.txt +0 -0
  58. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena.egg-info/entry_points.txt +0 -0
  59. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena.egg-info/requires.txt +0 -0
  60. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/pyscreeps_arena.egg-info/top_level.txt +0 -0
  61. {pyscreeps_arena-0.5.9b6 → pyscreeps_arena-0.5.9.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyscreeps-arena
3
- Version: 0.5.9b6
3
+ Version: 0.5.9.2
4
4
  Summary: Python api|interface to play game: Screeps: Arena.
5
5
  Author-email: 2229066748@qq.com
6
6
  Maintainer: Eagle'sBaby
@@ -4,6 +4,7 @@ from pyscreeps_arena.core import *
4
4
  from pyscreeps_arena.localization import *
5
5
 
6
6
  import re
7
+ import sys
7
8
  import shutil
8
9
  import chardet
9
10
  import subprocess
@@ -1173,7 +1174,7 @@ class Compiler(CompilerBase):
1173
1174
  def transcrypt_cmd(self):
1174
1175
  # 执行cmd命令: python -m transcrypt -b -m -n -s -e 6 target | execute cmd: python -m transcrypt -b -m -n -s -e 6 target
1175
1176
  # 并获取cmd得到的输出 | and get the output of the cmd
1176
- cmd = 'python -m transcrypt -b -m -n -s -e 6 %s' % self.target_py
1177
+ cmd = f'{sys.executable} -m transcrypt -b -m -n -s -e 6 {self.target_py}'
1177
1178
  core.lprint(WAIT, core.lformat(LOC_TRANSCRYPTING, [cmd]), end="", ln=config.language)
1178
1179
  p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
1179
1180
  stdout, stderr = p.communicate()
@@ -9,7 +9,7 @@
9
9
  #
10
10
  import re
11
11
 
12
- VERSION = "0.5.9b"
12
+ VERSION = "0.5.9.2"
13
13
  AUTHOR = "●ω<🤍♪"
14
14
  STEAM_ID = "1029562896"
15
15
  GITHUB_NAME = "EagleBaby"
@@ -864,7 +864,7 @@ class ProjectCreatorUI(QMainWindow):
864
864
 
865
865
  def _init_ui(self):
866
866
  """Initialize main window"""
867
- self.setWindowTitle("PyScreeps Arena - 项目创建器")
867
+ self.setWindowTitle("PyScreeps Arena - Project Wizard")
868
868
  self.setWindowIcon(QIcon(get_pixmap()))
869
869
 
870
870
  # Create central widget
@@ -0,0 +1,87 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Prefabs model for scanning and loading prefab directories
4
+ """
5
+ import os
6
+ import json
7
+
8
+
9
+ def scan_prefabs(root_path, progress_callback=None):
10
+ """
11
+ Scan the given root path for prefab directories and return a dictionary of prefab information.
12
+
13
+ Args:
14
+ root_path: The root directory to scan for prefab directories
15
+ progress_callback: Optional callback function to report progress
16
+ Signature: progress_callback(current, total)
17
+
18
+ Returns:
19
+ dict: A dictionary where keys are full paths to prefab directories,
20
+ and values are dictionaries with prefab information
21
+ """
22
+ prefabs = {}
23
+
24
+ if not os.path.exists(root_path):
25
+ return prefabs
26
+
27
+ # First, get the total number of directories to scan for progress calculation
28
+ total_dirs = 0
29
+ for _, dirs, _ in os.walk(root_path):
30
+ total_dirs += len(dirs) + 1 # +1 for current directory
31
+
32
+ # Walk through the directory tree with progress
33
+ current_dir = 0
34
+ for root, dirs, files in os.walk(root_path):
35
+ current_dir += 1
36
+
37
+ # Update progress if callback is provided
38
+ if progress_callback:
39
+ progress_callback(current_dir, total_dirs)
40
+
41
+ # Check if this directory contains a prefab.json file
42
+ if 'prefab.json' in files:
43
+ # This is a prefab directory, don't continue walking into it
44
+ prefab_path = root
45
+ prefab_name = os.path.basename(prefab_path)
46
+
47
+ # Initialize default values
48
+ prefab_info = {
49
+ 'name': prefab_name,
50
+ 'desc_cn': '',
51
+ 'desc_en': '',
52
+ 'version': '',
53
+ 'author': ''
54
+ }
55
+
56
+ # Try to read the prefab.json file
57
+ prefab_json_path = os.path.join(prefab_path, 'prefab.json')
58
+ try:
59
+ with open(prefab_json_path, 'r', encoding='utf-8') as f:
60
+ data = json.load(f)
61
+ # Update with values from the file if they exist
62
+ if 'author' in data:
63
+ prefab_info['author'] = data['author']
64
+ if 'desc_en' in data:
65
+ prefab_info['desc_en'] = data['desc_en']
66
+ if 'desc_cn' in data:
67
+ prefab_info['desc_cn'] = data['desc_cn']
68
+ if 'version' in data:
69
+ prefab_info['version'] = data['version']
70
+ except Exception:
71
+ # If reading fails, keep the default values
72
+ pass
73
+
74
+ # Add rels field for tree structure
75
+ rel_path = os.path.relpath(prefab_path, root_path)
76
+ path_parts = rel_path.split(os.path.sep)
77
+ # Remove the last part which is the prefab directory itself
78
+ rels = path_parts[:-1] if len(path_parts) > 1 else []
79
+ prefab_info['rels'] = rels
80
+
81
+ # Add to the result dictionary
82
+ prefabs[prefab_path] = prefab_info
83
+
84
+ # Remove this directory from dirs so os.walk doesn't continue into it
85
+ dirs[:] = [d for d in dirs if d != os.path.basename(root)]
86
+
87
+ return prefabs
@@ -0,0 +1,536 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Prefabs manager UI widget
4
+ """
5
+ import os
6
+ import json
7
+ from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
8
+ QPushButton, QFileDialog, QTreeView, QHeaderView, QProgressBar)
9
+ from PyQt6.QtGui import QStandardItemModel, QStandardItem
10
+ from PyQt6.QtCore import Qt, pyqtSignal, pyqtProperty
11
+ from PyQt6.QtGui import QFont, QCursor
12
+
13
+ from pyscreeps_arena.ui.qprefabs.model import scan_prefabs
14
+
15
+
16
+ # Language mapping
17
+ LANG = {
18
+ 'cn': {
19
+ 'custom_prefabs': 'Custom Prefabs',
20
+ 'prefab_library_path': 'Prefab-Lib Path',
21
+ 'browse': 'Browse...',
22
+ 'select_library_path': 'Select Prefab-Lib Path',
23
+ },
24
+ 'en': {
25
+ 'custom_prefabs': 'Custom Prefabs',
26
+ 'prefab_library_path': 'Prefab Library Path',
27
+ 'browse': 'Browse...',
28
+ 'select_library_path': 'Select Prefab Library Path',
29
+ }
30
+ }
31
+
32
+
33
+ class QPrefabsManager(QWidget):
34
+ """
35
+ Prefabs manager widget for managing custom prefabs
36
+ """
37
+
38
+ # Signals
39
+ libraryPathChanged = pyqtSignal(str)
40
+ selectionChanged = pyqtSignal(list)
41
+
42
+ def __init__(self, parent=None):
43
+ super().__init__(parent)
44
+ self._library_path = ""
45
+ self._selected_prefabs = []
46
+ self._current_language = "cn"
47
+ self._init_ui()
48
+ self._load_settings()
49
+
50
+ def lang(self, key):
51
+ """
52
+ Get translation for the current language
53
+
54
+ Args:
55
+ key: The language key to translate
56
+
57
+ Returns:
58
+ str: The translated string
59
+ """
60
+ return LANG.get(self._current_language, LANG['cn']).get(key, key)
61
+
62
+ def _get_settings_path(self):
63
+ """
64
+ Get cross-platform settings file path
65
+
66
+ Returns:
67
+ str: The path to the settings file
68
+ """
69
+ # Get user's home directory
70
+ home_dir = os.path.expanduser("~")
71
+
72
+ # Create settings directory if it doesn't exist
73
+ settings_dir = os.path.join(home_dir, ".psaui")
74
+ os.makedirs(settings_dir, exist_ok=True)
75
+
76
+ # Return settings file path
77
+ return os.path.join(settings_dir, ".prefab.json")
78
+
79
+ def _save_settings(self):
80
+ """
81
+ Save settings to .prefab.json
82
+ """
83
+ settings = {
84
+ "library_path": self._library_path,
85
+ "selected_prefabs": self._selected_prefabs
86
+ }
87
+
88
+ try:
89
+ settings_path = self._get_settings_path()
90
+ with open(settings_path, 'w', encoding='utf-8') as f:
91
+ json.dump(settings, f, indent=2, ensure_ascii=False)
92
+ except Exception as e:
93
+ print(f"Error saving settings: {e}")
94
+
95
+ def _load_settings(self):
96
+ """
97
+ Load settings from .prefab.json if it exists
98
+ """
99
+ try:
100
+ settings_path = self._get_settings_path()
101
+ if os.path.exists(settings_path):
102
+ with open(settings_path, 'r', encoding='utf-8') as f:
103
+ settings = json.load(f)
104
+
105
+ # Load library path
106
+ if "library_path" in settings:
107
+ self._library_path = settings["library_path"]
108
+ self._path_input.setText(self._library_path)
109
+ self._update_prefabs_tree()
110
+
111
+ # Load selected prefabs
112
+ if "selected_prefabs" in settings:
113
+ self._selected_prefabs = settings["selected_prefabs"]
114
+ self._update_tree_selection()
115
+ except Exception as e:
116
+ print(f"Error loading settings: {e}")
117
+
118
+ def _init_ui(self):
119
+ """
120
+ Initialize the UI
121
+ """
122
+ # Main layout
123
+ layout = QVBoxLayout(self)
124
+ layout.setSpacing(10)
125
+ layout.setContentsMargins(10, 10, 10, 10)
126
+
127
+ # First row: Title label
128
+ title_layout = QHBoxLayout()
129
+ self._title_label = QLabel(self.lang('custom_prefabs'))
130
+ title_font = QFont()
131
+ title_font.setPointSize(12)
132
+ title_font.setBold(True)
133
+ self._title_label.setFont(title_font)
134
+ title_layout.addWidget(self._title_label)
135
+ title_layout.addStretch()
136
+ layout.addLayout(title_layout)
137
+
138
+ # Second row: Path selection
139
+ path_layout = QHBoxLayout()
140
+ self._path_label = QLabel(self.lang('prefab_library_path'))
141
+ self._path_label.setFixedWidth(100)
142
+ self._path_input = QLineEdit()
143
+ self._path_input.setReadOnly(True)
144
+ self._browse_btn = QPushButton(self.lang('browse'))
145
+ self._browse_btn.setFixedWidth(80)
146
+ self._browse_btn.clicked.connect(self._browse_path)
147
+
148
+ path_layout.addWidget(self._path_label)
149
+ path_layout.addWidget(self._path_input)
150
+ path_layout.addWidget(self._browse_btn)
151
+ layout.addLayout(path_layout)
152
+
153
+ # Third row: Progress bar (hidden by default)
154
+ self._progress_bar = QProgressBar()
155
+ self._progress_bar.setMinimum(0)
156
+ self._progress_bar.setMaximum(100)
157
+ self._progress_bar.setValue(0)
158
+ self._progress_bar.setVisible(False) # Hide by default
159
+ layout.addWidget(self._progress_bar)
160
+
161
+ # Fourth row: Tree view for prefabs
162
+ self._prefabs_model = QStandardItemModel()
163
+ self._prefabs_model.setHorizontalHeaderLabels(['Name', 'Version', 'Author', 'Description'])
164
+
165
+ self._prefabs_tree = QTreeView()
166
+ self._prefabs_tree.setModel(self._prefabs_model)
167
+ # Allow resizing columns
168
+ self._prefabs_tree.header().setSectionResizeMode(QHeaderView.ResizeMode.Interactive)
169
+ # Set initial column widths - make NAME column wider
170
+ self._prefabs_tree.setColumnWidth(0, 200) # NAME column
171
+ self._prefabs_tree.setColumnWidth(1, 100) # VERSION column
172
+ self._prefabs_tree.setColumnWidth(2, 100) # AUTHOR column
173
+ self._prefabs_tree.setColumnWidth(3, 200) # DESCRIPTION column
174
+ self._prefabs_tree.setSelectionMode(QTreeView.SelectionMode.NoSelection)
175
+ # Connect to model item changed signal
176
+ self._prefabs_model.itemChanged.connect(self._on_item_changed)
177
+ layout.addWidget(self._prefabs_tree)
178
+
179
+ def _browse_path(self):
180
+ """
181
+ Handle browse button click to select library path
182
+ """
183
+ current_path = self._path_input.text() or os.path.expanduser("~")
184
+ path = QFileDialog.getExistingDirectory(
185
+ self, self.lang('select_library_path'), current_path
186
+ )
187
+ if path:
188
+ self._library_path = path
189
+ self._path_input.setText(self._library_path)
190
+ self._update_prefabs_tree()
191
+ self._save_settings()
192
+ self.libraryPathChanged.emit(self._library_path)
193
+
194
+ def _update_prefabs_tree(self):
195
+ """
196
+ Update the prefabs tree based on the current library path
197
+ """
198
+ # Clear existing model
199
+ self._prefabs_model.clear()
200
+ self._prefabs_model.setHorizontalHeaderLabels(['Name', 'Version', 'Author', 'Description'])
201
+
202
+ # Show progress bar
203
+ self._progress_bar.setVisible(True)
204
+ self._progress_bar.setValue(0)
205
+
206
+ # Progress callback function
207
+ def progress_callback(current, total):
208
+ # Calculate percentage
209
+ percentage = int((current / total) * 100)
210
+ self._progress_bar.setValue(percentage)
211
+
212
+ # Scan for prefabs with progress
213
+ prefabs = scan_prefabs(self._library_path, progress_callback=progress_callback)
214
+
215
+ # Create tree structure
216
+ if prefabs:
217
+ # Dictionary to store directory items for quick lookup
218
+ directory_items = {}
219
+
220
+ for prefab_path, prefab_info in prefabs.items():
221
+ # Use rels field from prefab_info for tree structure
222
+ path_parts = prefab_info.get('rels', [])
223
+ prefab_name = prefab_info['name']
224
+
225
+ # Create directory structure in model
226
+ current_parent = self._prefabs_model.invisibleRootItem()
227
+ current_path = []
228
+
229
+ # Create parent directory nodes
230
+ for part in path_parts:
231
+ current_path.append(part)
232
+ path_key = '/'.join(current_path)
233
+
234
+ if path_key not in directory_items:
235
+ # Create new directory item - NO checkbox
236
+ dir_item = QStandardItem(part)
237
+ # Set ONLY the basic flags - no checkable flag
238
+ dir_item.setFlags(Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable)
239
+ # Create empty items for other columns
240
+ empty_items = [QStandardItem('') for _ in range(3)]
241
+ # Add all columns to parent
242
+ current_parent.appendRow([dir_item] + empty_items)
243
+ # Store reference
244
+ directory_items[path_key] = dir_item
245
+
246
+ # Move to next level
247
+ current_parent = directory_items[path_key]
248
+
249
+ # Create leaf node (prefab) - WITH checkbox
250
+ name_item = QStandardItem(prefab_name)
251
+ # Set checkable flag for leaf nodes
252
+ name_item.setFlags(Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsUserCheckable)
253
+ name_item.setCheckState(Qt.CheckState.Unchecked)
254
+ # Store prefab path as user data
255
+ name_item.setData(prefab_path, Qt.ItemDataRole.UserRole)
256
+ # Set tooltip with description based on current language
257
+ description = prefab_info['desc_cn'] if self._current_language == 'cn' else prefab_info['desc_en']
258
+ name_item.setToolTip(description)
259
+
260
+ # Create other columns
261
+ version_item = QStandardItem(prefab_info['version'])
262
+ author_item = QStandardItem(prefab_info['author'])
263
+ description = prefab_info['desc_cn'] if self._current_language == 'cn' else prefab_info['desc_en']
264
+ desc_item = QStandardItem(description)
265
+
266
+ # Add all items to parent
267
+ current_parent.appendRow([name_item, version_item, author_item, desc_item])
268
+
269
+ # Update selection
270
+ self._update_tree_selection()
271
+
272
+ # Set column widths after model is populated
273
+ # Make NAME column wider
274
+ self._prefabs_tree.setColumnWidth(0, 200) # NAME column - increased to 300 for better visibility
275
+ self._prefabs_tree.setColumnWidth(1, 100) # VERSION column
276
+ self._prefabs_tree.setColumnWidth(2, 100) # AUTHOR column
277
+ self._prefabs_tree.setColumnWidth(3, 200) # DESCRIPTION column
278
+
279
+ # Hide progress bar after scan is complete
280
+ self._progress_bar.setVisible(False)
281
+
282
+ def _find_item_by_path(self, part, parent_item):
283
+ """
284
+ Find a tree item by path part
285
+
286
+ Args:
287
+ part: The path part to find
288
+ parent_item: The parent item to search in, or None for root
289
+
290
+ Returns:
291
+ QTreeWidgetItem: The found item, or None if not found
292
+ """
293
+ if parent_item is None:
294
+ # Search in root items
295
+ for i in range(self._prefabs_tree.topLevelItemCount()):
296
+ item = self._prefabs_tree.topLevelItem(i)
297
+ if item.text(0) == part:
298
+ return item
299
+ else:
300
+ # Search in child items
301
+ for i in range(parent_item.childCount()):
302
+ item = parent_item.child(i)
303
+ if item.text(0) == part:
304
+ return item
305
+
306
+ return None
307
+
308
+ def _update_tree_selection(self):
309
+ """
310
+ Update the model selection based on saved selected prefabs
311
+ """
312
+ # Clear existing selection
313
+ def clear_selection(item):
314
+ for row in range(item.rowCount()):
315
+ child_item = item.child(row, 0) # Get first column item
316
+ if child_item:
317
+ # Check if this is a leaf node with user data
318
+ prefab_path = child_item.data(Qt.ItemDataRole.UserRole)
319
+ if prefab_path:
320
+ # This is a prefab item, uncheck it
321
+ child_item.setCheckState(Qt.CheckState.Unchecked)
322
+ else:
323
+ # This is a directory item, recurse
324
+ clear_selection(child_item)
325
+
326
+ # Start from root item
327
+ root_item = self._prefabs_model.invisibleRootItem()
328
+ clear_selection(root_item)
329
+
330
+ # Select saved prefabs
331
+ def select_item(item, prefab_path):
332
+ for row in range(item.rowCount()):
333
+ child_item = item.child(row, 0) # Get first column item
334
+ if child_item:
335
+ # Check if this is a leaf node with user data
336
+ item_path = child_item.data(Qt.ItemDataRole.UserRole)
337
+ if item_path == prefab_path:
338
+ # This is the prefab we're looking for, check it
339
+ child_item.setCheckState(Qt.CheckState.Checked)
340
+ return True
341
+ elif not item_path:
342
+ # This is a directory item, recurse
343
+ if select_item(child_item, prefab_path):
344
+ return True
345
+ return False
346
+
347
+ for prefab_path in self._selected_prefabs:
348
+ select_item(root_item, prefab_path)
349
+
350
+ # Removed _clear_tree_selection and _select_item_by_path methods
351
+ # They're no longer needed with the new QStandardItemModel approach
352
+
353
+ def _on_item_changed(self, item):
354
+ """
355
+ Handle model item change (checkbox state change)
356
+
357
+ Args:
358
+ item: The changed item
359
+ """
360
+ # Check if this is a leaf node (prefab) with user data
361
+ if item.data(Qt.ItemDataRole.UserRole):
362
+ # Update selected prefabs list
363
+ self._update_selected_prefabs()
364
+
365
+ # Removed _propagate_check_state and _update_parent_states methods
366
+ # They're no longer needed with the new QStandardItemModel approach
367
+
368
+ def _update_selected_prefabs(self):
369
+ """
370
+ Update the selected prefabs list based on model selection
371
+ """
372
+ self._selected_prefabs = []
373
+
374
+ def collect_selected(item):
375
+ for row in range(item.rowCount()):
376
+ child_item = item.child(row, 0) # Get first column item
377
+ if child_item:
378
+ # Check if this is a leaf node with user data
379
+ prefab_path = child_item.data(Qt.ItemDataRole.UserRole)
380
+ if prefab_path:
381
+ # This is a prefab item, check if it's selected
382
+ if child_item.checkState() == Qt.CheckState.Checked:
383
+ self._selected_prefabs.append(prefab_path)
384
+ else:
385
+ # This is a directory item, recurse
386
+ collect_selected(child_item)
387
+
388
+ # Start from root item
389
+ root_item = self._prefabs_model.invisibleRootItem()
390
+ collect_selected(root_item)
391
+
392
+ # Save settings
393
+ self._save_settings()
394
+ self.selectionChanged.emit(self._selected_prefabs)
395
+
396
+ def set_language(self, language):
397
+ """
398
+ Set the language for the widget
399
+
400
+ Args:
401
+ language: The language code ('cn' or 'en')
402
+ """
403
+ if language in LANG:
404
+ self._current_language = language
405
+
406
+ # Update UI elements
407
+ self._title_label.setText(self.lang('custom_prefabs'))
408
+ self._path_label.setText(self.lang('prefab_library_path'))
409
+ self._browse_btn.setText(self.lang('browse'))
410
+
411
+ # Update tooltips
412
+ def update_tooltips(item):
413
+ if item.childCount() > 0:
414
+ for i in range(item.childCount()):
415
+ update_tooltips(item.child(i))
416
+ else:
417
+ # Only update leaf nodes
418
+ prefab_path = item.data(0, Qt.ItemDataRole.UserRole)
419
+ if prefab_path:
420
+ prefabs = scan_prefabs(self._library_path)
421
+ if prefab_path in prefabs:
422
+ prefab_info = prefabs[prefab_path]
423
+ tooltip = prefab_info['desc_cn'] if self._current_language == 'cn' else prefab_info['desc_en']
424
+ item.setData(0, Qt.ItemDataRole.ToolTipRole, tooltip)
425
+
426
+ for i in range(self._prefabs_tree.topLevelItemCount()):
427
+ update_tooltips(self._prefabs_tree.topLevelItem(i))
428
+
429
+ # Properties
430
+ @pyqtProperty(str, constant=False)
431
+ def libraryPath(self) -> str:
432
+ """
433
+ Get the prefab library path
434
+
435
+ Returns:
436
+ str: The current library path
437
+ """
438
+ return self._library_path
439
+
440
+ @libraryPath.setter
441
+ def libraryPath(self, value: str):
442
+ """
443
+ Set the prefab library path
444
+
445
+ Args:
446
+ value: The new library path
447
+ """
448
+ if value != self._library_path:
449
+ self._library_path = value
450
+ self._path_input.setText(self._library_path)
451
+ self._update_prefabs_tree()
452
+ self._save_settings()
453
+ self.libraryPathChanged.emit(self._library_path)
454
+
455
+ @pyqtProperty(list, constant=False)
456
+ def selectedPrefabs(self) -> list:
457
+ """
458
+ Get the list of selected prefab paths
459
+
460
+ Returns:
461
+ list: The list of selected prefab paths
462
+ """
463
+ return self._selected_prefabs
464
+
465
+ def list_to_dict(self, paths: list[str]) -> dict[str, str]:
466
+ """
467
+ Convert a list of paths to a dictionary where keys are unique directory names
468
+ and values are the full paths. Handles duplicate directory names by
469
+ prepending parent directory names until uniqueness is achieved.
470
+
471
+ Args:
472
+ paths: List of prefab paths
473
+
474
+ Returns:
475
+ dict: Dictionary mapping unique directory names to full paths
476
+ """
477
+ result = {}
478
+
479
+ for path in paths:
480
+ # Get relative path from library root
481
+ rel_path = os.path.relpath(path, self._library_path)
482
+ # Split relative path into parts
483
+ rel_parts = rel_path.split(os.path.sep)
484
+
485
+ k = 1
486
+ while True:
487
+ # Generate candidate name by taking last k parts of relative path
488
+ if k >= len(rel_parts):
489
+ candidate_parts = rel_parts
490
+ else:
491
+ candidate_parts = rel_parts[-k:]
492
+ candidate_name = '_'.join(candidate_parts)
493
+
494
+ # Check if name is unique
495
+ if candidate_name not in result:
496
+ result[candidate_name] = path
497
+ break
498
+ else:
499
+ # If not unique, try with more parts
500
+ k += 1
501
+
502
+ return result
503
+
504
+ # Signals
505
+ libraryPathChanged = pyqtSignal(str)
506
+ selectionChanged = pyqtSignal(list)
507
+
508
+
509
+ if __name__ == '__main__':
510
+ import sys
511
+ from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
512
+
513
+ app = QApplication(sys.argv)
514
+ window = QPrefabsManager()
515
+
516
+ # Connect to the selectionChanged signal to print selections
517
+ def print_selections(selected):
518
+ print(f"Selected prefabs: {selected}")
519
+
520
+ window.selectionChanged.connect(print_selections)
521
+
522
+ window.show()
523
+
524
+ # Run the application
525
+ exit_code = app.exec()
526
+
527
+ # Print final selections when application exits
528
+ selected = window.selectedPrefabs
529
+ print(f"Final selected prefabs: {selected}")
530
+
531
+ # Convert to dict and print
532
+ if selected:
533
+ converted = window.list_to_dict(selected)
534
+ print(f"Converted to dict: {converted}")
535
+
536
+ sys.exit(exit_code)
@@ -0,0 +1,53 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Test script for QPrefabsManager
4
+ """
5
+ import sys
6
+ import os
7
+
8
+ # Add the parent directory to Python path
9
+ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
10
+
11
+ from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
12
+ from ui.qprefabs.qprefabs import QPrefabsManager
13
+
14
+
15
+ class TestWindow(QMainWindow):
16
+ """Test window for QPrefabsManager"""
17
+
18
+ def __init__(self):
19
+ super().__init__()
20
+ self.setWindowTitle("QPrefabsManager Test")
21
+ self.setGeometry(100, 100, 600, 400)
22
+
23
+ # Create central widget
24
+ central_widget = QWidget()
25
+ self.setCentralWidget(central_widget)
26
+
27
+ # Create layout
28
+ layout = QVBoxLayout(central_widget)
29
+
30
+ # Create QPrefabsManager
31
+ self.prefabs_manager = QPrefabsManager()
32
+
33
+ # Add to layout
34
+ layout.addWidget(self.prefabs_manager)
35
+
36
+ # Connect signals
37
+ self.prefabs_manager.libraryPathChanged.connect(self.on_library_path_changed)
38
+ self.prefabs_manager.selectionChanged.connect(self.on_selection_changed)
39
+
40
+ def on_library_path_changed(self, path):
41
+ """Handle library path changed signal"""
42
+ print(f"Library path changed: {path}")
43
+
44
+ def on_selection_changed(self, selected):
45
+ """Handle selection changed signal"""
46
+ print(f"Selection changed: {selected}")
47
+
48
+
49
+ if __name__ == "__main__":
50
+ app = QApplication(sys.argv)
51
+ window = TestWindow()
52
+ window.show()
53
+ sys.exit(app.exec())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyscreeps-arena
3
- Version: 0.5.9b6
3
+ Version: 0.5.9.2
4
4
  Summary: Python api|interface to play game: Screeps: Arena.
5
5
  Author-email: 2229066748@qq.com
6
6
  Maintainer: Eagle'sBaby
@@ -49,6 +49,10 @@ pyscreeps_arena/ui/qmapv/test_qcinfo.py
49
49
  pyscreeps_arena/ui/qmapv/test_qco_drag.py
50
50
  pyscreeps_arena/ui/qmapv/test_qmapv.py
51
51
  pyscreeps_arena/ui/qmapv/test_simple_array.py
52
+ pyscreeps_arena/ui/qprefabs/__init__.py
53
+ pyscreeps_arena/ui/qprefabs/model.py
54
+ pyscreeps_arena/ui/qprefabs/qprefabs.py
55
+ pyscreeps_arena/ui/qprefabs/test.py
52
56
  pyscreeps_arena/ui/qrecipe/__init__.py
53
57
  pyscreeps_arena/ui/qrecipe/model.py
54
58
  pyscreeps_arena/ui/qrecipe/qrecipe.py
@@ -7,7 +7,7 @@ with open(r"T:\New_PC\Import_Project\uploads\pyscreeps-arena_upload\pyscreeps-ar
7
7
  long_description = f.read()
8
8
  setup(
9
9
  name='pyscreeps-arena',
10
- version='0.5.9b6',
10
+ version='0.5.9.2',
11
11
  description='Python api|interface to play game: Screeps: Arena.',
12
12
  long_description=long_description,
13
13
  long_description_content_type='text/markdown',