in this code option boxes are too small for their texts fix it , improve all graphics and add motional graphics and design too all of this and find all bugs and fix them "import random
import os
import sys
import tkinter as tk
from tkinter import messagebox, ttk


# ---------- Custom Button with Advanced Hover Effects ----------

class HoverButton(tk.Canvas):
    def __init__(self, master, width=600, height=60, corner_radius=15, padding=10,
                 bg_color="#E3F2FD", hover_color="#90CAF9", active_color="#1976D2",
                 text="", font=("Arial", 12, "bold"), command=None, **kwargs):
        super().__init__(master, width=width, height=height, highlightthickness=0, bg=master['bg'], **kwargs)
        self.width = width
        self.height = height
        self.corner_radius = corner_radius
        self.padding = padding
        self.bg_color = bg_color
        self.hover_color = hover_color
        self.active_color = active_color
        self.text = text
        self.font = font
        self.command = command
        self.current_color = bg_color

        # Create rounded rectangle
        self.rect = self.create_round_rect(0, 0, width, height, corner_radius, fill=self.bg_color, outline="")

        # Create text
        self.label = self.create_text(width / 2, height / 2, text=self.text, font=self.font, fill="black")

        # Bind events
        self.bind("<Enter>", self.on_enter)
        self.bind("<Leave>", self.on_leave)
        self.bind("<Button-1>", self.on_click)

    def create_round_rect(self, x1, y1, x2, y2, r=25, **kwargs):
        points = [
            x1 + r, y1,
            x1 + r, y1,
            x2 - r, y1,
            x2 - r, y1,
            x2, y1,
            x2, y1 + r,
            x2, y1 + r,
            x2, y2 - r,
            x2, y2 - r,
            x2, y2,
            x2 - r, y2,
            x2 - r, y2,
            x1 + r, y2,
            x1 + r, y2,
            x1, y2,
            x1, y2 - r,
            x1, y2 - r,
            x1, y1 + r,
            x1, y1 + r,
            x1, y1,
            x1 + r, y1
        ]
        return self.create_polygon(points, smooth=True, **kwargs)

    def on_enter(self, event):
        self.itemconfig(self.rect, fill=self.hover_color)
        # Start bounce animation
        self.bounce(True)

    def on_leave(self, event):
        self.itemconfig(self.rect, fill=self.bg_color)
        # Reset scale
        self.scale('all', self.width / 2, self.height / 2, 1, 1)

    def on_click(self, event):
        if self.command:
            self.command()

    def bounce(self, hover=True, step=0):
        # Simple bounce effect using scaling
        if step > 5:
            self.scale('all', self.width / 2, self.height / 2, 1, 1)
            return
        if hover:
            scale_factor = 1.05 if step % 2 == 0 else 0.95
        else:
            scale_factor = 1.0
        self.scale('all', self.width / 2, self.height / 2, scale_factor, scale_factor)
        self.after(50, lambda: self.bounce(hover, step + 1))

    def update_text(self, new_text):
        self.itemconfig(self.label, text=new_text)

    def set_state(self, state):
        if state == "disabled":
            self.itemconfig(self.rect, fill='#E0E0E0')
            self.itemconfig(self.label, fill="#A0A0A0")
            self.unbind("<Enter>")
            self.unbind("<Leave>")
            self.unbind("<Button-1>")
        else:
            self.itemconfig(self.rect, fill=self.bg_color)
            self.itemconfig(self.label, fill="black")
            self.bind("<Enter>", self.on_enter)
            self.bind("<Leave>", self.on_leave)
            self.bind("<Button-1>", self.on_click)


# ---------- Resource Path Helper ----------

def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS  # For PyInstaller
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)


# ---------- File Reading Functions ----------

def read_words_meanings(file_path):
    words = []
    meanings = []
    examples = []
    with open(file_path, 'r', encoding='utf-8') as file:
        content = file.read().strip().split('\n\n')
        for entry in content:
            lines = [line.strip() for line in entry.strip().split('\n') if line.strip()]
            if len(lines) < 3:
                print(f"Skipping entry due to incorrect format: {entry}")
                continue
            word = lines[0].replace(":", "").strip()
            meaning_line = lines[1]
            example_line = lines[2]
            if not meaning_line.startswith("Meaning: ") or not example_line.startswith("Example: "):
                print(f"Skipping entry due to incorrect format: {entry}")
                continue
            meaning = meaning_line.replace("Meaning: ", "").strip()
            example = example_line.replace("Example: ", "").strip()
            words.append(word)
            meanings.append(meaning)
            examples.append(example)
    return words, meanings, examples


