Skip to content

Commit 71a12bf

Browse files
committed
Minor update of the --gui functionality
1 parent f7aa757 commit 71a12bf

File tree

3 files changed

+198
-56
lines changed

3 files changed

+198
-56
lines changed

data/txt/sha256sums.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ ce6e1c1766acd95168f7708ddcacaa4a586c21ffc9e92024c4715611c802b60c lib/core/dicts
177177
c9d1f64648062d7962caf02c4e2e7d84e8feb2a14451146f627112aae889afcd lib/core/dump.py
178178
c1f211843ccc93a50639ae6f4a50eb434f334e095d9fea440cebe589004374f3 lib/core/enums.py
179179
00a9b29caa81fe4a5ef145202f9c92e6081f90b2a85cd76c878d520d900ad856 lib/core/exception.py
180-
629c0d06d4f4d093badfc8d1de49432d058f66f3223b08dded012eaf05719de2 lib/core/gui.py
180+
1c48804c10b94da696d3470efbd25d2fff0f0bbf2af0101aaac8f8c097fce02b lib/core/gui.py
181181
4608f21a4333c162ab3c266c903fda4793cc5834de30d06affe9b7566dd09811 lib/core/__init__.py
182182
3d308440fb01d04b5d363bfbe0f337756b098532e5bb7a1c91d5213157ec2c35 lib/core/log.py
183183
2a06dc9b5c17a1efdcdb903545729809399f1ee96f7352cc19b9aaa227394ff3 lib/core/optiondict.py
@@ -188,7 +188,7 @@ c4bfb493a03caf84dd362aec7c248097841de804b7413d0e1ecb8a90c8550bc0 lib/core/readl
188188
d1bd70c1a55858495c727fbec91e30af267459c8f64d50fabf9e4ee2c007e920 lib/core/replication.py
189189
1d0f80b0193ac5204527bfab4bde1a7aee0f693fd008e86b4b29f606d1ef94f3 lib/core/revision.py
190190
d2eb8e4b05ac93551272b3d4abfaf5b9f2d3ac92499a7704c16ed0b4f200db38 lib/core/session.py
191-
9321b30f898d67fd5505426274f562af6f95e426c57f95c54eb69174beb48278 lib/core/settings.py
191+
84eb7f5d155afce459120ab42efb8f5baa104f8ed2f8e64d8d8cbdea62a79dc7 lib/core/settings.py
192192
1c5eab9494eb969bc9ce118a2ea6954690c6851cbe54c18373c723b99734bf09 lib/core/shell.py
193193
4eea6dcf023e41e3c64b210cb5c2efc7ca893b727f5e49d9c924f076bb224053 lib/core/subprocessng.py
194194
cdd352e1331c6b535e780f6edea79465cb55af53aa2114dcea0e8bf382e56d1a lib/core/target.py

lib/core/gui.py

Lines changed: 195 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,6 @@ def check(self, *args):
6161
else:
6262
self.set(self.old_value)
6363

64-
# Reference: https://code.activestate.com/recipes/580726-tkinter-notebook-that-fits-to-the-height-of-every-/
65-
class AutoresizableNotebook(_tkinter_ttk.Notebook):
66-
def __init__(self, master=None, **kw):
67-
_tkinter_ttk.Notebook.__init__(self, master, **kw)
68-
self.bind("<<NotebookTabChanged>>", self._on_tab_changed)
69-
70-
def _on_tab_changed(self, event):
71-
event.widget.update_idletasks()
72-
73-
tab = event.widget.nametowidget(event.widget.select())
74-
event.widget.configure(height=tab.winfo_reqheight())
75-
7664
try:
7765
window = _tkinter.Tk()
7866
except Exception as ex:
@@ -81,11 +69,41 @@ def _on_tab_changed(self, event):
8169

8270
window.title(VERSION_STRING)
8371

