This commit is contained in:
2026-09-06 01:06:15 +02:00
parent 04ee194227
commit 3afa31e90f
8 changed files with 107 additions and 119 deletions
+50 -50
View File
@@ -12,9 +12,9 @@ class ImageInterface:
def __init__(self, base_dir=None):
self.base_dir = Path(base_dir or Path(__file__).resolve().parent.parent)
self.image_sets = {
"source": self._load_images(str(self.base_dir / "images" / "source" / "*.png")),
"goal": self._load_images(str(self.base_dir / "images" / "goal" / "*.png")),
"shenanigans": self._load_images(str(self.base_dir / "images" / "shenanigans" / "*.png")),
"source": self.load_images(str(self.base_dir / "images" / "source" / "*.png")),
"goal": self.load_images(str(self.base_dir / "images" / "goal" / "*.png")),
"shenanigans": self.load_images(str(self.base_dir / "images" / "shenanigans" / "*.png")),
}
self.current_category = None
self.current_index = 0
@@ -31,19 +31,19 @@ class ImageInterface:
"button": "#2b2b2b",
"button_hover": "#3a3a3a",
}
def _load_images(self, pattern):
def load_images(self, pattern):
return sorted(glob(pattern))
def _ensure_figure(self):
def ensure_figure(self):
if self.figure is None:
self.figure = plt.figure(figsize=(10, 6))
self.key_connection_id = self.figure.canvas.mpl_connect("key_press_event", self._on_key_press)
def _clear_layout(self):
self._ensure_figure()
self.key_connection_id = self.figure.canvas.mpl_connect("key_press_event", self.on_key_press)
def clear_layout(self):
self.ensure_figure()
self.figure.clf()
self.image_axis = None
self.list_axis = None
self.buttons = []
def _make_button(self, rect, label, callback):
def make_button(self, rect, label, callback):
button_axis = self.figure.add_axes(rect)
button_axis.set_facecolor(self.colors["button"])
button_axis.tick_params(left=False, labelleft=False, bottom=False, labelbottom=False)
@@ -52,12 +52,12 @@ class ImageInterface:
button.on_clicked(callback)
self.buttons.append(button)
return button
def _open_image(self, image_paths, index):
def open_image(self, image_paths, index):
if not image_paths:
return None
safe_index = max(0, min(index, len(image_paths) - 1))
return Image.open(image_paths[safe_index])
def _draw_image_panel(self, axis, image, title):
def draw_image_panel(self, axis, image, title):
axis.clear()
axis.set_title(title)
axis.set_facecolor(self.colors["panel"])
@@ -67,7 +67,7 @@ class ImageInterface:
axis.imshow(image)
else:
axis.text(0.5, 0.5, "No images found", ha="center", va="center", color=self.colors["text"])
def _draw_list_panel(self, axis, image_paths, current_index):
def draw_list_panel(self, axis, image_paths, current_index):
axis.clear()
axis.set_facecolor(self.colors["panel"])
axis.axis("off")
@@ -83,19 +83,19 @@ class ImageInterface:
lines.append(f"{prefix}{name}")
axis.text(0.02, 0.98, "\n".join(lines), ha="left", va="top", family="monospace", color=self.colors["text"])
axis.title.set_color(self.colors["text"])
def _show_menu(self):
def show_menu(self):
self.current_category = None
self._clear_layout()
self.clear_layout()
self.figure.patch.set_facecolor(self.colors["figure"])
self._menu_row(0.66, "Source Images", "source", lambda event: self._open_category("source"))
self._menu_row(0.50, "Goal Images", "goal", lambda event: self._open_category("goal"))
self._make_button([0.08, 0.34, 0.32, 0.12], "Shenanigans Image", lambda event: self._open_shenanigans())
self.menu_row(0.66, "Source Images", "source", lambda event: self.open_category("source"))
self.menu_row(0.50, "Goal Images", "goal", lambda event: self.open_category("goal"))
self.make_button([0.08, 0.34, 0.32, 0.12], "Shenanigans Image", lambda event: self.open_shenanigans())
self.figure.canvas.draw_idle()
def _open_category(self, category):
def open_category(self, category):
self.current_category = category
self.current_index = 0
self._show_browser()
def _open_shenanigans(self):
self.show_browser()
def open_shenanigans(self):
src_paths = self.image_sets.get("source", [])
goal_paths = self.image_sets.get("goal", [])
if not src_paths or not goal_paths:
@@ -109,77 +109,77 @@ class ImageInterface:
importlib.reload(transition)
except Exception:
pass
if not hasattr(transition, "transform_images"):
if not hasattr(transition, "show_image_transition"):
return
transition.transform_images(src_path, goal_path)
def _selected_image_name(self, category):
transition.show_image_transition(src_path, goal_path)
def selected_image_name(self, category):
selected_index = self.selected_indices.get(category)
image_paths = self.image_sets.get(category, [])
if selected_index is None or not image_paths:
return None
safe_index = max(0, min(selected_index, len(image_paths) - 1))
return Path(image_paths[safe_index]).name
def _menu_label(self, base_label, category=None):
def menu_label(self, base_label, category=None):
if category is None:
return base_label
selected_name = self._selected_image_name(category)
selected_name = self.selected_image_name(category)
if selected_name is None:
return base_label
return f"{base_label} - {selected_name}"
def _menu_row(self, y, label, category, callback):
self._make_button([0.08, y, 0.32, 0.12], label, callback)
selected_name = self._selected_image_name(category)
def menu_row(self, y, label, category, callback):
self.make_button([0.08, y, 0.32, 0.12], label, callback)
selected_name = self.selected_image_name(category)
if selected_name is not None:
self.figure.text(0.44, y + 0.055, f"- {selected_name}", color=self.colors["text"], va="center", ha="left", fontsize=11)
def _select_current_image(self):
def select_current_image(self):
if self.current_category in ("source", "goal"):
self.selected_indices[self.current_category] = self.current_index
self._show_menu()
def _close_interface(self):
self.show_menu()
def close_interface(self):
if self.figure is not None:
plt.close(self.figure)
def _show_browser(self):
self._clear_layout()
def show_browser(self):
self.clear_layout()
self.figure.patch.set_facecolor(self.colors["figure"])
self.figure.suptitle(self.current_category.replace("_", " ").title(), fontsize=16, color=self.colors["text"])
self.image_axis, self.list_axis = self.figure.subplots(1, 2, gridspec_kw={"width_ratios": [3, 1]})
self._refresh_browser_view()
self._make_button([0.02, 0.02, 0.12, 0.06], "Back", lambda event: self._show_menu())
self.refresh_browser_view()
self.make_button([0.02, 0.02, 0.12, 0.06], "Back", lambda event: self.show_menu())
if self.current_category in ("source", "goal"):
self._make_button([0.76, 0.10, 0.18, 0.06], "Select", lambda event: self._select_current_image())
self._make_button([0.76, 0.02, 0.08, 0.06], "<", lambda event: self.previous_image())
self._make_button([0.86, 0.02, 0.08, 0.06], ">", lambda event: self.next_image())
self.make_button([0.76, 0.10, 0.18, 0.06], "Select", lambda event: self.select_current_image())
self.make_button([0.76, 0.02, 0.08, 0.06], "<", lambda event: self.previous_image())
self.make_button([0.86, 0.02, 0.08, 0.06], ">", lambda event: self.next_image())
self.figure.subplots_adjust(left=0.05, right=0.95, bottom=0.12, top=0.90, wspace=0.22)
self.figure.canvas.draw_idle()
def _refresh_browser_view(self):
def refresh_browser_view(self):
images = self.image_sets.get(self.current_category, [])
current_image = self._open_image(images, self.current_index)
current_image = self.open_image(images, self.current_index)
category_title = self.current_category.replace("_", " ").title() if self.current_category else "Images"
self._draw_image_panel(self.image_axis, current_image, f"{category_title} {self.current_index + 1}/{max(len(images), 1)}")
self._draw_list_panel(self.list_axis, images, self.current_index)
self.draw_image_panel(self.image_axis, current_image, f"{category_title} {self.current_index + 1}/{max(len(images), 1)}")
self.draw_list_panel(self.list_axis, images, self.current_index)
self.figure.canvas.draw_idle()
def _step_image(self, delta):
def step_image(self, delta):
images = self.image_sets.get(self.current_category, [])
if images:
self.current_index = (self.current_index + delta) % len(images)
self._refresh_browser_view()
self.refresh_browser_view()
def next_image(self):
self._step_image(1)
self.step_image(1)
def previous_image(self):
self._step_image(-1)
def _on_key_press(self, event):
self.step_image(-1)
def on_key_press(self, event):
if self.current_category is None:
if event.key in ("escape", "q"):
self._close_interface()
self.close_interface()
return
if event.key in ("right", "d"):
self.next_image()
elif event.key in ("left", "a"):
self.previous_image()
elif event.key == "escape":
self._show_menu()
self.show_menu()
def render(self):
self._show_menu()
self.show_menu()
plt.show()
def launch_interface():