def read_fun_facts_from_file(file_path):
    with open(file_path, 'r', encoding='utf-8') as file:
        fun_facts = [line.strip().strip('"').strip(',') for line in file if line.strip()]
    return fun_facts


# ---------- Utility Functions ----------

def funny_message(fun_facts):
    return random.choice(fun_facts)


def create_quiz(words, meanings, examples, num_questions):
    question_set = set()
    quiz = []
    while len(quiz) < num_questions and len(question_set) < len(words):
        index = random.randint(0, len(words) - 1)
        if index in question_set:
            continue
        question_set.add(index)
        word = words[index]
        meaning = meanings[index]
        example = examples[index]
        options = [meaning]
        wrong_meanings = random.sample([m for m in meanings if m != meaning], min(2, len(meanings) - 1))
        options.extend(wrong_meanings)
        random.shuffle(options)
        correct_index = options.index(meaning)
        quiz.append((word, options, example, correct_index))
    random.shuffle(quiz)
    return quiz


# ---------- Fade-In Animation Function ----------

def fade_in(widget, target="#1976D2", step=0, max_steps=10):
    if step > max_steps:
        return
    # Calculate intermediate color
    r_target, g_target, b_target = hex_to_rgb(target)
    r_current = int(r_target * (step / max_steps))
    g_current = int(g_target * (step / max_steps))
    b_current = int(b_target * (step / max_steps))
    intermediate_color = rgb_to_hex((r_current, g_current, b_current))
    try:
        widget.config(fg=intermediate_color)
    except:
        # If widget does not support 'fg', skip
        pass
    widget.after(50, lambda: fade_in(widget, target, step + 1, max_steps))


