Skip to content

Commit 39e4567

Browse files
committed
Merge branch 'old'
# Conflicts: # .gitignore # .run/compile_ui.run.xml # .vscode/launch.json # README.md # compile_ui.py # makefile.py # requirements.txt # src/common.py # src/editors/assetgroup_maker/dialog.py # src/editors/assetgroup_maker/main.py # src/editors/assetgroup_maker/objects.py # src/editors/assetgroup_maker/property/ui_frame_group.py # src/editors/hotkey_editor/main.py # src/editors/hotkey_editor/objects.py # src/editors/loading_editor/main.py # src/editors/loading_editor/main.ui # src/editors/loading_editor/ui_main.py # src/editors/loading_editor/viewport.py # src/editors/smartprop_editor/_common.py # src/editors/smartprop_editor/actions/bulk_model_importer.py # src/editors/smartprop_editor/choices.py # src/editors/smartprop_editor/commands.py # src/editors/smartprop_editor/document.py # src/editors/smartprop_editor/document.ui # src/editors/smartprop_editor/main.py # src/editors/smartprop_editor/main.ui # src/editors/smartprop_editor/objects.py # src/editors/smartprop_editor/properties_group_frame.py # src/editors/smartprop_editor/property/bool.py # src/editors/smartprop_editor/property/color.py # src/editors/smartprop_editor/property/colormatch.py # src/editors/smartprop_editor/property/combobox.py # src/editors/smartprop_editor/property/comment.py # src/editors/smartprop_editor/property/comment.ui # src/editors/smartprop_editor/property/comparison.py # src/editors/smartprop_editor/property/filtersurface.py # src/editors/smartprop_editor/property/float.py # src/editors/smartprop_editor/property/legacy.py # src/editors/smartprop_editor/property/set_variable.py # src/editors/smartprop_editor/property/set_variable.ui # src/editors/smartprop_editor/property/string.py # src/editors/smartprop_editor/property/ui_comment.py # src/editors/smartprop_editor/property/ui_set_variable.py # src/editors/smartprop_editor/property/variable.py # src/editors/smartprop_editor/property/vector3d.py # src/editors/smartprop_editor/property_frame.py # src/editors/smartprop_editor/property_frame.ui # src/editors/smartprop_editor/ui_document.py # src/editors/smartprop_editor/ui_property_frame.py # src/editors/smartprop_editor/ui_variable_frame.py # src/editors/smartprop_editor/variable_frame.py # src/editors/smartprop_editor/variable_frame.ui # src/editors/smartprop_editor/vsmart.py # src/editors/soundevent_editor/audio_player.py # src/editors/soundevent_editor/commands.py # src/editors/soundevent_editor/internal_explorer.py # src/editors/soundevent_editor/main.py # src/editors/soundevent_editor/main.ui # src/editors/soundevent_editor/objects.py # src/editors/soundevent_editor/preset_manager.py # src/editors/soundevent_editor/properties_window.py # src/editors/soundevent_editor/properties_window.ui # src/editors/soundevent_editor/property/common.py # src/editors/soundevent_editor/property/curve/main.py # src/editors/soundevent_editor/property/frame.py # src/editors/soundevent_editor/ui_main.py # src/forms/about/main.ui # src/forms/about/ui_main.py # src/icons/assettypes/vsmart_sm.png # src/main.py # src/main.ui # src/other/addon_functions.py # src/other/ncm_setup.py # src/other/steam_restart.py # src/property/methods.py # src/resources.qrc # src/settings/common.py # src/settings/main.py # src/styles/common.py # src/styles/qt_global_stylesheet.py # src/ui_main.py # src/updater/check.py
2 parents 1c974f6 + 5c8526c commit 39e4567

35 files changed

Lines changed: 86144 additions & 0 deletions

.run/Build Final.run.xml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="build final" type="PythonConfigurationType" factoryName="Python">
3+
<module name="Hammer5Tools" />
4+
<option name="ENV_FILES" value="" />
5+
<option name="INTERPRETER_OPTIONS" value="" />
6+
<option name="PARENT_ENVS" value="true" />
7+
<envs>
8+
<env name="PYTHONUNBUFFERED" value="1" />
9+
</envs>
10+
<option name="SDK_HOME" value="" />
11+
<option name="SDK_NAME" value="Python desktop" />
12+
<option name="WORKING_DIRECTORY" value="" />
13+
<option name="IS_MODULE_SDK" value="false" />
14+
<option name="ADD_CONTENT_ROOTS" value="true" />
15+
<option name="ADD_SOURCE_ROOTS" value="true" />
16+
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/dev/build.py" />
17+
<option name="PARAMETERS" value="--build-all --archive" />
18+
<option name="SHOW_COMMAND_LINE" value="false" />
19+
<option name="EMULATE_TERMINAL" value="false" />
20+
<option name="MODULE_MODE" value="false" />
21+
<option name="REDIRECT_INPUT" value="false" />
22+
<option name="INPUT_FILE" value="" />
23+
<method v="2" />
24+
</configuration>
25+
</component>

