feat: Implement initial Sprite Editor application with basic UI components
- Added main application class `SpriteEditorApp` with layout setup. - Created menu bar with placeholder options. - Implemented `BottomToolbarView`, `LeftSidebarView`, `MainEditorView`, `RightSidebarView` with basic UI elements. - Added dialog classes for `ExportSettingsDialog` and `FlipbookCreatorDialog` to manage export settings and flipbook creation. - Introduced support for loading and displaying images in the flipbook creator. - Established a structure for handling sprite sheet composition and preview rendering.
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
from dataclasses import dataclass
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExportSettings:
|
||||
orientation: str = "horizontal"
|
||||
spacing: int = 0
|
||||
margin: int = 0
|
||||
rows: int = 0
|
||||
columns: int = 0
|
||||
output_name: str = "flipbook.png"
|
||||
|
||||
|
||||
class ExportSettingsDialog(tk.Toplevel):
|
||||
def __init__(self, parent: tk.Misc, initial_settings: ExportSettings | None = None) -> None:
|
||||
super().__init__(parent)
|
||||
self.title("Default Export Settings")
|
||||
self.resizable(False, False)
|
||||
self.transient(parent)
|
||||
self.grab_set()
|
||||
self.result: ExportSettings | None = None
|
||||
|
||||
settings = initial_settings or ExportSettings()
|
||||
self.orientation_var = tk.StringVar(value=settings.orientation)
|
||||
self.spacing_var = tk.StringVar(value=str(settings.spacing))
|
||||
self.margin_var = tk.StringVar(value=str(settings.margin))
|
||||
self.rows_var = tk.StringVar(value=str(settings.rows))
|
||||
self.columns_var = tk.StringVar(value=str(settings.columns))
|
||||
self.output_name_var = tk.StringVar(value=settings.output_name)
|
||||
|
||||
container = ttk.Frame(self, padding=10)
|
||||
container.grid(row=0, column=0, sticky="nsew")
|
||||
container.columnconfigure(1, weight=1)
|
||||
|
||||
ttk.Label(container, text="Orientation").grid(row=0, column=0, sticky="w", pady=4)
|
||||
orientation_combo = ttk.Combobox(
|
||||
container,
|
||||
state="readonly",
|
||||
values=["horizontal", "vertical"],
|
||||
textvariable=self.orientation_var,
|
||||
width=20,
|
||||
)
|
||||
orientation_combo.grid(row=0, column=1, sticky="ew", pady=4)
|
||||
|
||||
ttk.Label(container, text="Frame Spacing (px)").grid(row=1, column=0, sticky="w", pady=4)
|
||||
ttk.Spinbox(container, from_=0, to=999, textvariable=self.spacing_var, width=10).grid(
|
||||
row=1, column=1, sticky="w", pady=4
|
||||
)
|
||||
|
||||
ttk.Label(container, text="Margin (px)").grid(row=2, column=0, sticky="w", pady=4)
|
||||
ttk.Spinbox(container, from_=0, to=999, textvariable=self.margin_var, width=10).grid(
|
||||
row=2, column=1, sticky="w", pady=4
|
||||
)
|
||||
|
||||
ttk.Label(container, text="Rows (0 = auto)").grid(row=3, column=0, sticky="w", pady=4)
|
||||
ttk.Spinbox(container, from_=0, to=999, textvariable=self.rows_var, width=10).grid(
|
||||
row=3, column=1, sticky="w", pady=4
|
||||
)
|
||||
|
||||
ttk.Label(container, text="Columns (0 = auto)").grid(row=4, column=0, sticky="w", pady=4)
|
||||
ttk.Spinbox(container, from_=0, to=999, textvariable=self.columns_var, width=10).grid(
|
||||
row=4, column=1, sticky="w", pady=4
|
||||
)
|
||||
|
||||
ttk.Label(container, text="Default File Name").grid(row=5, column=0, sticky="w", pady=4)
|
||||
ttk.Entry(container, textvariable=self.output_name_var, width=24).grid(row=5, column=1, sticky="ew", pady=4)
|
||||
|
||||
actions = ttk.Frame(container)
|
||||
actions.grid(row=6, column=0, columnspan=2, sticky="e", pady=(10, 0))
|
||||
ttk.Button(actions, text="Cancel", command=self._cancel).grid(row=0, column=0, padx=4)
|
||||
ttk.Button(actions, text="Apply", command=self._apply).grid(row=0, column=1, padx=4)
|
||||
|
||||
self.protocol("WM_DELETE_WINDOW", self._cancel)
|
||||
|
||||
def show(self) -> ExportSettings | None:
|
||||
self.wait_window(self)
|
||||
return self.result
|
||||
|
||||
def _apply(self) -> None:
|
||||
try:
|
||||
spacing = int(self.spacing_var.get())
|
||||
margin = int(self.margin_var.get())
|
||||
rows = int(self.rows_var.get())
|
||||
columns = int(self.columns_var.get())
|
||||
except ValueError:
|
||||
messagebox.showerror(
|
||||
"Invalid settings",
|
||||
"Spacing, margin, rows, and columns must be valid whole numbers.",
|
||||
parent=self,
|
||||
)
|
||||
return
|
||||
|
||||
if spacing < 0 or margin < 0 or rows < 0 or columns < 0:
|
||||
messagebox.showerror("Invalid settings", "Spacing, margin, rows, and columns cannot be negative.", parent=self)
|
||||
return
|
||||
|
||||
orientation = self.orientation_var.get()
|
||||
if orientation not in {"horizontal", "vertical"}:
|
||||
messagebox.showerror("Invalid settings", "Orientation must be horizontal or vertical.", parent=self)
|
||||
return
|
||||
|
||||
output_name = self.output_name_var.get().strip() or "flipbook.png"
|
||||
if not output_name.lower().endswith(".png"):
|
||||
output_name = f"{output_name}.png"
|
||||
|
||||
self.result = ExportSettings(
|
||||
orientation=orientation,
|
||||
spacing=spacing,
|
||||
margin=margin,
|
||||
rows=rows,
|
||||
columns=columns,
|
||||
output_name=output_name,
|
||||
)
|
||||
self.destroy()
|
||||
|
||||
def _cancel(self) -> None:
|
||||
self.result = None
|
||||
self.destroy()
|
||||
Reference in New Issue
Block a user