#!/usr/bin/env python3 """ DarkHal 2.0 Splash Screen A professional splash screen with logo, disclaimers, and loading animation. """ import tkinter as tk from tkinter import ttk import os import sys import time import threading from pathlib import Path try: from PIL import Image, ImageTk PIL_AVAILABLE = True except ImportError: PIL_AVAILABLE = False class SplashScreen: """Professional splash screen for DarkHal 2.0""" def __init__(self, callback=None): """ Initialize splash screen. Args: callback (callable): Function to call when splash closes with selected hardware acceleration """ self.callback = callback self.selected_acceleration = None self.root = tk.Tk() self.showing_logo = True # References for dynamic logo sizing self.logo_original = None # PIL.Image (original) self.logo_photo = None # ImageTk.PhotoImage or tk.PhotoImage (current) self.logo_label = None # tk.Label showing the logo # References for dynamic logo sizing self.logo_original = None # PIL.Image (original) self.logo_photo = None # ImageTk.PhotoImage or tk.PhotoImage (current) self.logo_label = None # tk.Label that displays the logo # References for dynamic logo sizing self.logo_original = None # PIL.Image (original) self.logo_photo = None # ImageTk.PhotoImage or tk.PhotoImage (current) self.logo_label = None # tk.Label showing the logo self.setup_window() self.create_logo_screen() # Switch to main screen after 2.5 seconds self.root.after(2500, self.switch_to_main_screen) def setup_window(self): """Configure the splash window""" # Remove window decorations self.root.overrideredirect(True) # Set window size - larger to accommodate all elements width = 700 height = 600 # Center on screen screen_width = self.root.winfo_screenwidth() screen_height = self.root.winfo_screenheight() x = (screen_width - width) // 2 y = (screen_height - height) // 2 self.root.geometry(f"{width}x{height}+{x}+{y}") self.root.configure(bg='#1a1a1a') # Dark background # Make window topmost self.root.attributes('-topmost', True) # Set window icon if available try: icon_path = Path("assets/Halico.ico") if icon_path.exists(): self.root.iconbitmap(str(icon_path)) except: pass def load_logo(self): """Load and prepare the logo image""" logo_path = Path("assets/logo.png") print(f"Looking for logo at: {logo_path.absolute()}") print(f"Logo exists: {logo_path.exists()}") print(f"PIL available: {PIL_AVAILABLE}") if not logo_path.exists(): print("Logo file not found") return None try: if PIL_AVAILABLE: # Use Pillow for better image handling image = Image.open(logo_path) print(f"Original image size: {image.size}") # Resize to fit in the fixed 75x75 box image = image.resize((65, 65), Image.Resampling.LANCZOS) print(f"Resized image to: {image.size}") return ImageTk.PhotoImage(image) else: # Fallback to tkinter's basic image support return tk.PhotoImage(file=str(logo_path)) except Exception as e: print(f"Error loading logo: {e}") return None def create_logo_screen(self): """Create the initial logo-only screen""" # Clear any existing widgets for widget in self.root.winfo_children(): widget.destroy() # Center container for logo center_frame = tk.Frame(self.root, bg='#1a1a1a') center_frame.pack(expand=True, fill=tk.BOTH) logo_path = Path("assets/logo.png") # Dynamic path if PIL available, else static fallback if PIL_AVAILABLE: self.logo_original = self._load_logo_original() if self.logo_original is not None: # Create label and center it; image set during update self.logo_label = tk.Label(center_frame, bg='#1a1a1a', borderwidth=0, highlightthickness=0) self.logo_label.place(relx=0.5, rely=0.5, anchor=tk.CENTER) # Bind window resize to keep logo responsive self.root.bind("", self.update_logo_size) # Initial sizing self.update_logo_size() return elif logo_path.exists(): # PIL present but image failed -> fallback to static display using tk.PhotoImage try: self.logo_photo = tk.PhotoImage(file=str(logo_path)) self.logo_label = tk.Label(center_frame, image=self.logo_photo, bg='#1a1a1a') self.logo_label.place(relx=0.5, rely=0.5, anchor=tk.CENTER) return except Exception: pass else: # No PIL -> static display if possible if logo_path.exists(): try: self.logo_photo = tk.PhotoImage(file=str(logo_path)) self.logo_label = tk.Label(center_frame, image=self.logo_photo, bg='#1a1a1a') self.logo_label.place(relx=0.5, rely=0.5, anchor=tk.CENTER) return except Exception: pass # Fallback - large app name logo_text = tk.Label(center_frame, text="DarkHal 2.0", font=("Arial", 48, "bold"), fg='#00ff88', bg='#1a1a1a') logo_text.place(relx=0.5, rely=0.5, anchor=tk.CENTER) def load_logo_large(self): """Load logo at original size for logo screen""" logo_path = Path("assets/logo.png") if not logo_path.exists(): return None try: if PIL_AVAILABLE: image = Image.open(logo_path) # Keep original size or resize to reasonable splash size max_size = min(300, min(image.size)) image = image.resize((max_size, max_size), Image.Resampling.LANCZOS) return ImageTk.PhotoImage(image) else: return tk.PhotoImage(file=str(logo_path)) except Exception as e: print(f"Error loading large logo: {e}") return None def switch_to_main_screen(self): """Switch from logo screen to main text screen""" self.showing_logo = False # Stop handling resize events once the logo screen ends try: self.root.unbind("") except Exception: pass # Stop handling resize events once the logo screen ends try: self.root.unbind("") except Exception: pass try: self.root.unbind("") except Exception: pass self.create_widgets() def create_widgets(self): """Create the main text-only screen with buttons""" # Clear any existing widgets for widget in self.root.winfo_children(): widget.destroy() # Main container main_frame = tk.Frame(self.root, bg='#1a1a1a') main_frame.pack(fill=tk.BOTH, expand=True, padx=30, pady=20) # Application name title_label = tk.Label( main_frame, text="DarkHal 2.0", font=("Arial", 24, "bold"), fg='#00ff88', # Green accent color bg='#1a1a1a' ) title_label.pack(pady=(0, 5)) # Subtitle subtitle_label = tk.Label( main_frame, text="AI Model Management & Training Platform", font=("Arial", 11), fg='#cccccc', bg='#1a1a1a' ) subtitle_label.pack(pady=(0, 15)) # Warning/Disclaimer section warning_frame = tk.Frame(main_frame, bg='#2a2a2a', relief=tk.RAISED, bd=1) warning_frame.pack(fill=tk.X, pady=(0, 15)) warning_title = tk.Label( warning_frame, text="⚠️ IMPORTANT WARNING", font=("Arial", 10, "bold"), fg='#ff4444', bg='#2a2a2a' ) warning_title.pack(pady=(8, 5)) warning_text = """This software is provided "as is" without any warranties or guarantees. The user assumes all responsibility for the use of this software and any consequences that may arise from its use. The developers are not liable for any damages, data loss, or other issues that may occur.""" warning_label = tk.Label( warning_frame, text=warning_text, font=("Arial", 9), fg='#cccccc', bg='#2a2a2a', wraplength=600, justify=tk.CENTER ) warning_label.pack(pady=(0, 8)) # Terms agreement section terms_frame = tk.Frame(main_frame, bg='#1a1a1a') terms_frame.pack(pady=(10, 15)) terms_label = tk.Label( terms_frame, text="By continuing you agree to our terms", font=("Arial", 10), fg='#ffaa00', bg='#1a1a1a' ) terms_label.pack() # Agreement section agreement_frame = tk.Frame(main_frame, bg='#1a1a1a') agreement_frame.pack(pady=(10, 20)) agreement_label = tk.Label( agreement_frame, text="I agree", font=("Arial", 12, "bold"), fg='#00ff88', bg='#1a1a1a' ) agreement_label.pack(pady=(0, 15)) # Hardware acceleration buttons buttons_frame = tk.Frame(agreement_frame, bg='#1a1a1a') buttons_frame.pack() # CUDA button cuda_btn = tk.Button( buttons_frame, text="Start with CUDA", font=("Arial", 11, "bold"), bg='#00aa55', fg='white', activebackground='#00ff88', activeforeground='white', relief=tk.RAISED, bd=2, padx=20, pady=8, command=lambda: self.start_application('cuda') ) cuda_btn.pack(side=tk.LEFT, padx=(0, 10)) # Intel button intel_btn = tk.Button( buttons_frame, text="Start with Intel", font=("Arial", 11, "bold"), bg='#0078d4', fg='white', activebackground='#106ebe', activeforeground='white', relief=tk.RAISED, bd=2, padx=20, pady=8, command=lambda: self.start_application('intel') ) intel_btn.pack(side=tk.LEFT, padx=5) # CPU button cpu_btn = tk.Button( buttons_frame, text="Start with CPU", font=("Arial", 11, "bold"), bg='#666666', fg='white', activebackground='#888888', activeforeground='white', relief=tk.RAISED, bd=2, padx=20, pady=8, command=lambda: self.start_application('cpu') ) cpu_btn.pack(side=tk.LEFT, padx=(10, 0)) # Copyright section at bottom copyright_frame = tk.Frame(main_frame, bg='#1a1a1a') copyright_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=(20, 0)) copyright_label = tk.Label( copyright_frame, text="© 2025 Setec Labs", font=("Arial", 9, "bold"), fg='#888888', bg='#1a1a1a' ) copyright_label.pack(side=tk.LEFT) author_label = tk.Label( copyright_frame, text="by ssSnake", font=("Arial", 9, "italic"), fg='#888888', bg='#1a1a1a' ) author_label.pack(side=tk.RIGHT) def start_application(self, acceleration_type): """Start the application with selected hardware acceleration""" self.selected_acceleration = acceleration_type print(f"Starting DarkHal 2.0 with {acceleration_type.upper()} acceleration...") self.close_splash() def close_splash(self): """Close the splash screen and call callback""" self.root.destroy() if self.callback: self.callback(self.selected_acceleration) def show(self): """Show the splash screen""" self.root.mainloop() # --- Dynamic logo helpers --- def _load_logo_original(self): """Load the original logo as a PIL Image (RGBA) without resizing.""" logo_path = Path("assets/logo.png") if not logo_path.exists(): return None try: image = Image.open(logo_path) return image.convert("RGBA") except Exception as e: print(f"Error loading original logo: {e}") return None def update_logo_size(self, event=None): """Resize the logo image dynamically to match the window size.""" if not self.showing_logo: return if self.logo_label is None or self.logo_original is None: return try: # Current window size win_w = max(1, self.root.winfo_width()) win_h = max(1, self.root.winfo_height()) # Target size: fraction of shortest side target_box = int(min(win_w, win_h) * 0.45) # Clamp to reasonable bounds target_box = max(96, min(512, target_box)) ow, oh = self.logo_original.size scale = min(target_box / ow, target_box / oh) new_w = max(1, int(ow * scale)) new_h = max(1, int(oh * scale)) resized = self.logo_original.resize((new_w, new_h), Image.Resampling.LANCZOS) self.logo_photo = ImageTk.PhotoImage(resized) self.logo_label.configure(image=self.logo_photo) except Exception as e: print(f"Error dynamically resizing logo: {e}") """Resize the logo to fit dynamically within the current window size.""" if not self.showing_logo: return # Only active on the logo screen if self.logo_label is None or self.logo_original is None: return try: # Current window size win_w = max(1, self.root.winfo_width()) win_h = max(1, self.root.winfo_height()) # Target box as a fraction of the shortest side target_box = int(min(win_w, win_h) * 0.45) # Clamp to reasonable bounds target_box = max(96, min(512, target_box)) ow, oh = self.logo_original.size scale = min(target_box / ow, target_box / oh) new_w = max(1, int(ow * scale)) new_h = max(1, int(oh * scale)) # Resize with high-quality resampling resized = self.logo_original.resize((new_w, new_h), Image.Resampling.LANCZOS) self.logo_photo = ImageTk.PhotoImage(resized) self.logo_label.configure(image=self.logo_photo) except Exception as e: print(f"Error dynamically resizing logo: {e}") class SplashManager: """Manager for showing splash screen and launching main application""" def __init__(self, main_app_callback=None): """ Initialize splash manager. Args: main_app_callback (callable): Function to call when splash closes with acceleration type """ self.main_app_callback = main_app_callback def show_splash_and_launch(self): """Show splash screen then launch main application""" splash = SplashScreen(callback=self.launch_main_app) splash.show() def launch_main_app(self, acceleration_type): """Launch the main application after splash""" if self.main_app_callback: self.main_app_callback(acceleration_type) else: print(f"DarkHal 2.0 ready with {acceleration_type.upper() if acceleration_type else 'default'} acceleration!") def demo_main_app(acceleration_type): """Demo main application for testing""" root = tk.Tk() root.title(f"DarkHal 2.0 - Main Application ({acceleration_type.upper()})") root.geometry("800x600") label = tk.Label(root, text=f"Welcome to DarkHal 2.0!\nRunning with {acceleration_type.upper()} acceleration", font=("Arial", 16), justify=tk.CENTER) label.pack(expand=True) root.mainloop() def main(): """Main entry point for testing splash screen""" print("Starting DarkHal 2.0 with splash screen...") # Create splash manager splash_manager = SplashManager(main_app_callback=demo_main_app) # Show splash and launch app splash_manager.show_splash_and_launch() if __name__ == "__main__": main()