84-
# Reference: https://www.holadevs.com/pregunta/64750/change-selected-tab-color-in-ttknotebook
72+
# Set theme and colors
73+
bg_color = "#f5f5f5"
74+
fg_color = "#333333"
75+
accent_color = "#2c7fb8"
76+
window.configure(background=bg_color)
77+
78+
# Configure styles
8579
style = _tkinter_ttk.Style()
86-
settings = {"TNotebook.Tab": {"configure": {"padding": [5, 1], "background": "#fdd57e"}, "map": {"background": [("selected", "#C70039"), ("active", "#fc9292")], "foreground": [("selected", "#ffffff"), ("active", "#000000")]}}}
87-
style.theme_create("custom", parent="alt", settings=settings)
88-
style.theme_use("custom")
80+
81+
# Try to use a more modern theme if available
82+
available_themes = style.theme_names()
83+
if 'clam' in available_themes:
84+
style.theme_use('clam')
85+
elif 'alt' in available_themes:
86+
style.theme_use('alt')
87+
88+
# Configure notebook style
89+
style.configure("TNotebook", background=bg_color)
90+
style.configure("TNotebook.Tab",
91+
padding=[10, 4],
92+
background="#e1e1e1",
93+
font=('Helvetica', 9))
94+
style.map("TNotebook.Tab",
95+
background=[("selected", accent_color), ("active", "#7fcdbb")],
96+
foreground=[("selected", "white"), ("active", "white")])
97+
98+
# Configure button style
99+
style.configure("TButton",
100+
padding=4,
101+
relief="flat",
102+
background=accent_color,
103+
foreground="white",
104+
font=('Helvetica', 9))
105+
style.map("TButton",
106+
background=[('active', '#41b6c4')])
89107

90108
# Reference: https://stackoverflow.com/a/10018670
91109
def center(window):
@@ -138,24 +156,26 @@ def run():
138156
config = {}
139157

140158
for key in window._widgets:
141-
dest, type = key
159+
dest, widget_type = key
142160
widget = window._widgets[key]
143161

144162
if hasattr(widget, "get") and not widget.get():
145163
value = None
146-
elif type == "string":
164+
elif widget_type == "string":
147165
value = widget.get()
148-
elif type == "float":
166+
elif widget_type == "float":
149167
value = float(widget.get())
150-
elif type == "int":
168+
elif widget_type == "int":
151169
value = int(widget.get())
152170
else:
153171
value = bool(widget.var.get())
154172

155173
config[dest] = value
156174

157175
for option in parser.option_list:
158-
config[option.dest] = defaults.get(option.dest, None)
176+
# Only set default if not already set by the user
177+
if option.dest not in config or config[option.dest] is None:
178+
config[option.dest] = defaults.get(option.dest, None)
159179

160180
handle, configFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.CONFIG, text=True)
161181
os.close(handle)
@@ -183,20 +203,27 @@ def enqueue(stream, queue):
183203

184204
top = _tkinter.Toplevel()
185205
top.title("Console")
206+
top.configure(background=bg_color)
207+
208+
# Create a frame for the console
209+
console_frame = _tkinter.Frame(top, bg=bg_color)
210+
console_frame.pack(fill=_tkinter.BOTH, expand=True, padx=10, pady=10)
186211

187212
# Reference: https://stackoverflow.com/a/13833338
188-
text = _tkinter_scrolledtext.ScrolledText(top, undo=True)
213+
text = _tkinter_scrolledtext.ScrolledText(console_frame, undo=True, wrap=_tkinter.WORD,
214+
bg="#2c3e50", fg="#ecf0f1",
215+
insertbackground="white",
216+
font=('Consolas', 10))
189217
text.bind("<Key>", onKeyPress)
190218
text.bind("<Return>", onReturnPress)
191-
text.pack()
219+
text.pack(fill=_tkinter.BOTH, expand=True)
192220
text.focus()
193221

194222
center(top)
195223

196224
while True:
197225
line = ""
198226
try:
199-
# line = queue.get_nowait()
200227
line = queue.get(timeout=.1)
201228
text.insert(_tkinter.END, line)
202229
except _queue.Empty:
@@ -206,9 +233,10 @@ def enqueue(stream, queue):
206233
if not alive:
207234
break
208235

209-
menubar = _tkinter.Menu(window)
236+
# Create a menu bar
237+
menubar = _tkinter.Menu(window, bg=bg_color, fg=fg_color)
210238

211-
filemenu = _tkinter.Menu(menubar, tearoff=0)
239+
filemenu = _tkinter.Menu(menubar, tearoff=0, bg=bg_color, fg=fg_color)
212240
filemenu.add_command(label="Open", state=_tkinter.DISABLED)
213241
filemenu.add_command(label="Save", state=_tkinter.DISABLED)
214242
filemenu.add_separator()
@@ -217,7 +245,7 @@ def enqueue(stream, queue):
217245

218246
menubar.add_command(label="Run", command=run)
219247

220-
helpmenu = _tkinter.Menu(menubar, tearoff=0)
248+
helpmenu = _tkinter.Menu(menubar, tearoff=0, bg=bg_color, fg=fg_color)
221249
helpmenu.add_command(label="Official site", command=lambda: webbrowser.open(SITE))
222250
helpmenu.add_command(label="Github pages", command=lambda: webbrowser.open(GIT_PAGE))
223251
helpmenu.add_command(label="Wiki pages", command=lambda: webbrowser.open(WIKI_PAGE))
@@ -226,59 +254,173 @@ def enqueue(stream, queue):
226254
helpmenu.add_command(label="About", command=lambda: _tkinter_messagebox.showinfo("About", "Copyright (c) 2006-2025\n\n (%s)" % DEV_EMAIL_ADDRESS))
227255
menubar.add_cascade(label="Help", menu=helpmenu)
228256