dev/custom_curve/CurveWidget.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import sys
2+
from PySide6.QtWidgets import QApplication, QDialog, QVBoxLayout, QGraphicsView, QGraphicsScene, QGraphicsEllipseItem, QGraphicsLineItem
3+
from PySide6.QtGui import QPainter, QPen, QColor, QFont, QMouseEvent
4+
from PySide6.QtCore import Qt, QPointF
5+
6+
class Curve:
7+
def __init__(self):
8+
self.dots = [QPointF(0.0, 0.0), QPointF(1.0, 1.0), QPointF(0.25, 0.75), QPointF(0.75, 0.25)]
9+
10+
def evaluate(self, t):
11+
a, b, p1, p2 = self.dots
12+
return (
13+
(1 - t)**3 * a +
14+
3 * (1 - t)**2 * t * p1 +
15+
3 * (1 - t) * t**2 * p2 +
16+
t**3 * b
17+
)
18+
19+
class CurveWidget(QGraphicsView):
20+
def __init__(self, parent=None):
21+
super().__init__(parent)
22+
self.scene = QGraphicsScene(self)
23+
self.setScene(self.scene)
24+
25+
self.curve = Curve()
26+
self.setRenderHint(QPainter.Antialiasing)
27+
self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate)
28+
29+
self.debug_text = self.scene.addText("")
30+
self.debug_text.setDefaultTextColor(QColor(0, 0, 255)) # Blue debug text
31+
font = QFont()
32+
font.setPointSize(8)
33+
self.debug_text.setFont(font)
34+
35+
self.selected_dot_index = None
36+
37+
# Disable scrolling
38+
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
39+
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
40+
41+
def setCurve(self, curve):
42+
self.curve = curve
43+
self.update_scene()
44+
45+
def update_scene(self):
46+
self.scene.clear()
47+
width = self.width()
48+
height = self.height()
49+
50+
# Calculate margins
51+
margin_x = width * 0.04
52+
margin_y = height * 0.04
53+
54+
pen = QPen(QColor(150, 150, 150))
55+
for i in range(0, 1001):
56+
t = i / 1000.0
57+
point = self.curve.evaluate(t)
58+
x = margin_x + point.x() * (width - 2 * margin_x)
59+
y = margin_y + (1 - point.y()) * (height - 2 * margin_y)
60+
if 0 <= x <= width and 0 <= y <= height:
61+
self.scene.addLine(x - 1, y, x + 1, y, pen)
62+
63+
dot_radius = 6
64+
pen = QPen(QColor(150, 150, 40), 2)
65+
for i, dot in enumerate(self.curve.dots):
66+
x = margin_x + dot.x() * (width - 2 * margin_x)
67+
y = margin_y + (1 - dot.y()) * (height - 2 * margin_y)
68+
ellipse = QGraphicsEllipseItem(x - dot_radius, y - dot_radius, 2 * dot_radius, 2 * dot_radius)
69+
ellipse.setBrush(QColor(255, 100, 100))
70+
self.scene.addItem(ellipse)
71+
72+
if i == 2 or i == 3:
73+
anchor_x = margin_x + self.curve.dots[i - 2].x() * (width - 2 * margin_x)
74+
anchor_y = margin_y + (1 - self.curve.dots[i - 2].y()) * (height - 2 * margin_y)
75+
line = QGraphicsLineItem(anchor_x, anchor_y, x, y)
76+
line.setPen(pen)
77+
self.scene.addItem(line)
78+
79+
def resizeEvent(self, event):
80+
super().resizeEvent(event)
81+
self.update_scene()
82+
83+
def mousePressEvent(self, event: QMouseEvent):
84+
pos = event.position()
85+
width = self.width()
86+
height = self.height()
87+
margin_x = width * 0.04
88+
margin_y = height * 0.04
89+
bounding_box_size = 16
90+
for i, dot in enumerate(self.curve.dots):
91+
x = margin_x + dot.x() * (width - 2 * margin_x)
92+
y = margin_y + (1 - dot.y()) * (height - 2 * margin_y)
93+
if (x - bounding_box_size <= pos.x() <= x + bounding_box_size) and (y - bounding_box_size <= pos.y() <= y + bounding_box_size):
94+
self.selected_dot_index = i
95+
break
96+
97+
def mouseMoveEvent(self, event: QMouseEvent):
98+
if self.selected_dot_index is not None:
99+
pos = event.position()
100+
width = self.width()
101+
height = self.height()
102+
margin_x = width * 0.02
103+
margin_y = height * 0.02
104+
x = (pos.x() - margin_x) / (width - 2 * margin_x)
105+
y = 1 - ((pos.y() - margin_y) / (height - 2 * margin_y))
106+
self.curve.dots[self.selected_dot_index] = QPointF(x, y)
107+
self.update_scene()
108+
109+
def mouseReleaseEvent(self, event: QMouseEvent):
110+
self.selected_dot_index = None
111+
112+
class CurveWidgetDialog(QDialog):
113+
def __init__(self, parent=None):
114+
super().__init__(parent)
115+
self.setWindowTitle("Curve Widget Dialog")
116+
self.resize(800, 600)
117+
118+
layout = QVBoxLayout()
119+
self.curve_widget = CurveWidget(self)
120+
layout.addWidget(self.curve_widget)
121+
self.setLayout(layout)
122+
123+
self.curve_widget.setCurve(Curve())
124+
125+
def main():
126+
app = QApplication(sys.argv)
127+
main_window = CurveWidgetDialog()
128+
main_window.show()
129+
sys.exit(app.exec())
130+
131+
if __name__ == "__main__":
132+
main()

