Skip to content

Commit 1799803

Browse files
committed
Add a setting button
1 parent e7ac4a9 commit 1799803

File tree

3 files changed

+204
-2
lines changed

3 files changed

+204
-2
lines changed

settings.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,8 @@
2929
"/System/Volumes/Data/Users/CX330/Working/Share/x64asm/shell.asm",
3030
"/System/Volumes/Data/Users/CX330/Working/Share/x64asm/shell.bin"
3131
],
32-
"last_open_dir": "/Users/CX330/Working/Share/MplabProjects/lab4.X"
32+
"last_open_dir": "/Users/CX330/Working/Share/MplabProjects/lab4.X",
33+
"opt_rule_push_zero": true,
34+
"opt_rule_mov_imm8": true,
35+
"syscalls_style_default": "Commented"
3336
}

ui/main_window.py

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
from ..backends.validator import BadPatternManager, validate_all
6363
from ..utils.config import load_config, save_config
6464
from .patterns_dialog import PatternsDialog
65+
from .settings_dialog import SettingsDialog
6566
from .patterns_panel import PatternsPanel
6667
from .highlighters import (
6768
create_disassembly_highlighter,
@@ -183,12 +184,25 @@ def _is_null_pat(p) -> bool:
183184
tb.addSeparator()
184185
tb.addWidget(QLabel("Arch:"))
185186
tb.addWidget(self.arch_combo)
186-
tb.addSeparator()
187187
# Labels are always allowed (block assembly mode enabled)
188188
# Checkbox removed; always assemble with labels preserved.
189189
tb.addSeparator()
190190
tb.addAction(self.act_assemble)
191191
tb.addAction(self.act_disassemble)
192+
# Push Settings button to the far right within the same title bar
193+
try:
194+
self._toolbar_right_spacer = QWidget()
195+
self._toolbar_right_spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
196+
tb.addWidget(self._toolbar_right_spacer)
197+
except Exception:
198+
self._toolbar_right_spacer = None
199+
try:
200+
self.btn_settings = QPushButton("Settings")
201+
self.btn_settings.setToolTip("Open Settings")
202+
tb.addWidget(self.btn_settings)
203+
self.btn_settings.clicked.connect(self.on_open_settings)
204+
except Exception:
205+
self.btn_settings = None
192206

193207
# Central layout
194208
splitter = QSplitter()
@@ -372,6 +386,13 @@ def _copy_disasm():
372386
parent=self,
373387
)
374388
self.output_tabs.addTab(self.optimize_widget, "Optimize")
389+
# Apply optimize defaults from config
390+
try:
391+
cfg = load_config()
392+
self.optimize_widget.chk_rule1.setChecked(bool(cfg.get("opt_rule_push_zero", True)))
393+
self.optimize_widget.chk_rule2.setChecked(bool(cfg.get("opt_rule_mov_imm8", True)))
394+
except Exception:
395+
pass
375396

376397
# Formats view (Shellcode output pane)
377398
fmt_widget = QWidget()
@@ -411,6 +432,14 @@ def _copy_disasm():
411432
self.hll_lang_combo.addItems(["C", "Python", "Zig", "Rust", "Go"]) # supported generators
412433
except Exception:
413434
pass
435+
# Load default HLL language from config
436+
try:
437+
cfg = load_config()
438+
def_lang = (cfg.get("default_hll_lang") or "C")
439+
idx = max(0, self.hll_lang_combo.findText(def_lang))
440+
self.hll_lang_combo.setCurrentIndex(idx)
441+
except Exception:
442+
pass
414443
try:
415444
# Prevent Enter/Return from leaking to the Assembly editor when changing selection
416445
self.hll_lang_combo.installEventFilter(self)
@@ -521,6 +550,14 @@ def _insert_snippet(snippet: str) -> None:
521550
parent=self,
522551
)
523552
self.output_tabs.addTab(self.syscalls_widget, "Syscalls")
553+
# Apply Syscalls default style from config
554+
try:
555+
cfg = load_config()
556+
def_style = (cfg.get("syscalls_style_default") or "Commented")
557+
idx = max(0, self.syscalls_widget.style_combo.findText(def_style))
558+
self.syscalls_widget.style_combo.setCurrentIndex(idx)
559+
except Exception:
560+
pass
524561
# Now that Syscalls tab exists, sync Shellcode pane and editors padding to match it
525562
try:
526563
self._sync_shellcode_padding_to_syscalls()
@@ -565,6 +602,15 @@ def _insert_asm_text(s: str) -> None:
565602
parent=self,
566603
)
567604
self.output_tabs.addTab(self.shellstorm_widget, "Shell-Storm")
605+
# Apply Shell-Storm default preview language
606+
try:
607+
cfg = load_config()
608+
def_ss_lang = (cfg.get("shellstorm_default_lang") or "C")
609+
if getattr(self.shellstorm_widget, 'lang_combo', None) is not None:
610+
idx = max(0, self.shellstorm_widget.lang_combo.findText(def_ss_lang))
611+
self.shellstorm_widget.lang_combo.setCurrentIndex(idx)
612+
except Exception:
613+
pass
568614

