diff --git a/ui/__pycache__/ai_training_window.cpython-310.pyc b/ui/__pycache__/ai_training_window.cpython-310.pyc index 38a17be..2186b2b 100644 Binary files a/ui/__pycache__/ai_training_window.cpython-310.pyc and b/ui/__pycache__/ai_training_window.cpython-310.pyc differ diff --git a/ui/__pycache__/analytics_window.cpython-310.pyc b/ui/__pycache__/analytics_window.cpython-310.pyc index f5baf47..7188e1a 100644 Binary files a/ui/__pycache__/analytics_window.cpython-310.pyc and b/ui/__pycache__/analytics_window.cpython-310.pyc differ diff --git a/ui/__pycache__/hash_cracker_window.cpython-310.pyc b/ui/__pycache__/hash_cracker_window.cpython-310.pyc index c83357f..f89db3a 100644 Binary files a/ui/__pycache__/hash_cracker_window.cpython-310.pyc and b/ui/__pycache__/hash_cracker_window.cpython-310.pyc differ diff --git a/ui/__pycache__/hybrid_attack_window.cpython-310.pyc b/ui/__pycache__/hybrid_attack_window.cpython-310.pyc index 3cb9e3d..e6532ff 100644 Binary files a/ui/__pycache__/hybrid_attack_window.cpython-310.pyc and b/ui/__pycache__/hybrid_attack_window.cpython-310.pyc differ diff --git a/ui/__pycache__/launcher.cpython-310.pyc b/ui/__pycache__/launcher.cpython-310.pyc index 0cfddcb..335f865 100644 Binary files a/ui/__pycache__/launcher.cpython-310.pyc and b/ui/__pycache__/launcher.cpython-310.pyc differ diff --git a/ui/__pycache__/nav_manager.cpython-310.pyc b/ui/__pycache__/nav_manager.cpython-310.pyc index e1a2d67..7a3acf0 100644 Binary files a/ui/__pycache__/nav_manager.cpython-310.pyc and b/ui/__pycache__/nav_manager.cpython-310.pyc differ diff --git a/ui/__pycache__/rainbow_table_window.cpython-310.pyc b/ui/__pycache__/rainbow_table_window.cpython-310.pyc index dbfcb14..c98668b 100644 Binary files a/ui/__pycache__/rainbow_table_window.cpython-310.pyc and b/ui/__pycache__/rainbow_table_window.cpython-310.pyc differ diff --git a/ui/__pycache__/reports_window.cpython-310.pyc b/ui/__pycache__/reports_window.cpython-310.pyc index d61f3e7..0dd40cf 100644 Binary files a/ui/__pycache__/reports_window.cpython-310.pyc and b/ui/__pycache__/reports_window.cpython-310.pyc differ diff --git a/ui/__pycache__/rule_engine_window.cpython-310.pyc b/ui/__pycache__/rule_engine_window.cpython-310.pyc index 00dafe6..944a442 100644 Binary files a/ui/__pycache__/rule_engine_window.cpython-310.pyc and b/ui/__pycache__/rule_engine_window.cpython-310.pyc differ diff --git a/ui/__pycache__/wordlist_generator_window.cpython-310.pyc b/ui/__pycache__/wordlist_generator_window.cpython-310.pyc index 22738a6..aff97d6 100644 Binary files a/ui/__pycache__/wordlist_generator_window.cpython-310.pyc and b/ui/__pycache__/wordlist_generator_window.cpython-310.pyc differ diff --git a/ui/ai_training_window.py b/ui/ai_training_window.py index 54604ae..fe38a08 100644 --- a/ui/ai_training_window.py +++ b/ui/ai_training_window.py @@ -49,7 +49,7 @@ def _build_titlebar(self): def _build_body(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(14, 0)) + frame.pack(fill="x", padx=16, pady=(12, 0)) tk.Label(frame, text="TRAINING WORDLIST", @@ -79,7 +79,7 @@ def _build_body(self): tk.Label(frame, text="MODEL STATS", bg=BG_DARK, fg=FG_MUTED, font=("Courier", 8)).pack( - anchor="w", pady=(14, 4)) + anchor="w", pady=(12, 4)) self.stat_vars = { "Trained on": tk.StringVar(value="0"), @@ -107,22 +107,22 @@ def _build_body(self): bg=BG_CARD, fg=colors.get(label, FG_BLUE), font=("Courier",14,"bold") - ).pack(pady=(8,2)) + ).pack(pady=(12,6)) tk.Label(card, text=label, bg=BG_CARD, fg=FG_MUTED, font=("Courier",8) - ).pack(pady=(0,8)) + ).pack(pady=(0,12)) # Progress self.progress = ttk.Progressbar( frame, mode="determinate", maximum=100, value=0) - self.progress.pack(fill="x", pady=(12,0)) + self.progress.pack(fill="x", pady=(16,0)) self.prog_label = tk.Label( frame, text="0% · waiting...", bg=BG_DARK, fg=FG_MUTED, font=("Courier",8)) - self.prog_label.pack(anchor="w", pady=2) + self.prog_label.pack(anchor="w", pady=4) def _browse(self): path = filedialog.askopenfilename( @@ -133,7 +133,7 @@ def _browse(self): def _build_buttons(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10,6)) + frame.pack(fill="x", padx=16, pady=(10, 8)) self.train_btn = tk.Button( frame, @@ -144,7 +144,7 @@ def _build_buttons(self): command=self._train) self.train_btn.pack(side="left", expand=True, fill="x", padx=(0,6), - ipady=10) + ipady=11) tk.Button(frame, text="Reset Models", bg=BG_DARK, fg=FG_RED, @@ -174,7 +174,7 @@ def _build_statusbar(self): def _build_log(self): frame = tk.Frame(self, bg=BG_DARK) frame.pack(fill="both", expand=True, - padx=16, pady=(6,4)) + padx=16, pady=(6,8)) tk.Label(frame, text="TRAINING LOG", bg=BG_DARK, fg=FG_MUTED, font=("Courier",8)).pack( diff --git a/ui/analytics_window.py b/ui/analytics_window.py index 050ac3f..0a1099f 100644 --- a/ui/analytics_window.py +++ b/ui/analytics_window.py @@ -136,7 +136,7 @@ def _build_titlebar(self): def _build_input_row(self): frame = tk.Frame(self, bg=BG_DARK) frame.pack(fill="x", padx=16, - pady=(10, 0)) + pady=(12, 0)) tk.Label(frame, text="LOAD RESULTS — browse a " @@ -196,7 +196,7 @@ def _browse_csv(self): def _build_summary_cards(self): frame = tk.Frame(self, bg=BG_DARK) frame.pack(fill="x", padx=16, - pady=(10, 0)) + pady=(12, 0)) self.summary_vars = { "Total": tk.StringVar(value="0"), @@ -238,8 +238,7 @@ def _build_summary_cards(self): # ── Charts area ─────────────────────────────────── def _build_charts_area(self): outer = tk.Frame(self, bg=BG_DARK) - outer.pack(fill="x", padx=16, - pady=(10, 0)) + outer.pack(fill="x", padx=16, pady=(12, 0)) # Fixed height section outer.columnconfigure(0, weight=1) outer.columnconfigure(1, weight=1) outer.columnconfigure(2, weight=1) @@ -307,8 +306,7 @@ def _build_charts_area(self): # ── Top passwords + password tester ─────────────── def _build_top_passwords(self): outer = tk.Frame(self, bg=BG_DARK) - outer.pack(fill="x", padx=16, - pady=(10, 0)) + outer.pack(fill="both", expand=True, padx=16, pady=(12, 0)) outer.columnconfigure(0, weight=1) outer.columnconfigure(1, weight=1) @@ -353,7 +351,7 @@ def _build_top_passwords(self): columns=cols, show="headings", style="Analytics.Treeview", - height=6) + height=8) # Increased from 6 for col, txt, w in [ ("rank", "#", 30), @@ -460,8 +458,7 @@ def _build_top_passwords(self): # ── Buttons ─────────────────────────────────────── def _build_buttons(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, - pady=(10, 6)) + frame.pack(fill="x", padx=16, pady=(10, 8)) self.analyse_btn = tk.Button( frame, @@ -663,7 +660,7 @@ def _draw_bar_chart(self, canvas, colors: dict, max_val: int): canvas.delete("all") - canvas.update_idletasks() + # canvas.update_idletasks() - Removed to prevent mid-transition flickers w = canvas.winfo_width() or 300 h = 140 bar_h = 16 diff --git a/ui/app_ui.py b/ui/app_ui.py index 03b754e..6db621b 100644 --- a/ui/app_ui.py +++ b/ui/app_ui.py @@ -52,7 +52,8 @@ def start_cracking(hash_entry, wl_entry, output_text): def open_cracker_window(parent): """Opens the hash cracker as a child window from the launcher.""" - win = tk.Toplevel(parent) # ← fixed: tk.Toplevel not Tk.Toplevel + win = tk.Toplevel(parent) + win.withdraw() win.title("Hash Cracker") win.configure(padx=16, pady=16) build_ui(win) \ No newline at end of file diff --git a/ui/hash_cracker_window.py b/ui/hash_cracker_window.py index cf29bc3..62744c8 100644 --- a/ui/hash_cracker_window.py +++ b/ui/hash_cracker_window.py @@ -146,7 +146,7 @@ def _build_algo_section(self): # ── Hash preview table ─────────────────────────────────── def _build_hash_preview(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 0)) + frame.pack(fill="x", padx=16, pady=(6, 0)) tk.Label(frame, text="LOADED HASHES — AUTO-DETECTED TYPE", @@ -170,7 +170,7 @@ def _build_hash_preview(self): cols = ("Hash Value", "Detected Algorithm", "Length") self.preview_tree = ttk.Treeview(frame, columns=cols, - show="headings", height=3) + show="headings", height=2) # Reduced from 3 self.preview_tree.heading("Hash Value", text="Hash Value") self.preview_tree.heading("Detected Algorithm", text="Detected Algorithm") self.preview_tree.heading("Length", text="Length") @@ -201,7 +201,7 @@ def _load_hashes(self): # ── Stats bar ──────────────────────────────────────────── def _build_stats_bar(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 0)) + frame.pack(fill="x", padx=16, pady=(8, 0)) # Reduced from 12 self.stat_vars = { "Total": tk.StringVar(value="0"), @@ -225,7 +225,7 @@ def _build_stats_bar(self): card.pack(side="left", expand=True, fill="x", padx=4) tk.Label(card, textvariable=var, bg=BG_CARD, fg=colors[label], - font=("Courier", 16, "bold")).pack(pady=(8, 2)) + font=("Courier", 14, "bold")).pack(pady=(6, 2)) # Reduced font from 16 and pady tk.Label(card, text=label, bg=BG_CARD, fg=FG_MUTED, font=("Courier", 8)).pack(pady=(0, 8)) @@ -256,7 +256,7 @@ def _build_progress(self): # ── Buttons — packed BEFORE results so always visible ──── def _build_buttons(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 6)) + frame.pack(fill="x", padx=16, pady=(8, 6)) # Tightened pady self.start_btn = tk.Button( frame, diff --git a/ui/hybrid_attack_window.py b/ui/hybrid_attack_window.py index ade6495..7f37d8a 100644 --- a/ui/hybrid_attack_window.py +++ b/ui/hybrid_attack_window.py @@ -108,7 +108,7 @@ def _build_titlebar(self): # ── File selectors ─────────────────────────────────────── def _build_files_section(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 0)) + frame.pack(fill="x", padx=16, pady=(12, 0)) for label, var in [ ("HASH FILE", self.hash_file), @@ -153,7 +153,7 @@ def _browse(self, var): # ── Stage indicators — single row 1×4 ──────────────────── def _build_stage_indicators(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 0)) + frame.pack(fill="x", padx=16, pady=(12, 0)) tk.Label(frame, text="ATTACK STAGES — RUNS IN ORDER", @@ -201,7 +201,7 @@ def _set_stage(self, name, state): # ── Mutation rules ─────────────────────────────────────── def _build_mutation_section(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 0)) + frame.pack(fill="x", padx=16, pady=(12, 0)) tk.Label(frame, text="MUTATION RULES", bg=BG_DARK, fg=FG_MUTED, @@ -258,7 +258,7 @@ def _toggle_rule(self, rule): # ── Brute force config ─────────────────────────────────── def _build_brute_config(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 0)) + frame.pack(fill="x", padx=16, pady=(12, 0)) tk.Label(frame, text="BRUTE FORCE CONFIG", bg=BG_DARK, fg=FG_MUTED, @@ -318,7 +318,7 @@ def _build_brute_config(self): # ── Stats bar ──────────────────────────────────────────── def _build_stats_bar(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 0)) + frame.pack(fill="x", padx=16, pady=(12, 0)) self.stat_vars = { "Total": tk.StringVar(value="0"), @@ -378,7 +378,7 @@ def _build_progress(self): # ── Buttons — packed BEFORE log ────────────────────────── def _build_buttons(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 6)) + frame.pack(fill="x", padx=16, pady=(10, 8)) # Start self.start_btn = tk.Button( @@ -395,7 +395,7 @@ def _build_buttons(self): command=self._start) self.start_btn.pack( side="left", expand=True, - fill="x", padx=(0, 6), ipady=10) + fill="x", padx=(0, 6), ipady=11) # Pause self.pause_btn = tk.Button( diff --git a/ui/launcher.py b/ui/launcher.py index 4923292..f42ca34 100644 --- a/ui/launcher.py +++ b/ui/launcher.py @@ -31,15 +31,15 @@ def __init__(self, parent, nav): def _build_header(self): # Container frame for logo and text header_container = tk.Frame(self, bg=BG_DARK) - header_container.pack(fill="x", pady=(20, 0), padx=20) + header_container.pack(fill="x", pady=(18, 10), padx=20) # Added top padding for balance # Logo placement try: logo_path = os.path.join("resources", "logo.png") if os.path.exists(logo_path): img = Image.open(logo_path) - # Larger size for better detail visibility - img = img.resize((120, 120), Image.LANCZOS) + # Smaller logo for vertical space + img = img.resize((50, 50), Image.LANCZOS) # Apply sharpening for crisp edges img = img.filter(ImageFilter.SHARPEN) self.logo_img = ImageTk.PhotoImage(img) @@ -81,7 +81,7 @@ def _build_header(self): info_btn.pack(side="right", anchor="n") tk.Frame(self, bg=BORDER, height=1).pack(fill="x", - padx=20, pady=14) + padx=20, pady=0) def _build_mode_selector(self): outer = tk.Frame(self, bg=BG_DARK) @@ -89,7 +89,7 @@ def _build_mode_selector(self): tk.Label(outer, text="SELECT MODE", bg=BG_DARK, fg=FG_MUTED, font=("Courier", 8)).pack( - anchor="w", pady=(0, 8)) + anchor="w", pady=(5, 5)) row = tk.Frame(outer, bg=BG_DARK) row.pack(fill="x") @@ -114,7 +114,7 @@ def _build_mode_selector(self): bg=BG_CARD, fg=FG_MUTED, font=("Courier", 8), justify="center" - ).pack(pady=(0, 10)) + ).pack(pady=(0, 6)) btn.bind("", lambda e, n=name: self._select_mode(n)) @@ -148,7 +148,7 @@ def _select_mode(self, name): def _build_module_grid(self): outer = tk.Frame(self, bg=BG_DARK) - outer.pack(fill="x", padx=20, pady=(16, 0)) + outer.pack(fill="x", padx=20, pady=(0, 0)) tk.Label(outer, text="OPEN MODULE", bg=BG_DARK, fg=FG_MUTED, font=("Courier", 8)).pack( @@ -193,10 +193,10 @@ def _build_module_grid(self): highlightbackground=BORDER, cursor="hand2") card.grid(row=i // 2, column=i % 2, - sticky="ew", padx=4, pady=4) + sticky="ew", padx=4, pady=2) inner = tk.Frame(card, bg=BG_CARD) - inner.pack(fill="x", padx=12, pady=10) + inner.pack(fill="x", padx=12, pady=6) tk.Label(inner, text=name, bg=BG_CARD, fg=FG_PRIMARY, @@ -226,7 +226,7 @@ def _build_module_grid(self): def _build_quick_start(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=20, pady=16) + frame.pack(fill="x", padx=20, pady=(2, 12)) tk.Button(frame, text="▶ Start Quick Crack", bg=BTN_BLUE, fg="#e0f0ff", @@ -236,12 +236,12 @@ def _build_quick_start(self): activeforeground="#ffffff", cursor="hand2", command=self._open_hash_cracker - ).pack(fill="x", ipady=10) + ).pack(fill="x", ipady=4) def _build_statusbar(self): bar = tk.Frame(self, bg=BG_CARD, - height=30) - bar.pack(fill="x", side="bottom") + height=28) + bar.pack(fill="x", side="bottom", pady=(0, 10)) # Added bottom padding for balance bar.pack_propagate(False) tk.Label(bar, text="●", bg=BG_CARD, fg=FG_GREEN, diff --git a/ui/nav_manager.py b/ui/nav_manager.py index 460a11a..ba26e3f 100644 --- a/ui/nav_manager.py +++ b/ui/nav_manager.py @@ -7,25 +7,51 @@ FG_PRIMARY = "#cbd5e1" FG_MUTED = "#64748b" FG_BLUE = "#7dd3fc" +BG_ACCENT = "#1e3a4a" BORDER = "#3a3a50" class NavigationManager(tk.Tk): def __init__(self): super().__init__() + self.withdraw() # Hide immediately to prevent launch flicker + self.title("CryptX v2.0") - self.geometry("900x750") - self.minsize(800, 700) + + self.width = 1100 + self.height = 750 + self.minsize(950, 500) self.configure(bg=BG_DARK) # History stack (list of frames) self.history = [] self.current_frame = None + + # View cache to make switching near-instant + self.views = {} self._init_ui() + def _center_window(self): + """Dynamic centering: snaps window height to content requirements.""" + self.update_idletasks() + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + + req_height = self.winfo_reqheight() + req_width = self.winfo_reqwidth() + + self.height = min(req_height + 4, screen_height - 80) + self.width = max(1100, min(req_width, screen_width - 40)) + + x = (screen_width // 2) - (self.width // 2) + y = (screen_height // 2) - (self.height // 2) + + y = max(20, y) + self.geometry(f"{self.width}x{self.height}+{x}+{y}") + def _init_ui(self): # ── Navbar (Header) ────── - self.navbar = tk.Frame(self, bg=BG_CARD, height=44) + self.navbar = tk.Frame(self, bg=BG_CARD, height=36) self.navbar.pack(fill="x") self.navbar.pack_propagate(False) @@ -42,7 +68,7 @@ def _init_ui(self): padx=15 ) self.back_btn.pack(side="left", fill="y") - self.back_btn.pack_forget() # Hide initially + self.back_btn.pack_forget() # App Title in Navbar self.title_label = tk.Label( @@ -54,38 +80,70 @@ def _init_ui(self): ) self.title_label.pack(side="left", padx=20) - # Main Container for views - self.container = tk.Frame(self, bg=BG_DARK) - self.container.pack(fill="both", expand=True) + # ── Main Container (Standard Frame) ────── + self.main_area = tk.Frame(self, bg=BG_DARK) + self.main_area.pack(fill="both", expand=True, padx=0, pady=0) def show_view(self, view_class, *args, **kwargs): - """Clears the current view and shows a new one. History is NOT pushed.""" + """High-performance view switcher with caching and smart state transitions.""" + target_name = view_class.__name__ + is_home = (target_name == "LauncherFrame") + + # 1. Determine if we need to hide the window + # We only withdraw if we are changing between 'zoomed' and 'normal' states + current_state = self.state() + target_state = "normal" if is_home else "zoomed" + needs_masking = (current_state != target_state) or (current_state == "withdrawn") + + if needs_masking and current_state != "withdrawn": + self.withdraw() + self.update_idletasks() + + # 2. Swap the frame (Optimized with caching) if self.current_frame: - self.current_frame.destroy() + # We don't destroy cached views, just unmap them + self.current_frame.pack_forget() + + if target_name in self.views: + self.current_frame = self.views[target_name] + else: + # Create and cache + self.current_frame = view_class(self.main_area, self, *args, **kwargs) + self.views[target_name] = self.current_frame - self.current_frame = view_class(self.container, self, *args, **kwargs) self.current_frame.pack(fill="both", expand=True) - # Update back button visibility + # 3. Update navigation state if self.history: self.back_btn.pack(side="left", fill="y") else: self.back_btn.pack_forget() + # 4. Handle State & Geometry + if is_home: + if self.state() == "zoomed": + self.state("normal") + self._center_window() + else: + if self.state() != "zoomed": + self.state("zoomed") + + # 5. Show window (Instant if no state change, otherwise fast reveal) + if needs_masking: + # Reduced delay to 50ms for snappy feel + self.after(50, lambda: ( + self.deiconify(), + self.lift(), + self.focus_force(), + self.update_idletasks() + )) + else: + self.update_idletasks() + self.lift() + self.focus_force() + def push_view(self, view_class, *args, **kwargs): """Pushes current view to history stack and shows new view.""" - # Note: In Tkinter, we might want to store the class and its state, - # but for simplicity, we destroy the old frame and just store the class for navigation back. - # If we need state preservation, we could hide instead of destroy. - - # Here we only store the "Home" view for now as we transition. - # Later, we can make it more generic. - if self.current_frame: - # We don't store the actual frame object usually because of resource management, - # but we can store the class type if we want to re-instantiate it. - # For this simple app, we just need a way to go back to Home. - pass - self.history.append(view_class) self.show_view(view_class, *args, **kwargs) @@ -94,12 +152,10 @@ def pop_view(self): if not self.history: return - self.history.pop() # Remove current + self.history.pop() if not self.history: - # Go back to launcher (Home) from ui.launcher import LauncherFrame self.show_view(LauncherFrame) else: prev_view = self.history[-1] - # Since we destroy frames to save resources, we re-instantiate. self.show_view(prev_view) diff --git a/ui/rainbow_table_window.py b/ui/rainbow_table_window.py index 8cffc44..3454e51 100644 --- a/ui/rainbow_table_window.py +++ b/ui/rainbow_table_window.py @@ -316,7 +316,7 @@ def _select_algo(self, algo): # ── Lookup bar ──────────────────────────────────── def _build_lookup_bar(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 0)) + frame.pack(fill="x", padx=16, pady=(12, 0)) tk.Label(frame, text="INSTANT LOOKUP — " @@ -404,7 +404,7 @@ def _lookup_hash(self): # ── Stats bar ───────────────────────────────────── def _build_stats_bar(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 0)) + frame.pack(fill="x", padx=16, pady=(12, 0)) self.stat_vars = { "Total entries": tk.StringVar(value="0"), @@ -463,7 +463,7 @@ def _build_progress(self): # ── Buttons ─────────────────────────────────────── def _build_buttons(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 6)) + frame.pack(fill="x", padx=16, pady=(10, 8)) self.build_btn = tk.Button( frame, @@ -479,7 +479,7 @@ def _build_buttons(self): command=self._build_table) self.build_btn.pack( side="left", expand=True, - fill="x", padx=(0, 6), ipady=10) + fill="x", padx=(0, 6), ipady=11) # increased ipady tk.Button(frame, text="Load Table", @@ -521,7 +521,7 @@ def _build_buttons(self): command=self._clear_all ).pack(side="left", expand=True, fill="x", padx=(3, 0), - ipady=10) + ipady=11) # ── Status bar ──────────────────────────────────── def _build_statusbar(self): diff --git a/ui/reports_window.py b/ui/reports_window.py index 39cefd1..ae7340f 100644 --- a/ui/reports_window.py +++ b/ui/reports_window.py @@ -66,7 +66,7 @@ def _build_titlebar(self): tk.Label(bar, bg=color, width=2).pack( side="left", padx=(8 if color == "#ff5f57" else 4, 0), - pady=10) + pady=7) tk.Label(bar, text="Window 8 — Reports & Logs · Compliance-ready audit trail", bg=BG_CARD, fg=FG_MUTED, @@ -108,7 +108,7 @@ def _build_summary_cards(self): # ── Main 2-column area ──────────────────────────── def _build_main_area(self): outer = tk.Frame(self, bg=BG_DARK) - outer.pack(fill="x", padx=16, pady=(10, 0)) + outer.pack(fill="both", expand=True, padx=16, pady=(12, 0)) outer.columnconfigure(0, weight=3) outer.columnconfigure(1, weight=2) @@ -149,7 +149,7 @@ def _build_session_log(self, parent): self.log_tree = ttk.Treeview(card, columns=cols, show="headings", style="Log.Treeview", - height=10) + height=8) # Reduced from 10 to fit vertical budget for col, txt, w in [ ("id", "#", 35), @@ -266,9 +266,6 @@ def _out(e, ent=entry, p=ph): btn.pack(side="left", padx=(0, 6)) self.fmt_btns[fmt] = btn - # ── FIX: guard so _update_preview is not called before - # preview_box exists (it is built in _build_preview, - # which runs after _build_main_area). self._select_format("TXT") tk.Label(inner, text="INCLUDE IN REPORT", @@ -290,7 +287,6 @@ def _out(e, ent=entry, p=ph): activeforeground=FG_BLUE, font=("Courier", 8)).pack(anchor="w") - # ── FIX: guard _update_preview until preview_box exists ────────── def _select_format(self, fmt): self.report_format.set(fmt) for f, btn in self.fmt_btns.items(): @@ -300,7 +296,7 @@ def _select_format(self, fmt): else: btn.configure(bg=BG_DARK, fg=FG_MUTED, highlightbackground=BORDER) - if self.preview_box is not None: # ← GUARD + if self.preview_box is not None: self._update_preview() # ── Report preview ──────────────────────────────── @@ -322,19 +318,16 @@ def _build_preview(self): font=("Courier", 9), relief="flat", state="disabled", - height=7, + height=5, padx=10, pady=8) - self.preview_box.pack(fill="x", expand=True) + self.preview_box.pack(fill="x", expand=False) - # Now that preview_box exists, do the first real preview render self._update_preview() for var in [self.analyst_var, self.target_var, self.scope_var]: var.trace_add("write", lambda *a: self._update_preview()) def _update_preview(self): - # Safety guard — should never be needed after the fix above, - # but kept as a belt-and-braces check. if self.preview_box is None: return diff --git a/ui/rule_engine_window.py b/ui/rule_engine_window.py index 8e617c6..4805db5 100644 --- a/ui/rule_engine_window.py +++ b/ui/rule_engine_window.py @@ -87,7 +87,7 @@ def _build_titlebar(self): tk.Label(bar, bg=color, width=2).pack( side="left", padx=(8 if color=="#ff5f57" else 4,0), - pady=10) + pady=8) tk.Label(bar, text="Window 5 — Rule Engine " "(Hashcat-compatible syntax)", @@ -98,7 +98,7 @@ def _build_titlebar(self): # ── File + ruleset selector ─────────────────────── def _build_files_section(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(12,0)) + frame.pack(fill="x", padx=16, pady=(12, 0)) row = tk.Frame(frame, bg=BG_DARK) row.pack(fill="x") @@ -168,7 +168,7 @@ def _load_preset(self, event=None): # ── Main 2-column area ──────────────────────────── def _build_main_area(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10,0)) + frame.pack(fill="both", expand=True, padx=16, pady=(12, 0)) frame.columnconfigure(0, weight=1) frame.columnconfigure(1, weight=1) @@ -238,9 +238,11 @@ def _build_main_area(self): self._add_token(t) ).pack(side="right", padx=4) - inner.update_idletasks() - canvas.configure( - scrollregion=canvas.bbox("all")) + # Delayed update ensures the scrollregion is calculated after the transition + self.after(200, lambda: ( + inner.update_idletasks(), + canvas.configure(scrollregion=canvas.bbox("all")) + )) # ── Right: rule editor + live preview ───────── right = tk.Frame(frame, bg=BG_DARK) @@ -401,8 +403,8 @@ def _update_live_preview(self): # ── Stats bar ───────────────────────────────────── def _build_stats_bar(self): - frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10,0)) + outer = tk.Frame(self, bg=BG_DARK) + outer.pack(fill="x", padx=16, pady=(12, 0)) self.stat_vars = { "Rules": tk.StringVar(value="0"), @@ -436,7 +438,7 @@ def _build_stats_bar(self): # ── Progress bar ────────────────────────────────── def _build_progress(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(8,0)) + frame.pack(fill="x", padx=16, pady=(6,0)) style = ttk.Style() style.theme_use("clam") @@ -459,7 +461,7 @@ def _build_progress(self): # ── Buttons ─────────────────────────────────────── def _build_buttons(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10,6)) + frame.pack(fill="x", padx=16, pady=(6,6)) self.apply_btn = tk.Button( frame, @@ -520,7 +522,7 @@ def _build_buttons(self): # ── Status bar ──────────────────────────────────── def _build_statusbar(self): bar = tk.Frame(self, bg=BG_CARD, - height=28) + height=25) bar.pack(fill="x", side="bottom") bar.pack_propagate(False) diff --git a/ui/wordlist_generator_window.py b/ui/wordlist_generator_window.py index 0c9bcb4..f50a4b3 100644 --- a/ui/wordlist_generator_window.py +++ b/ui/wordlist_generator_window.py @@ -86,7 +86,7 @@ def _build_titlebar(self): # ── Target info — 2 column grid ────────────────── def _build_target_section(self): outer = tk.Frame(self, bg=BG_DARK) - outer.pack(fill="x", padx=16, pady=(12, 0)) + outer.pack(fill="x", padx=16, pady=(16, 0)) tk.Label(outer, text="TARGET INFORMATION — fill what you know", @@ -190,7 +190,7 @@ def on_out(e, ent=entry, ph=placeholder): # ── Generation options ──────────────────────────── def _build_options_section(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 0)) + frame.pack(fill="x", padx=16, pady=(6, 0)) tk.Label(frame, text="GENERATION OPTIONS", bg=BG_DARK, fg=FG_MUTED, @@ -239,7 +239,7 @@ def _toggle_opt(self, opt): # ── Stats bar ───────────────────────────────────── def _build_stats_bar(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 0)) + frame.pack(fill="x", padx=16, pady=(12, 0)) self.stat_vars = { "Words": tk.StringVar(value="0"), @@ -301,7 +301,7 @@ def _build_progress(self): # ── Buttons ─────────────────────────────────────── def _build_buttons(self): frame = tk.Frame(self, bg=BG_DARK) - frame.pack(fill="x", padx=16, pady=(10, 6)) + frame.pack(fill="x", padx=16, pady=(8, 6)) # Tightened pady self.gen_btn = tk.Button( frame, @@ -317,7 +317,7 @@ def _build_buttons(self): command=self._generate) self.gen_btn.pack(side="left", expand=True, fill="x", padx=(0, 6), - ipady=10) + ipady=11) tk.Button(frame, text="Save to File", @@ -408,12 +408,12 @@ def _build_preview(self): self.preview_box = tk.Text( box_frame, - bg="#1a1a2e", fg=FG_PRIMARY, + bg="#0f0f1e", fg=FG_GREEN, font=("Courier", 10), relief="flat", state="disabled", - wrap="word", - padx=10, pady=8) + height=4, + padx=8, pady=6) sb = tk.Scrollbar(box_frame, command=self.preview_box.yview,