229-
window.config(menu=menubar)
257+
window.config(menu=menubar, bg=bg_color)
230258
window._widgets = {}
231259

232-
notebook = AutoresizableNotebook(window)
260+
# Create header frame
261+
header_frame = _tkinter.Frame(window, bg=bg_color, height=60)
262+
header_frame.pack(fill=_tkinter.X, pady=(0, 5))
263+
header_frame.pack_propagate(0)
233264

234-
first = None
235-
frames = {}
265+
# Add header label
266+
title_label = _tkinter.Label(header_frame, text="Configuration",
267+
font=('Helvetica', 14),
268+
fg=accent_color, bg=bg_color)
269+
title_label.pack(side=_tkinter.LEFT, padx=15)
236270

237-
for group in parser.option_groups:
238-
frame = frames[group.title] = _tkinter.Frame(notebook, width=200, height=200)
239-
notebook.add(frames[group.title], text=group.title)
271+
# Add run button in header
272+
run_button = _tkinter_ttk.Button(header_frame, text="Run", command=run, width=12)
273+
run_button.pack(side=_tkinter.RIGHT, padx=15)
274+
275+
# Create notebook
276+
notebook = _tkinter_ttk.Notebook(window)
277+
notebook.pack(expand=1, fill="both", padx=5, pady=(0, 5))
240278

241-
_tkinter.Label(frame).grid(column=0, row=0, sticky=_tkinter.W)
279+
# Store tab information for background loading
280+
tab_frames = {}
281+
tab_canvases = {}
282+
tab_scrollable_frames = {}
283+
tab_groups = {}
284+
285+
# Create empty tabs with scrollable areas first (fast)
286+
for group in parser.option_groups:
287+
# Create a frame with scrollbar for the tab
288+
tab_frame = _tkinter.Frame(notebook, bg=bg_color)
289+
tab_frames[group.title] = tab_frame
290+
291+
# Create a canvas with scrollbar
292+
canvas = _tkinter.Canvas(tab_frame, bg=bg_color, highlightthickness=0)
293+
scrollbar = _tkinter_ttk.Scrollbar(tab_frame, orient="vertical", command=canvas.yview)
294+
scrollable_frame = _tkinter.Frame(canvas, bg=bg_color)
295+
296+
# Store references
297+
tab_canvases[group.title] = canvas
298+
tab_scrollable_frames[group.title] = scrollable_frame
299+
tab_groups[group.title] = group
300+
301+
# Configure the canvas scrolling
302+
scrollable_frame.bind(
303+
"<Configure>",
304+
lambda e, canvas=canvas: canvas.configure(scrollregion=canvas.bbox("all"))
305+
)
306+
307+
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
308+
canvas.configure(yscrollcommand=scrollbar.set)
309+
310+
# Pack the canvas and scrollbar
311+
canvas.pack(side="left", fill="both", expand=True)
312+
scrollbar.pack(side="right", fill="y")
313+
314+
# Add the tab to the notebook
315+
notebook.add(tab_frame, text=group.title)
316+
317+
# Add a loading indicator
318+
loading_label = _tkinter.Label(scrollable_frame, text="Loading options...",
319+
font=('Helvetica', 12),
320+
fg=accent_color, bg=bg_color)
321+
loading_label.pack(expand=True)
322+
323+
# Function to populate a tab in the background
324+
def populate_tab(tab_name):
325+
group = tab_groups[tab_name]
326+
scrollable_frame = tab_scrollable_frames[tab_name]
327+
canvas = tab_canvases[tab_name]
328+
329+
# Remove loading indicator
330+
for child in scrollable_frame.winfo_children():
331+
child.destroy()
332+
333+
# Add content to the scrollable frame
334+
row = 0
242335

243-
row = 1
244336
if group.get_description():
245-
_tkinter.Label(frame, text="%s:" % group.get_description()).grid(column=0, row=1, columnspan=3, sticky=_tkinter.W)
246-
_tkinter.Label(frame).grid(column=0, row=2, sticky=_tkinter.W)
247-
row += 2
337+
desc_label = _tkinter.Label(scrollable_frame, text=group.get_description(),
338+
wraplength=600, justify="left",
339+
font=('Helvetica', 9),
340+
fg="#555555", bg=bg_color)
341+
desc_label.grid(row=row, column=0, columnspan=3, sticky="w", padx=10, pady=(10, 5))
342+
row += 1
248343