dev/main/json_steam/main.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import json
2+
import json_stream
3+
import time
4+
5+
file_path = 'sounds.hbat'
6+
def read_with_json(file_path):
7+
with open(file_path, 'r') as file:
8+
data = json.load(file)
9+
return data.get('process')
10+
11+
def read_with_json_stream(file_path):
12+
with open(file_path, 'r') as file:
13+
data = json_stream.load(file)
14+
for key, value in data.items():
15+
if key == 'process':
16+
# Access the process data directly
17+
process_data = {k: v for k, v in value.items()}
18+
return process_data
19+
20+
# Measure time for json
21+
start_time = time.time()
22+
process_data_json = read_with_json(file_path)
23+
json_duration = time.time() - start_time
24+
print(f"Process data using json: {process_data_json}")
25+
print(f"Time taken with json: {json_duration:.6f} seconds")
26+
27+
# Measure time for json_stream
28+
start_time = time.time()
29+
process_data_json_stream = read_with_json_stream(file_path)
30+
json_stream_duration = time.time() - start_time
31+
print(f"Process data using json_stream: {process_data_json_stream}")
32+
print(f"Time taken with json_stream: {json_stream_duration:.6f} seconds")

dev/main/json_steam/sounds.hbat

Lines changed: 23 additions & 0 deletions
Large diffs are not rendered by default.

dev/main/json_steam/sounds_light.hbat

Lines changed: 23 additions & 0 deletions
Large diffs are not rendered by default.

dev/main/system_watcher.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import sys
2+
import time
3+
from PySide6.QtWidgets import QApplication, QMainWindow, QTextEdit, QVBoxLayout, QWidget, QMessageBox
4+
from PySide6.QtCore import QDir
5+
from watchdog.observers import Observer
6+
from watchdog.events import FileSystemEventHandler
7+
8+
class FileWatcherExample(QMainWindow):
9+
def __init__(self):
10+
super().__init__()
11+
self.setWindowTitle("File System Watcher Example")
12+
13+
self.central_widget = QWidget()
14+
self.setCentralWidget(self.central_widget)
15+
self.layout = QVBoxLayout(self.central_widget)
16+
17+
self.text_edit = QTextEdit()
18+
self.text_edit.setReadOnly(True)
19+
self.layout.addWidget(self.text_edit)
20+
21+
self.last_event_time = {}
22+
self.debounce_time = 0.5 # 500 milliseconds
23+
24+
root_path = r"C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Global Offensive\content\csgo_addons\batch_creator"
25+
26+
if QDir(root_path).exists():
27+
self.start_watching(root_path)
28+
else:
29+
QMessageBox.critical(self, "Error", f"The directory {root_path} does not exist.")
30+
self.close()
31+
32+
def start_watching(self, path):
33+
event_handler = FileSystemEventHandler()
34+
event_handler.on_modified = self.on_modified
35+
event_handler.on_created = self.on_created
36+
event_handler.on_deleted = self.on_deleted
37+
event_handler.on_moved = self.on_moved
38+
39+
self.observer = Observer()
40+
self.observer.schedule(event_handler, path, recursive=True)
41+
self.observer.start()
42+
43+
def should_process_event(self, event):
44+
current_time = time.time()
45+
last_time = self.last_event_time.get(event.src_path, 0)
46+
if current_time - last_time > self.debounce_time:
47+
self.last_event_time[event.src_path] = current_time
48+
return True
49+
return False
50+
51+
def on_modified(self, event):
52+
if self.should_process_event(event):
53+
self.text_edit.append(f"Modified: {event.src_path}")
54+
55+
def on_created(self, event):
56+
if self.should_process_event(event):
57+
self.text_edit.append(f"Created: {event.src_path}")
58+
59+
def on_deleted(self, event):
60+
if self.should_process_event(event):
61+
self.text_edit.append(f"Deleted: {event.src_path}")
62+
63+
def on_moved(self, event):
64+
if self.should_process_event(event):
65+
self.text_edit.append(f"Moved: from {event.src_path} to {event.dest_path}")
66+
67+
def closeEvent(self, event):
68+
self.observer.stop()
69+
self.observer.join()
70+
event.accept()
71+
72+
if __name__ == "__main__":
73+
app = QApplication(sys.argv)
74+
window = FileWatcherExample()
75+
window.show()
76+
sys.exit(app.exec())

