diff --git a/app.py b/app.py index 96172d0..a0d8e12 100644 --- a/app.py +++ b/app.py @@ -4,6 +4,7 @@ """ import streamlit as st +import streamlit.components.v1 as components from PIL import Image import os from typing import Optional, Union @@ -52,6 +53,58 @@ ) +def inject_keyboard_shortcuts(): + """ + JavaScriptを入れて,キーボードの左右矢印キーで画面上の「◀」「▶」ボタンをプログラム的にクリックさせる + """ + js_code = """ + + """ + components.html(js_code, height=0) + def open_folder_dialog(initial_dir: str = ".") -> str: """ Windows標準のフォルダ選択ダイアログを開き、選択されたパスを返す。 @@ -339,17 +392,28 @@ st.markdown("---") # --- 画像拡大率 --- - st.subheader("表示設定") - zoom_percent = st.select_slider( - "画像拡大率", - options=[30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150], - value=st.session_state.zoom_percent, - format_func=lambda x: f"{x}%", - key="global_zoom" - ) - if zoom_percent != st.session_state.zoom_percent: - st.session_state.zoom_percent = zoom_percent - st.rerun() + zoom_levels = [30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150] + if st.session_state.zoom_percent not in zoom_levels: + st.session_state.zoom_percent = 80 + + current_idx = zoom_levels.index(st.session_state.zoom_percent) + + col_z1, col_z2, col_z3 = st.columns([1, 2, 1]) + + with col_z1: + if st.button("-", key="zoom_out", use_container_width=True): + if current_idx > 0: + st.session_state.zoom_percent = zoom_levels[current_idx - 1] + st.rerun() + + with col_z2: + st.markdown(f"
{st.session_state.zoom_percent} %
", unsafe_allow_html=True) + + with col_z3: + if st.button("+", key="zoom_in", use_container_width=True): + if current_idx < len(zoom_levels) - 1: + st.session_state.zoom_percent = zoom_levels[current_idx + 1] + st.rerun() def render_image_viewer(case_id: Union[int, float], container): @@ -371,19 +435,28 @@ if frame_key not in st.session_state: st.session_state[frame_key] = 0 + # ボタンが押されたときに実行される関数 + def change_frame(amount: int): + current = st.session_state[frame_key] + new_val = current + amount + if 0 <= new_val < len(images): + st.session_state[frame_key] = new_val + # st.rerun() + # Image slider frame_idx = container.slider( "フレーム番号", min_value=0, max_value=len(images) - 1, value=st.session_state[frame_key], - key=f"frame_slider_{case_id}", - on_change=lambda: None # Ensure state updates + key=frame_key, + label_visibility="collapsed", + # on_change=lambda: None # Ensure state updates ) # Update session state from slider - if frame_idx != st.session_state[frame_key]: - st.session_state[frame_key] = frame_idx + # if frame_idx != st.session_state[frame_key]: + # st.session_state[frame_key] = frame_idx # Display image with custom width based on global zoom level try: @@ -403,19 +476,34 @@ with col1: st.write("") # Spacer with col2: - if st.button("◀", key=f"prev_frame_{case_id}", disabled=frame_idx == 0, use_container_width=True): - st.session_state[frame_key] = frame_idx - 1 - st.rerun() + st.button( + "◀", + key=f"prev_{case_id}", + on_click=change_frame, + args=(-1,), + ) + # if st.button("◀", key=f"prev_{case_id}"): + # if frame_idx > 0: + # st.session_state[frame_key] = frame_idx - 1 + # st.rerun() with col3: - if st.button("▶", key=f"next_frame_{case_id}", disabled=frame_idx >= len(images) - 1, use_container_width=True): - st.session_state[frame_key] = frame_idx + 1 - st.rerun() + st.button( + "▶", + key=f"next_{case_id}", + on_click=change_frame, + args=(1,), + ) + # if st.button("▶", key=f"next_{case_id}", disabled=frame_idx >= len(images) - 1): + # if frame_idx < len(images) - 1: + # st.session_state[frame_key] = frame_idx + 1 + # st.rerun() except Exception as e: container.error(f"画像読み込みエラー: {e}") # Keyboard navigation support (キーボードの矢印キーでフレーム移動) container.caption("💡 ヒント: スライダーをクリックしてから矢印キー(←→)でフレーム移動、または◀▶ボタンをクリックできます") + inject_keyboard_shortcuts() def render_annotation_form(container, case_id: Union[int, float]) -> dict: