Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions src/navigate/controller/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -906,10 +906,7 @@ def refresh(width: int, height: int) -> None:
None
"""
self.view.scroll_frame.resize(width, height)
self.view.right_frame.config(
width=width - self.view.left_frame.winfo_width() - 3,
height=height - self.view.left_frame.winfo_height(),
)
self.view.update_idletasks()

if not self.resize_ready_flag:
return
Expand Down
108 changes: 59 additions & 49 deletions src/navigate/controller/sub_controllers/camera_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
# POSSIBILITY OF SUCH DAMAGE.

# Standard Library Imports
from __future__ import annotations
import platform
import tkinter as tk
from tkinter import messagebox
Expand Down Expand Up @@ -245,6 +246,9 @@ def __init__(self, view, parent_controller=None) -> None:
#: event: The resize event ID.
self.resize_event_id = None

#: event: The bound widget resize handler ID.
self.resize_binding_id = None

#: list: The selected channels being acquired.
self.selected_channels = None

Expand Down Expand Up @@ -1309,10 +1313,11 @@ def move_stage(self) -> None:
title="Warning", message="Can't move to there! Invalid stage position!"
)

def update_canvas_size(self) -> None:
def update_canvas_size(
self, width: int | None = None, height: int | None = None
) -> None:
"""Update the canvas size."""
r_canvas_width = int(self.view.canvas["width"])
r_canvas_height = int(self.view.canvas["height"])
r_canvas_width, r_canvas_height = self._get_canvas_widget_size(width, height)
img_ratio = self.original_image_width / self.original_image_height
canvas_ratio = r_canvas_width / r_canvas_height

Expand All @@ -1327,6 +1332,8 @@ def update_canvas_size(self) -> None:
self.canvas_height_scale = float(
self.original_image_height / self.canvas_height
)
self.view.canvas_width = self.canvas_width
self.view.canvas_height = self.canvas_height

def _prepare_zoom_window(self) -> tuple[slice, slice]:
"""Update zoom state and return crop slices for Y and X."""
Expand Down Expand Up @@ -1475,6 +1482,25 @@ def get_absolute_position(self) -> tuple:
y = self.parent_controller.view.winfo_pointery()
return x, y

def _get_canvas_widget_size(
self, width: int | None = None, height: int | None = None
) -> tuple[int, int]:
"""Return the actual drawable canvas size with stable fallbacks."""
resolved_width = int(width) if width is not None else 0
resolved_height = int(height) if height is not None else 0

if resolved_width <= 1:
resolved_width = int(self.canvas.winfo_width())
if resolved_height <= 1:
resolved_height = int(self.canvas.winfo_height())

if resolved_width <= 1:
resolved_width = int(self.canvas.cget("width"))
if resolved_height <= 1:
resolved_height = int(self.canvas.cget("height"))

return max(1, resolved_width), max(1, resolved_height)

def _ensure_canvas_image(self, w: int, h: int, mode: str) -> None:
"""Create/recreate the backing PhotoImage when size or mode changes.

Expand Down Expand Up @@ -1504,13 +1530,13 @@ def _ensure_canvas_image(self, w: int, h: int, mode: str) -> None:
self._photo = ImageTk.PhotoImage(base)
self._photo_mode = mode

if getattr(self, "_img_item", None) is None:
self._img_item = self.canvas.create_image(
0, 0, image=self._photo, anchor="nw"
)
else:
# Reuse the same canvas item, just rebind the image
self.canvas.itemconfig(self._img_item, image=self._photo)
if getattr(self, "_img_item", None) is None:
self._img_item = self.canvas.create_image(
0, 0, image=self._photo, anchor="nw"
)
else:
# Reuse the same canvas item, just rebind the image
self.canvas.itemconfig(self._img_item, image=self._photo)

def populate_image(self, image: np.ndarray) -> None:
"""Update the Tk canvas using a persistent PhotoImage + paste.
Expand Down Expand Up @@ -1614,61 +1640,45 @@ def resize(self, event: tk.Event) -> None:
"""
if not self.parent_controller.resize_ready_flag:
return
if event.width < 512 or event.height < 512:
event_widget = getattr(event, "widget", None)
resolved_widget = getattr(event_widget, "widget", event_widget)
if resolved_widget not in (self.view, self.canvas):
return
if event.widget != self.view:

width = int(getattr(event, "width", 0))
height = int(getattr(event, "height", 0))
if width <= 1 or height <= 1:
return
if self.view.is_docked:
left_width = self.parent_controller.view.left_frame.winfo_width()
top_height = self.parent_controller.view.top_frame.winfo_height()
w_width = self.parent_controller.view.winfo_width()
w_height = self.parent_controller.view.winfo_height()
width = max(w_width - left_width - 16, 560 + self.view.lut.winfo_width())
height = max(w_height - top_height - 50, 670)
else:
width = event.width
height = event.height - 24

if self.resize_event_id:
self.view.after_cancel(self.resize_event_id)
self.resize_event_id = self.view.after(300, lambda: self.refresh(width, height))
self.resize_event_id = self.view.after(
100, lambda w=width, h=height: self.refresh(w, h)
)

def refresh(self, width: int, height: int) -> None:
def refresh(self, width: int | None = None, height: int | None = None) -> None:
"""Refresh the window.

Parameters
----------
width : int
Width of the window.
height : int
Height of the window.
width : int or None
Width of the canvas viewport.
height : int or None
Height of the canvas viewport.
"""
width, height = self._get_canvas_widget_size(width, height)
if (
self.width
and self.height
and abs(width - self.width) < 10
and abs(height - self.height) < 10
and abs(width - self.width) < 2
and abs(height - self.height) < 2
):
return
self.canvas_width = width - self.view.lut.winfo_width() - 24
widget_height = 0
for widget in self.view.cam_image.winfo_children():
if widget != self.view.canvas:
if self.view.is_docked or widget.winfo_ismapped():
widget_height += widget.winfo_height() + 5
if widget.winfo_height() < 30:
widget_height += 30

self.canvas_height = (
height - widget_height - (50 if self.view.is_docked else -5)
)
self.view.canvas.config(width=self.canvas_width, height=self.canvas_height)
self.view.update_idletasks()

self.width, self.height = width, height

# if resize the window during acquisition, the image showing should be updated
self.update_canvas_size()
self.update_canvas_size(width, height)
self.reset_display(False)

def update_min_max_counts(self, display: bool = False):
Expand Down Expand Up @@ -1762,7 +1772,7 @@ def __init__(self, view, parent_controller=None) -> None:
# Slider Binding
self.view.slider.bind("<Motion>", self.slider_update)

self.resize_event_id = self.view.bind("<Configure>", self.resize)
self.resize_binding_id = self.view.canvas.bind("<Configure>", self.resize)

#: str: The display state.
self.display_state = "Live"
Expand Down Expand Up @@ -2397,7 +2407,7 @@ def __init__(self, view, parent_controller=None) -> None:
#: dict: The render widgets.
self.render_widgets = self.view.render.get_widgets()

self.resize_event_id = self.view.bind("<Configure>", self.resize)
self.resize_binding_id = self.view.canvas.bind("<Configure>", self.resize)

#: bool: The display enabled flag.
self.display_enabled = tk.BooleanVar()
Expand Down Expand Up @@ -2872,6 +2882,7 @@ def try_to_display_image(self, image: np.ndarray) -> None:
def _clear_mip(self) -> None:
"""Clear the mip but keep canvas interactive."""
self.canvas.delete("all")
self._img_item = None
self.tk_image = None
self.canvas.create_text(
self.canvas_width // 2,
Expand Down Expand Up @@ -3030,8 +3041,7 @@ def down_sample_image(
"""
sx, sy = self.canvas_width, self.canvas_height
if self.render_widgets["perspective"].get() == "Multi":
sx = int(self.view.canvas["width"])
sy = int(self.view.canvas["height"])
sx, sy = self._get_canvas_widget_size()
self.canvas_width = sx
self.canvas_height = sy
down_sampled_image = cv2.resize(image, (sx, sy))
Expand Down
8 changes: 6 additions & 2 deletions src/navigate/controller/sub_controllers/waveform_tab.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
# Local Imports
from navigate.controller.sub_controllers.gui import GUIController
from navigate.tools.waveform_template_funcs import get_waveform_template_parameters
from navigate.view.custom_widgets.common import themed_grid

# Logger Setup
p = __name__.split(".")[1]
Expand Down Expand Up @@ -145,8 +146,11 @@ def initialize_plots(self):
"""Initialize the plots in the waveform tab."""
self.view.plot_etl = self.view.fig.add_subplot(211)
self.view.plot_galvo = self.view.fig.add_subplot(212)
self.view.canvas.get_tk_widget().grid(
row=5, column=0, columnspan=3, sticky=NSEW, padx=(5, 5), pady=(5, 5)
themed_grid(
self.view.canvas.get_tk_widget(),
row=0,
column=0,
sticky=NSEW,
)

def plot_waveforms(self, event):
Expand Down
Loading
Loading