dev/widgets/test_tree_widget.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import pytest
2+
from PySide6.QtWidgets import QApplication, QTreeWidgetItem
3+
from PySide6.QtCore import Qt, QPointF
4+
from dev.widgets.tree_widget import CustomTreeWidget, MoveItemCommand
5+
6+
@pytest.fixture(scope="session")
7+
def qapp():
8+
import sys
9+
from PySide6.QtWidgets import QApplication
10+
app = QApplication.instance() or QApplication(sys.argv)
11+
yield app
12+
13+
def serialize_tree(tree):
14+
def serialize_item(item):
15+
return {
16+
"text": item.text(0),
17+
"children": [serialize_item(item.child(i)) for i in range(item.childCount())]
18+
}
19+
return [
20+
serialize_item(tree.topLevelItem(i))
21+
for i in range(tree.topLevelItemCount())
22+
]
23+
24+
def setup_tree():
25+
# Build the tree as described
26+
tree = CustomTreeWidget(undo_stack=type("DummyStack", (), {"push": lambda self, cmd: cmd.redo()})())
27+
parent1 = QTreeWidgetItem(["Parent1"])
28+
child1 = QTreeWidgetItem(["child1"])
29+
child2 = QTreeWidgetItem(["child2"])
30+
child3 = QTreeWidgetItem(["child3"])
31+
parent1.addChildren([child1, child2, child3])
32+
parent2 = QTreeWidgetItem(["Parent2"])
33+
child4 = QTreeWidgetItem(["child4"])
34+
parent2.addChild(child4)
35+
tree.addTopLevelItems([parent1, parent2])
36+
return tree, parent1, child1, child2, child3, parent2, child4
37+
38+
def test_drag_and_drop_and_undo(qapp):
39+
# Use a real QUndoStack for undo/redo
40+
from PySide6.QtGui import QUndoStack
41+
tree = CustomTreeWidget(undo_stack=QUndoStack())
42+
parent1 = QTreeWidgetItem(["Parent1"])
43+
child1 = QTreeWidgetItem(["child1"])
44+
child2 = QTreeWidgetItem(["child2"])
45+
child3 = QTreeWidgetItem(["child3"])
46+
parent1.addChildren([child1, child2, child3])
47+
parent2 = QTreeWidgetItem(["Parent2"])
48+
child4 = QTreeWidgetItem(["child4"])
49+
parent2.addChild(child4)
50+
tree.addTopLevelItems([parent1, parent2])
51+
52+
# Save initial state
53+
initial_state = serialize_tree(tree)
54+
55+
# 1. Move child1 under child4
56+
old_parent = parent1
57+
old_index = old_parent.indexOfChild(child1)
58+
new_parent = child4
59+
new_index = child4.childCount()
60+
tree.undo_stack.push(MoveItemCommand(tree, child1, old_parent, old_index, new_parent, new_index))
61+
62+
# 2. Move child2 to root (as first top-level item)
63+
old_parent = parent1
64+
old_index = old_parent.indexOfChild(child2)
65+
new_parent = None
66+
new_index = 0
67+
tree.undo_stack.push(MoveItemCommand(tree, child2, old_parent, old_index, new_parent, new_index))
68+
69+
# 3. Move parent1 under child1
70+
old_parent = None
71+
old_index = tree.indexOfTopLevelItem(parent1)
72+
new_parent = child1
73+
new_index = child1.childCount()
74+
tree.undo_stack.push(MoveItemCommand(tree, parent1, old_parent, old_index, new_parent, new_index))
75+
76+
# 4. Move parent2 under child2
77+
old_parent = None
78+
old_index = tree.indexOfTopLevelItem(parent2)
79+
new_parent = child2
80+
new_index = child2.childCount()
81+
tree.undo_stack.push(MoveItemCommand(tree, parent2, old_parent, old_index, new_parent, new_index))
82+
83+
# Now undo all operations
84+
for _ in range(tree.undo_stack.count()):
85+
tree.undo_stack.undo()
86+
87+
# Compare state after undo to initial state
88+
final_state = serialize_tree(tree)
89+
assert final_state == initial_state, f"Tree structure after undo does not match initial structure.\nInitial: {initial_state}\nFinal: {final_state}"

0 commit comments

Comments
 (0)