def hex_to_rgb(hex_color):
    hex_color = hex_color.lstrip('#')
    h_len = len(hex_color)
    return tuple(int(hex_color[i:i + h_len // 3], 16) for i in range(0, h_len, h_len // 3))


def rgb_to_hex(rgb_tuple):
    return '#%02x%02x%02x' % rgb_tuple


# ---------- Main Interface Functions ----------

def show_quiz_interface():
    global question_label, option1_button, option2_button, option3_button
    global joker_button, progress_bar, score_label, remaining_label, progress_var

    # Clear existing widgets
    for widget in root.winfo_children():
        widget.destroy()

    # Create container frame
    container = tk.Frame(root, bg="#f0f8ff")
    container.pack(expand=True, fill='both', padx=20, pady=20)

    # Create sub-frames for better layout management
    top_frame = tk.Frame(container, bg="#f0f8ff")
    top_frame.pack(fill='x', pady=(0, 20))

    middle_frame = tk.Frame(container, bg="#f0f8ff")
    middle_frame.pack(fill='x', pady=20)

    bottom_frame = tk.Frame(container, bg="#f0f8ff")
    bottom_frame.pack(fill='x', pady=(20, 0))

    # Question Label
    question_label = tk.Label(top_frame, text="Press Start to begin the quiz",
                              wraplength=800, justify="center",
                              font=("Helvetica", 18, "bold"), bg="#f0f8ff", fg="#1976D2")
    question_label.pack(pady=10)

    # Option Buttons Styling and Creation
    option1_button = HoverButton(middle_frame, width=600, height=60, corner_radius=15, text="Option 1",
                                 font=("Helvetica", 14), bg_color="#E3F2FD",
                                 hover_color="#90CAF9", active_color="#1976D2",
                                 command=lambda i=0: check_answer(i))
    option1_button.pack(pady=10)

    option2_button = HoverButton(middle_frame, width=600, height=60, corner_radius=15, text="Option 2",
                                 font=("Helvetica", 14), bg_color="#FFCDD2",  # Slightly different color
                                 hover_color="#EF9A9A", active_color="#D32F2F",
                                 command=lambda i=1: check_answer(i))
    option2_button.pack(pady=10)

    option3_button = HoverButton(middle_frame, width=600, height=60, corner_radius=15, text="Option 3",
                                 font=("Helvetica", 14), bg_color="#C8E6C9",  # Slightly different color
                                 hover_color="#A5D6A7", active_color="#388E3C",
                                 command=lambda i=2: check_answer(i))
    option3_button.pack(pady=10)

    # Control Buttons Styling
    control_style = {
        'font': ('Helvetica', 12, "bold"),
        'width': 15,
        'height': 1,
        'bg': '#2196F3',
        'fg': 'white',
        'activebackground': '#1976D2',
        'activeforeground': 'white',
        'relief': tk.FLAT,
        'bd': 0
    }

    # Joker Button
    joker_button = HoverButton(bottom_frame, width=180, height=50, corner_radius=15,
                               text="Use Joker", font=("Helvetica", 12, "bold"),
                               bg_color='#FFC107', hover_color='#FFB300', active_color='#FFA000',
                               command=use_joker)
    joker_button.pack(pady=5)

    # Start Quiz Button
    start_button = HoverButton(bottom_frame, width=180, height=50, corner_radius=15,
                               text="Start Quiz", font=("Helvetica", 12, "bold"),
                               bg_color='#4CAF50', hover_color='#43A047', active_color='#388E3C',
                               command=start_quiz)
    start_button.pack(pady=10)

    # Progress Bar Styling
    style = ttk.Style()
    style.theme_use('clam')
    style.configure("Custom.Horizontal.TProgressbar",
                    troughcolor='#E3F2FD',
                    background='#2196F3',
                    thickness=20)
    style.configure("TLabel", background="#f0f8ff", foreground="#1976D2", font=("Helvetica", 14, "bold"))

    # Progress Bar with Contextual Colors
    progress_var = tk.DoubleVar()
    progress_bar = ttk.Progressbar(bottom_frame,
                                   style="Custom.Horizontal.TProgressbar",
                                   variable=progress_var,
                                   maximum=100,
                                   length=300)
    progress_bar.pack(pady=10)

    # Score Label
    score_label = tk.Label(bottom_frame, text="Score: 0",
                           font=("Helvetica", 14, "bold"),
                           fg="#1976D2",
                           bg="#f0f8ff")
    score_label.pack(pady=5)

    # Remaining Questions Label
    remaining_label = tk.Label(bottom_frame, text="Remaining: 0",
                               font=("Helvetica", 14, "bold"),
                               fg="#1976D2",
                               bg="#f0f8ff")
    remaining_label.pack(pady=5)


def create_question_count_selection():
    # Clear any existing widgets
    for widget in root.winfo_children():
        widget.destroy()

    # Create main container with padding
    container = tk.Frame(root, bg="#f0f8ff")
    container.pack(expand=True, fill='both', padx=40, pady=40)

    # Title Label
    title_label = tk.Label(container,
                           text="How many questions would you like to answer?",
                           font=("Helvetica", 20, "bold"),
                           fg="#1976D2",
                           bg="#f0f8ff",
                           pady=20)
    title_label.pack()
    # Simulate fade-in by calling fade_in with text color
    # Note: Tkinter does not support widget-specific alpha, so we skip actual fade-in
    # fade_in(title_label)

    # Frame for Buttons
    button_frame = tk.Frame(container, bg="#f0f8ff")
    button_frame.pack(expand=True)

    # Button Styling and Creation
    button_style = {
        'width': 200,
        'height': 60,
        'corner_radius': 20,
        'font': ("Helvetica", 14, "bold"),
    }

    # Question Count Options with Different Colors
    questions_options = [
        {"count": 5, "bg": "#E3F2FD", "hover": "#90CAF9", "active": "#64B5F6"},
        {"count": 10, "bg": "#FFCDD2", "hover": "#EF9A9A", "active": "#E57373"},
        {"count": 15, "bg": "#C8E6C9", "hover": "#A5D6A7", "active": "#81C784"},
        {"count": 20, "bg": "#FFF9C4", "hover": "#FFF59D", "active": "#FFF176"},
    ]

    for option in questions_options:
        btn = HoverButton(button_frame,
                          width=600,
                          height=60,
                          corner_radius=20,
                          text=f"{option['count']} Questions",
                          font=("Helvetica", 14, "bold"),
                          bg_color=option['bg'],
                          hover_color=option['hover'],
                          active_color=option['active'],
                          command=lambda c=option['count']: select_question_count(c))
        btn.pack(pady=10)


# ---------- Quiz Logic Functions ----------

def select_question_count(count):
    global num_questions
    num_questions = count
    print(f"Selected number of questions: {num_questions}")
    show_quiz_interface()


def check_answer(selected_index):
    global question_number, score, quiz, joker_button_state
    word, options, example, correct_index = quiz[question_number]
    funny_threshold = 0.5
    funny = random.random() < funny_threshold

    # Disable all options temporarily
    disable_all_options()

    if selected_index == correct_index:
        score += 1
        feedback = "Correct!"
        color = "#C8E6C9"  # Greenish
        print(f"Question {question_number + 1}: Correct")
    else:
        score -= 1
        feedback = f"Wrong! The correct answer was: '{options[correct_index]}'."
        color = "#FFCDD2"  # Reddish
        print(
            f"Question {question_number + 1}: Wrong (Selected: {options[selected_index]}, Correct: {options[correct_index]})")

    # Highlight the selected and correct options
    if selected_index != correct_index:
        highlight_option(selected_index, "#FFCDD2")  # Wrong selection
    highlight_option(correct_index, "#C8E6C9")  # Correct answer

    # Show feedback
    message = f"{feedback}\n\nExample:\n{example}"
    if funny:
        message += f"\n\nFun Fact: {funny_message(fun_facts)}"
    messagebox.showinfo("Result", message)

    # Update score label
    calculate_score()

    question_number += 1
    administer_quiz()


def calculate_score():
    global score_label
    percentage = max(score, 0)  # Prevent negative scores
    rounded_percentage = round((percentage / len(quiz)) * 100) if len(quiz) > 0 else 0
    score_label.config(text=f"Score: {rounded_percentage}% ({score})")
    print(f"Updated Score: {score_label.cget('text')}")


def use_joker():
    global joker_used, joker_button_state
    if not joker_used and question_number < len(quiz):
        word, options, example, correct_index = quiz[question_number]
        print(f"Using Joker on Question {question_number + 1}: {word}")
        incorrect_indices = [i for i in range(len(options)) if i != correct_index]
        if incorrect_indices:
            option_to_remove = random.choice(incorrect_indices)
            disable_option_button(option_to_remove)
            joker_used = True
            joker_button.set_state("disabled")
            print(f"Joker used. Disabled option {option_to_remove + 1}")
    else:
        print("Joker cannot be used.")


def disable_option_button(index):
    if index == 0:
        option1_button.set_state("disabled")
    elif index == 1:
        option2_button.set_state("disabled")
    elif index == 2:
        option3_button.set_state("disabled")


def disable_all_options():
    option1_button.set_state("disabled")
    option2_button.set_state("disabled")
    option3_button.set_state("disabled")


def highlight_option(index, color):
    if index == 0:
        option1_button.itemconfig(option1_button.rect, fill=color)
    elif index == 1:
        option2_button.itemconfig(option2_button.rect, fill=color)
    elif index == 2:
        option3_button.itemconfig(option3_button.rect, fill=color)


def start_quiz():
    global question_number, score, quiz, joker_used
    question_number = 0
    score = 0
    joker_used = False
    print(f"Starting quiz with {num_questions} questions.")
    quiz = create_quiz(words, meanings, examples, num_questions)
    if not quiz:
        messagebox.showerror("Error", "No valid quiz questions available.")
        create_question_count_selection()
        return
    administer_quiz()


def administer_quiz():
    global question_number, score, quiz, joker_used, joker_button_state
    if question_number < len(quiz):
        word, options, example, correct_index = quiz[question_number]
        print(f"Administering Question {question_number + 1}: {word}")
        print(f"Options: {options}, Correct Index: {correct_index}")

        # Update Question Label
        question_text = f"Question {question_number + 1}: What is the meaning of '{word}'?"
        question_label.config(text=question_text)

        # Reset button states and update texts
        option1_button.update_text(options[0])
        option2_button.update_text(options[1])
        option3_button.update_text(options[2])

        option1_button.set_state("normal")
        option2_button.set_state("normal")
        option3_button.set_state("normal")

        # Reset button colors
        option1_button.itemconfig(option1_button.rect, fill=option1_button.bg_color)
        option2_button.itemconfig(option2_button.rect, fill=option2_button.bg_color)
        option3_button.itemconfig(option3_button.rect, fill=option3_button.bg_color)

        # Update commands
        option1_button.command = lambda i=0: check_answer(i)
        option2_button.command = lambda i=1: check_answer(i)
        option3_button.command = lambda i=2: check_answer(i)

        # Update Progress Bar with smooth animation
        progress_percentage = ((question_number + 1) / len(quiz)) * 100
        animate_progress_bar(progress_percentage)

        # Update Remaining Questions Label
        remaining_questions = len(quiz) - (question_number + 1)
        remaining_label.config(text=f"Remaining: {remaining_questions}")
        print(f"Progress: {progress_percentage}%, Remaining: {remaining_questions}")

        # Handle Joker Button State
        if not joker_used:
            joker_button.set_state("normal")
            joker_button.itemconfig(joker_button.rect, fill=joker_button.bg_color)
            joker_button.itemconfig(joker_button.label, fill="white")
            print("Joker is available.")
        else:
            joker_button.set_state("disabled")
            joker_button.itemconfig(joker_button.rect, fill='#E0E0E0')
            joker_button.itemconfig(joker_button.label, fill="#A0A0A0")
            print("Joker has been used.")

    else:
        finalize_quiz()


def animate_progress_bar(target):
    current = progress_var.get()
    if current < target:
        current += 1
        progress_var.set(current)
        root.after(10, lambda: animate_progress_bar(target))
    else:
        progress_var.set(target)


def finalize_quiz():
    percentage_score = (score / len(quiz)) * 100 if len(quiz) > 0 else 0
    rounded_percentage = round(percentage_score)
    joker_message = "You used the joker." if joker_used else "You did not use the joker."
    final_message = (
        f"🎉 Congratulations! 🎉\n\n"
        f"Your final score is {score}/{len(quiz)}.\n"
        f"That's {rounded_percentage}%!\n\n"
        f"{joker_message}\n\n"
        f"Thank you for taking the quiz with Sadra!"
    )
    # Add a final fun fact
    if fun_facts:
        final_message += f"\n\nLast Fun Fact: {funny_message(fun_facts)}"
    messagebox.showinfo("Quiz Completed", final_message)
    print("Quiz completed. Exiting application.")
    root.destroy()


# ---------- Main Application Setup ----------

if __name__ == '__main__':
    # Load resources
    funny_message_file_path = resource_path('funny_message.txt')
    words_meanings_file_path = resource_path('words_meanings.txt')

    # Verify resource files
    if not os.path.exists(words_meanings_file_path):
        messagebox.showerror("Error", f"Error: {words_meanings_file_path} does not exist.")
        sys.exit(1)
    if not os.path.exists(funny_message_file_path):
        messagebox.showerror("Error", f"Error: {funny_message_file_path} does not exist.")
        sys.exit(1)

    words, meanings, examples = read_words_meanings(words_meanings_file_path)
    if not words:
        messagebox.showerror("Error", "No valid entries found in the words_meanings.txt file.")
        sys.exit(1)

    fun_facts = read_fun_facts_from_file(funny_message_file_path)

    # Create the main application window
    root = tk.Tk()
    root.title("Vocabulary Quiz")
    root.geometry("900x700")
    root.config(bg="#f0f8ff")

    # Initialize variables
    question_number = 0
    score = 0
    joker_used = False
    joker_button_state = False
    quiz = []
    num_questions = 10  # Default value, will be updated by user selection

    # Center the window on the screen
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()
    x = (screen_width - 900) // 2
    y = (screen_height - 700) // 2
    root.geometry(f"900x700+{x}+{y}")

    # Add window icon (if available)
    try:
        root.iconbitmap(resource_path('quiz_icon.ico'))
    except:
        pass  # Skip if icon file is not available

    # Configure custom styles for the application
    style = ttk.Style()
    style.theme_use('clam')

    # Configure a custom style for the progress bar
    style.configure("Custom.Horizontal.TProgressbar",
                    troughcolor='#E3F2FD',
                    background='#2196F3',
                    thickness=20,
                    borderwidth=0)

    # Configure grid weights for responsive layout
    root.grid_rowconfigure(0, weight=1)
    root.grid_rowconfigure(1, weight=1)
    root.grid_rowconfigure(2, weight=1)
    root.grid_columnconfigure(0, weight=1)

    # Create custom fonts for different elements
    title_font = ("Helvetica", 24, "bold")
    button_font = ("Helvetica", 12)
    label_font = ("Helvetica", 14)


    # ---------- Keyboard Shortcuts ----------

    def handle_keyboard_input(event):
        if question_number < len(quiz):
            if event.char in ['1', '2', '3']:
                index = int(event.char) - 1
                if index == 0 and option1_button['state'] != 'disabled':
                    option1_button.invoke()
                elif index == 1 and option2_button['state'] != 'disabled':
                    option2_button.invoke()
                elif index == 2 and option3_button['state'] != 'disabled':
                    option3_button.invoke()
            elif event.char.lower() == 'j' and not joker_used and joker_button['state'] != 'disabled':
                joker_button.invoke()


    root.bind('<Key>', handle_keyboard_input)


    # ---------- Error Handling ----------

    def on_error(exception_type, value, traceback_info):
        messagebox.showerror("Error",
                             "An unexpected error occurred. The application will restart.\n\n"
                             f"Error: {str(value)}")
        root.destroy()
        sys.exit(1)


    root.report_callback_exception = on_error

    # ---------- Start with Question Count Selection ----------

    create_question_count_selection()

    # ---------- Start the Main Event Loop ----------

    try:
        root.mainloop()
    except Exception as e:
        print(f"Error in main loop: {str(e)}")
        sys.exit(1)"