lots of ux improvements and small bug fixes
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -62,7 +62,7 @@ class AIEditorManager:
|
||||
|
||||
# Prompt entry renamed to "Copy Editing Rules" with a Text area
|
||||
ttk.Label(main_frame, text="Copy Editing Rules:").grid(row=4, column=0, sticky=tk.NW, pady=2)
|
||||
prompt_entry = tk.Text(main_frame, height=8, width=50)
|
||||
prompt_entry = tk.Text(main_frame, height=8, width=50, background="white", font=("Arial", 10))
|
||||
|
||||
# Default prompt example if none exists
|
||||
default_prompt = "Edit the text provided to ensure it has a clear, professional tone. Fix any grammatical errors, improve sentence structure, and maintain consistent formatting. Make the language concise and impactful while preserving the original meaning. Make sure to edit text only and do not reply to it."
|
||||
|
||||
@@ -44,6 +44,8 @@ class PresetsManager:
|
||||
|
||||
# Bind to window resize for responsive layout
|
||||
self.parent.bind("<Configure>", self.on_window_resize)
|
||||
# This resize timer helps batch updates during resizing
|
||||
self.resize_timer = None
|
||||
|
||||
def create_presets_section(self):
|
||||
"""Create the presets section UI with accordion behavior."""
|
||||
@@ -146,6 +148,9 @@ class PresetsManager:
|
||||
# Configure the scroll region to update when the frame changes
|
||||
self.presets_scrollable_frame.bind("<Configure>",
|
||||
lambda e: self.presets_canvas.configure(scrollregion=self.presets_canvas.bbox("all")))
|
||||
|
||||
# Add a binding for the canvas size changes
|
||||
self.presets_canvas.bind("<Configure>", self.on_canvas_resize)
|
||||
|
||||
# Populate tabs and presets
|
||||
self.populate_tabs() # Refresh tabs to show selection
|
||||
@@ -159,10 +164,9 @@ class PresetsManager:
|
||||
"""Handler for window resize events to adjust the presets layout."""
|
||||
# Only proceed if event is from the main window and presets are visible
|
||||
if event and event.widget == self.parent and not self.presets_collapsed:
|
||||
# Schedule a refresh after a short delay to prevent excessive updates during resize
|
||||
if hasattr(self, 'resize_timer') and self.resize_timer:
|
||||
self.parent.after_cancel(self.resize_timer)
|
||||
self.resize_timer = self.parent.after(100, self.refresh_presets_display)
|
||||
# We don't need to immediately refresh here, as on_canvas_resize will handle it
|
||||
# This is because the window resize will trigger canvas resize events
|
||||
pass
|
||||
|
||||
def _adjust_row_weights(self):
|
||||
"""Adjust row weights to prioritize presets area expansion."""
|
||||
@@ -313,14 +317,17 @@ class PresetsManager:
|
||||
canvas_width = self.presets_canvas.winfo_width()
|
||||
# Ensure we have a minimum width to calculate with
|
||||
if canvas_width < 50: # If the canvas is too narrow or not yet realized
|
||||
canvas_width = self.parent.winfo_width() - 30 # Estimate canvas width
|
||||
|
||||
canvas_width = self.parent.winfo_width() - 40 # Estimate canvas width with more margin for scrollbar
|
||||
|
||||
# Calculate number of columns (minimum 1, maximum 20)
|
||||
min_card_width = 140 # Minimum width for each card
|
||||
num_columns = max(1, min(20, canvas_width // min_card_width))
|
||||
|
||||
# Log for debugging - can be removed in production
|
||||
print(f"Canvas width: {canvas_width}, Columns: {num_columns}")
|
||||
|
||||
# Dynamically adjust card width based on available space
|
||||
preset_width = max(min_card_width, canvas_width // num_columns - 8)
|
||||
preset_width = max(min_card_width, (canvas_width // num_columns) - 10) # Slightly more padding
|
||||
preset_height = 100
|
||||
|
||||
# Configure columns to fill available space
|
||||
@@ -715,4 +722,15 @@ class PresetsManager:
|
||||
|
||||
# Save and refresh
|
||||
self.debounced_save()
|
||||
self.refresh_presets_display()
|
||||
self.refresh_presets_display()
|
||||
|
||||
def on_canvas_resize(self, event=None):
|
||||
"""Handle resize events specifically for the presets canvas area."""
|
||||
# Only process if presets are visible
|
||||
if not self.presets_collapsed:
|
||||
# Cancel any previous refresh timer to avoid multiple refreshes
|
||||
if hasattr(self, 'resize_timer') and self.resize_timer:
|
||||
self.parent.after_cancel(self.resize_timer)
|
||||
|
||||
# Schedule a refresh with a short delay to avoid excessive refreshes during drag
|
||||
self.resize_timer = self.parent.after(150, self.refresh_presets_display)
|
||||
@@ -87,7 +87,7 @@ class SettingsManager:
|
||||
settings_file = cls.get_settings_file_path()
|
||||
|
||||
with open(settings_file, "w") as f:
|
||||
json.dump(settings, f)
|
||||
json.dump(settings, f, indent=4)
|
||||
|
||||
@classmethod
|
||||
def update_settings(cls, partial_settings):
|
||||
|
||||
@@ -40,7 +40,7 @@ class TextToMic(tk.Tk):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.version = "1.3.5"
|
||||
self.version = "1.3.0"
|
||||
self.title(f"Text to Mic by Scorchsoft.com - v{self.version}")
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class TextToMic(tk.Tk):
|
||||
|
||||
# Fixed window dimensions for all states - DEFINED ONCE as class constants
|
||||
# These are the ONLY values that should be used throughout the application
|
||||
self.BASE_WIDTH = 590
|
||||
self.BASE_WIDTH = 600
|
||||
self.BASE_HEIGHT_WITH_BANNER = 860
|
||||
self.BASE_HEIGHT_NO_BANNER = 700
|
||||
self.COLLAPSED_HEIGHT_WITH_BANNER = 630
|
||||
@@ -188,45 +188,59 @@ class TextToMic(tk.Tk):
|
||||
self.menubar = Menu(self)
|
||||
self.config(menu=self.menubar)
|
||||
|
||||
# Get current hotkey settings
|
||||
settings = self.load_settings()
|
||||
hotkey_manager = self.hotkey_manager if hasattr(self, 'hotkey_manager') else None
|
||||
|
||||
# Format hotkeys for display in menus
|
||||
if hotkey_manager:
|
||||
replay_shortcut = hotkey_manager.format_shortcut(settings["hotkeys"]["play_last_audio"])
|
||||
record_shortcut = hotkey_manager.format_shortcut(settings["hotkeys"]["record_start_stop"])
|
||||
stop_shortcut = hotkey_manager.format_shortcut(settings["hotkeys"]["stop_recording"])
|
||||
cancel_shortcut = hotkey_manager.format_shortcut(settings["hotkeys"]["cancel_operation"])
|
||||
else:
|
||||
# Default values if hotkey_manager isn't available
|
||||
replay_shortcut = "Ctrl+Shift+8"
|
||||
record_shortcut = "Ctrl+Shift+0"
|
||||
stop_shortcut = "Ctrl+Shift+9"
|
||||
cancel_shortcut = "Ctrl+Shift+1"
|
||||
|
||||
# File or settings menu
|
||||
settings_menu = Menu(self.menubar, tearoff=0)
|
||||
self.menubar.add_cascade(label="Settings", menu=settings_menu)
|
||||
settings_menu.add_command(label="Change API Key", command=self.change_api_key)
|
||||
settings_menu.add_command(label="AI Copy Editing", command=self.show_ai_editor_settings)
|
||||
settings_menu.add_command(label="Hotkey Settings", command=self.show_hotkey_settings)
|
||||
settings_menu.add_command(label="Manage Tone Presets", command=self.show_tone_presets_manager)
|
||||
settings_menu.add_command(label="API Key", command=self.change_api_key)
|
||||
settings_menu.add_command(label="AI Copyediting", command=self.show_ai_editor_settings)
|
||||
settings_menu.add_command(label="Keyboard Shortcuts", command=self.show_hotkey_settings)
|
||||
settings_menu.add_command(label="Manage Tones", command=self.show_tone_presets_manager)
|
||||
settings_menu.add_separator()
|
||||
settings_menu.add_checkbutton(label="Auto Check for Updates", variable=self.auto_check_version, command=self.toggle_auto_version_check)
|
||||
settings_menu.add_checkbutton(label="Hide Scorchsoft Banner", variable=self.banner_var, command=self.toggle_banner)
|
||||
|
||||
# Playback menu
|
||||
playback_menu = Menu(self.menubar, tearoff=0)
|
||||
self.menubar.add_cascade(label="Playback", menu=playback_menu)
|
||||
playback_menu.add_command(label="Play Last Audio", command=self.play_last_audio)
|
||||
|
||||
#apply_ai
|
||||
input_menu = Menu(self.menubar, tearoff=0)
|
||||
self.menubar.add_cascade(label="Input", menu=input_menu)
|
||||
input_menu.add_command(label="Apply AI Manipulation to Input Text", command=self.apply_ai_to_input)
|
||||
|
||||
self.menubar.add_cascade(label="Actions", menu=playback_menu)
|
||||
|
||||
# Add keyboard shortcuts to menu items
|
||||
playback_menu.add_command(label=f"Replay [{replay_shortcut}]", command=self.play_last_audio)
|
||||
playback_menu.add_command(label="Apply AI Copyedit", command=self.apply_ai_to_input)
|
||||
playback_menu.add_separator()
|
||||
playback_menu.add_command(label=f"Start/Stop Recording [{record_shortcut}]", command=self.handle_record_button_click)
|
||||
playback_menu.add_command(label=f"Stop Recording [{stop_shortcut}]", command=lambda: self.stop_recording(auto_play=False))
|
||||
playback_menu.add_command(label=f"Cancel Operation [{cancel_shortcut}]", command=self.stop_playback)
|
||||
|
||||
# Help menu
|
||||
help_menu = Menu(self.menubar, tearoff=0)
|
||||
self.menubar.add_cascade(label="Help", menu=help_menu)
|
||||
help_menu.add_command(label="Check Version", command=self.check_version)
|
||||
|
||||
help_menu.add_command(label="How to Use", command=self.show_instructions)
|
||||
help_menu.add_command(label="Terms of Use and Licence", command=self.show_terms_of_use)
|
||||
help_menu.add_command(label="Hotkey Instructions", command=self.show_hotkey_instructions)
|
||||
|
||||
# Add toggle for banner visibility - use the existing banner_var from __init__
|
||||
help_menu.add_checkbutton(label="Hide Banner", variable=self.banner_var, command=self.toggle_banner)
|
||||
|
||||
|
||||
def show_hotkey_settings(self):
|
||||
"""Show the hotkey settings dialog."""
|
||||
HotkeyManager.hotkey_settings_dialog(self)
|
||||
|
||||
def show_hotkey_instructions(self):
|
||||
"""Show hotkey instructions."""
|
||||
HotkeyManager.show_hotkey_instructions(self)
|
||||
|
||||
def change_api_key(self):
|
||||
"""Change the API key using APIKeyManager."""
|
||||
@@ -401,12 +415,12 @@ class TextToMic(tk.Tk):
|
||||
self.text_input = tk.Text(main_frame, height=5, width=68)
|
||||
# Use white background for text input instead of the system background color
|
||||
text_color = self.style.lookup('TLabel', 'foreground')
|
||||
self.text_input.configure(bg="white", fg=text_color, insertbackground=text_color, wrap=tk.WORD)
|
||||
self.text_input.configure(bg="white", fg=text_color, insertbackground=text_color, wrap=tk.WORD, font=("Arial", 10))
|
||||
self.text_input.grid(column=0, row=5, columnspan=2, pady=(0, 20), sticky="nsew") # Proper spacing
|
||||
|
||||
# Add a status frame at the bottom of the text input with white background
|
||||
status_frame = ttk.Frame(main_frame, style='White.TFrame')
|
||||
status_frame.grid(column=0, row=5, columnspan=2, sticky=(tk.S, tk.E), pady=(0, 25))
|
||||
status_frame.grid(column=0, row=5, columnspan=2, sticky=(tk.S, tk.E), pady=(0, 25), padx=(0, 5)) # Add right padding to shift the frame inward
|
||||
|
||||
# Create a custom style for the white frame
|
||||
self.style.configure('White.TFrame', background='white')
|
||||
@@ -1029,6 +1043,7 @@ class TextToMic(tk.Tk):
|
||||
record_shortcut = "+".join(filter(None, settings["hotkeys"]["record_start_stop"]))
|
||||
play_shortcut = "+".join(filter(None, settings["hotkeys"]["play_last_audio"]))
|
||||
stop_shortcut = "+".join(filter(None, settings["hotkeys"]["stop_recording"]))
|
||||
cancel_shortcut = "+".join(filter(None, settings["hotkeys"]["cancel_operation"]))
|
||||
|
||||
# Update CTkButton for recording state, keeping shortcuts visible
|
||||
self.record_button.configure(text=f"Stop and Insert", fg_color="#d32f2f")
|
||||
|
||||
@@ -103,7 +103,7 @@ class TonePresetsManager:
|
||||
|
||||
# Listbox for tones with scrollbar
|
||||
self.tone_list = tk.Listbox(select_frame, height=8, selectmode=tk.BROWSE,
|
||||
bg="#f0f0f0", fg="#333333",
|
||||
bg="#ffffff", fg="#333333",
|
||||
selectbackground="#0078d7", selectforeground="#ffffff",
|
||||
font=("Arial", 10))
|
||||
tone_scrollbar = ttk.Scrollbar(select_frame, orient=tk.VERTICAL, command=self.tone_list.yview)
|
||||
@@ -168,7 +168,7 @@ class TonePresetsManager:
|
||||
# Create the text widget with word wrap and vertical scrollbar
|
||||
self.content_text = tk.Text(text_frame, wrap=tk.WORD,
|
||||
yscrollcommand=v_scrollbar.set,
|
||||
bg="#f0f0f0", fg="#333333",
|
||||
bg="#ffffff", fg="#333333",
|
||||
font=("Arial", 10),
|
||||
relief="solid", borderwidth=1)
|
||||
self.content_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
|
||||
@@ -68,22 +68,28 @@ class VersionChecker:
|
||||
f"Could not check for updates. Server returned status code: {response.status_code}"
|
||||
))
|
||||
except requests.RequestException as e:
|
||||
error_message = f"Could not connect to update server: {str(e)}"
|
||||
print(f"Version check error: {error_message}")
|
||||
if show_result:
|
||||
self.app.after(0, lambda: messagebox.showwarning(
|
||||
self.app.after(0, lambda msg=error_message: messagebox.showwarning(
|
||||
"Version Check Failed",
|
||||
f"Could not connect to update server: {str(e)}"
|
||||
msg
|
||||
))
|
||||
except json.JSONDecodeError:
|
||||
except json.JSONDecodeError as e:
|
||||
error_message = "Invalid update information received."
|
||||
print(f"Version check error: {error_message}")
|
||||
if show_result:
|
||||
self.app.after(0, lambda: messagebox.showwarning(
|
||||
self.app.after(0, lambda msg=error_message: messagebox.showwarning(
|
||||
"Version Check Failed",
|
||||
"Invalid update information received."
|
||||
msg
|
||||
))
|
||||
except Exception as e:
|
||||
error_message = f"Could not check for updates: {str(e)}"
|
||||
print(f"Version check error: {error_message}")
|
||||
if show_result:
|
||||
self.app.after(0, lambda: messagebox.showwarning(
|
||||
self.app.after(0, lambda msg=error_message: messagebox.showwarning(
|
||||
"Version Check Failed",
|
||||
f"Could not check for updates: {str(e)}"
|
||||
msg
|
||||
))
|
||||
|
||||
def show_update_notification(self, latest_version, download_url, message):
|
||||
|
||||
Reference in New Issue
Block a user