569615
# Validation tab (container with a button bar and text)
570616
val_container = QWidget()
@@ -2180,3 +2226,61 @@ def closeEvent(self, event):
21802226
cfg["bad_patterns"] = self.bpm.serialize()
21812227
save_config(cfg)
21822228
super().closeEvent(event)
2229+
2230+
def on_open_settings(self):
2231+
"""Open Settings dialog and apply changes live on accept."""
2232+
try:
2233+
dlg = SettingsDialog(self)
2234+
except Exception:
2235+
return
2236+
try:
2237+
res = dlg.exec()
2238+
except Exception:
2239+
res = dlg.exec_()
2240+
if not res:
2241+
return
2242+
vals = dlg.values()
2243+
# Apply: Bad-chars highlight only if value provided
2244+
if "bad_highlight_enabled" in vals:
2245+
try:
2246+
self.on_badchars_toggled(bool(vals.get("bad_highlight_enabled")))
2247+
if hasattr(self, 'patterns_widget') and hasattr(self.patterns_widget, 'chk_enabled'):
2248+
self.patterns_widget.chk_enabled.setChecked(bool(vals.get("bad_highlight_enabled")))
2249+
except Exception:
2250+
pass
2251+
# Apply: Optimize rules (present in Settings)
2252+
try:
2253+
if "opt_rule_push_zero" in vals:
2254+
self.optimize_widget.chk_rule1.setChecked(bool(vals.get("opt_rule_push_zero")))
2255+
if "opt_rule_mov_imm8" in vals:
2256+
self.optimize_widget.chk_rule2.setChecked(bool(vals.get("opt_rule_mov_imm8")))
2257+
self.optimize_widget.on_preview()
2258+
except Exception:
2259+
pass
2260+
# Apply: Formats default language only if present
2261+
if "default_hll_lang" in vals:
2262+
try:
2263+
def_lang = vals.get("default_hll_lang")
2264+
if def_lang:
2265+
idx = max(0, self.hll_lang_combo.findText(def_lang))
2266+
self.hll_lang_combo.setCurrentIndex(idx)
2267+
except Exception:
2268+
pass
2269+
# Apply: Syscalls snippet style (present in Settings)
2270+
try:
2271+
if "syscalls_style_default" in vals:
2272+
def_style = vals.get("syscalls_style_default")
2273+
if def_style:
2274+
idx = max(0, self.syscalls_widget.style_combo.findText(def_style))
2275+
self.syscalls_widget.style_combo.setCurrentIndex(idx)
2276+
except Exception:
2277+
pass
2278+
# Apply: Shell-Storm preview syntax only if present
2279+
if "shellstorm_default_lang" in vals:
2280+
try:
2281+
def_ss = vals.get("shellstorm_default_lang")
2282+
if def_ss and getattr(self.shellstorm_widget, 'lang_combo', None) is not None:
2283+
idx = max(0, self.shellstorm_widget.lang_combo.findText(def_ss))
2284+
self.shellstorm_widget.lang_combo.setCurrentIndex(idx)
2285+
except Exception:
2286+
pass