249344
for option in group.option_list:
250-
_tkinter.Label(frame, text="%s " % parser.formatter._format_option_strings(option)).grid(column=0, row=row, sticky=_tkinter.W)
251-
345+
# Option label
346+
option_label = _tkinter.Label(scrollable_frame,
347+
text=parser.formatter._format_option_strings(option) + ":",
348+
font=('Helvetica', 9),
349+
fg=fg_color, bg=bg_color,
350+
anchor="w")
351+
option_label.grid(row=row, column=0, sticky="w", padx=10, pady=2)
352+
353+
# Input widget
252354
if option.type == "string":
253-
widget = _tkinter.Entry(frame)
355+
widget = _tkinter.Entry(scrollable_frame, font=('Helvetica', 9),
356+
relief="sunken", bd=1, width=20)
357+
widget.grid(row=row, column=1, sticky="w", padx=5, pady=2)
254358
elif option.type == "float":
255-
widget = ConstrainedEntry(frame, regex=r"\A\d*\.?\d*\Z")
359+
widget = ConstrainedEntry(scrollable_frame, regex=r"\A\d*\.?\d*\Z",
360+
font=('Helvetica', 9),
361+
relief="sunken", bd=1, width=10)
362+
widget.grid(row=row, column=1, sticky="w", padx=5, pady=2)
256363
elif option.type == "int":
257-
widget = ConstrainedEntry(frame, regex=r"\A\d*\Z")
364+
widget = ConstrainedEntry(scrollable_frame, regex=r"\A\d*\Z",
365+
font=('Helvetica', 9),
366+
relief="sunken", bd=1, width=10)
367+
widget.grid(row=row, column=1, sticky="w", padx=5, pady=2)
258368
else:
259369
var = _tkinter.IntVar()
260-
widget = _tkinter.Checkbutton(frame, variable=var)
370+
widget = _tkinter.Checkbutton(scrollable_frame, variable=var,
371+
bg=bg_color, activebackground=bg_color)
261372
widget.var = var
373+
widget.grid(row=row, column=1, sticky="w", padx=5, pady=2)
374+
375+
# Help text (truncated to improve performance)
376+
help_text = option.help
377+
if len(help_text) > 100:
378+
help_text = help_text[:100] + "..."
262379

263-
first = first or widget
264-
widget.grid(column=1, row=row, sticky=_tkinter.W)
380+
help_label = _tkinter.Label(scrollable_frame, text=help_text,
381+
font=('Helvetica', 8),
382+
fg="#666666", bg=bg_color,
383+
wraplength=400, justify="left")
384+
help_label.grid(row=row, column=2, sticky="w", padx=5, pady=2)
265385

386+
# Store widget reference
266387
window._widgets[(option.dest, option.type)] = widget
267388

389+
# Set default value
268390
default = defaults.get(option.dest)
269391
if default:
270392
if hasattr(widget, "insert"):
271393
widget.insert(0, default)
272-
273-
_tkinter.Label(frame, text=" %s" % option.help).grid(column=2, row=row, sticky=_tkinter.W)
394+
elif hasattr(widget, "var"):
395+
widget.var.set(1 if default else 0)
274396

275397
row += 1
276398

277-
_tkinter.Label(frame).grid(column=0, row=row, sticky=_tkinter.W)
399+
# Add some padding at the bottom
400+
_tkinter.Label(scrollable_frame, bg=bg_color, height=1).grid(row=row, column=0)
401+
402+
# Update the scroll region after adding all widgets
403+
canvas.update_idletasks()
404+
canvas.configure(scrollregion=canvas.bbox("all"))
405+
406+
# Update the UI to show the tab is fully loaded
407+
window.update_idletasks()
408+
409+
# Function to populate tabs in the background
410+
def populate_tabs_background():
411+
for tab_name in tab_groups.keys():
412+
# Schedule each tab to be populated with a small delay between them
413+
window.after(100, lambda name=tab_name: populate_tab(name))
414+
415+
# Start populating tabs in the background after a short delay
416+
window.after(500, populate_tabs_background)
278417

279-
notebook.pack(expand=1, fill="both")
280-
notebook.enable_traversal()
418+
# Set minimum window size
419+
window.update()
420+
window.minsize(800, 500)
281421

282-
first.focus()
422+
# Center the window on screen
423+
center(window)
283424

425+
# Start the GUI
284426
window.mainloop()

lib/core/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from thirdparty import six
2020

2121
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
22-
VERSION = "1.9.9.3"
22+
VERSION = "1.9.9.4"
2323
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
2424
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
2525
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

0 commit comments

Comments
 (0)