ui/settings_dialog.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
from __future__ import annotations
2+
3+
from typing import Optional
4+
5+
try:
6+
from PySide6.QtCore import Qt # type: ignore
7+
from PySide6.QtWidgets import ( # type: ignore
8+
QDialog, QDialogButtonBox, QVBoxLayout, QHBoxLayout, QWidget,
9+
QLabel, QCheckBox, QPushButton, QComboBox, QTabWidget
10+
)
11+
except Exception:
12+
from PySide2.QtCore import Qt # type: ignore
13+
from PySide2.QtWidgets import ( # type: ignore
14+
QDialog, QDialogButtonBox, QVBoxLayout, QHBoxLayout, QWidget,
15+
QLabel, QCheckBox, QPushButton, QComboBox, QTabWidget
16+
)
17+
18+
from ..utils.config import load_config, save_config
19+
# Patterns management is no longer exposed in Settings
20+
21+
22+
class SettingsDialog(QDialog):
23+
"""Aggregated Settings dialog for Shellcode IDE.
24+
25+
Tabs include per-feature preferences mirrored from the main UI:
26+
- Bad Chars (highlight toggle + manage patterns)
27+
- Optimize (rule toggles)
28+
- Formats (default language)
29+
- Syscalls (snippet style)
30+
- Shell-Storm (preview syntax)
31+
"""
32+
33+
def __init__(self, parent=None):
34+
super().__init__(parent)
35+
self.setWindowTitle("Settings")
36+
self.resize(520, 360)
37+
38+
cfg = load_config()
39+
40+
lay = QVBoxLayout(self)
41+
self.tabs = QTabWidget()
42+
lay.addWidget(self.tabs)
43+
44+
# Optimize tab
45+
opt = QWidget(); opt_l = QVBoxLayout(opt)
46+
self.chk_opt_rule1 = QCheckBox("Push 0 -> xor; push reg")
47+
self.chk_opt_rule2 = QCheckBox("mov reg, imm -> mov reg8/16/32, imm (risky)")
48+
self.chk_opt_rule1.setChecked(bool(cfg.get("opt_rule_push_zero", True)))
49+
self.chk_opt_rule2.setChecked(bool(cfg.get("opt_rule_mov_imm8", True)))
50+
opt_l.addWidget(self.chk_opt_rule1)
51+
opt_l.addWidget(self.chk_opt_rule2)
52+
opt_l.addStretch(1)
53+
self.tabs.addTab(opt, "Optimize")
54+
55+
# Syscalls tab
56+
sc = QWidget(); sc_l = QVBoxLayout(sc)
57+
r2 = QHBoxLayout()
58+
r2.addWidget(QLabel("Default snippet style:"))
59+
self.combo_sys_style = QComboBox(); self.combo_sys_style.addItems(["Commented", "Minimal"])
60+
try:
61+
def_style = (cfg.get("syscalls_style_default") or "Commented")
62+
idx = max(0, self.combo_sys_style.findText(def_style))
63+
self.combo_sys_style.setCurrentIndex(idx)
64+
except Exception:
65+
pass
66+
r2.addWidget(self.combo_sys_style)
67+
r2.addStretch(1)
68+
sc_l.addLayout(r2)
69+
sc_l.addStretch(1)
70+
self.tabs.addTab(sc, "Syscalls")
71+
72+
# Buttons
73+
self.buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
74+
lay.addWidget(self.buttons)
75+
76+
# Events
77+
self.buttons.accepted.connect(self._on_accept)
78+
self.buttons.rejected.connect(self.reject)
79+
80+
# Expose results to caller
81+
def values(self) -> dict:
82+
return {
83+
"opt_rule_push_zero": bool(self.chk_opt_rule1.isChecked()),
84+
"opt_rule_mov_imm8": bool(self.chk_opt_rule2.isChecked()),
85+
"syscalls_style_default": self.combo_sys_style.currentText() or "Commented",
86+
}
87+
88+
# Hooks
89+
def _on_accept(self):
90+
# Persist to config; the main window will apply live
91+
cfg = load_config()
92+
vals = self.values()
93+
cfg.update(vals)
94+
save_config(cfg)
95+
self.accept()

0 commit comments

Comments
 (0)