TheBug95's picture
Fix: image sizing, thumbnail consistency, protection layer, page jumping
5979537
"""OphthalmoCapture — Image Gallery Component
Renders a thumbnail strip of all uploaded images with labeling-status
badges and click-to-select behaviour.
"""
import streamlit as st
from i18n import t
from services import session_manager as sm
def _label_badge(label):
"""Return a coloured status indicator for the label value."""
if label is None:
return "🔴" # unlabeled
return "🟢" # labeled (any value)
def render_gallery():
"""Draw the horizontal thumbnail gallery with status badges.
Returns True if the user clicked on a thumbnail (triggers rerun).
"""
images = st.session_state.images
order = st.session_state.image_order
current_id = st.session_state.current_image_id
if not order:
return False
# ── Progress bar ─────────────────────────────────────────────────────
labeled, total = sm.get_labeling_progress()
progress_text = f"{t('progress')}: **{labeled}** / **{total}** {t('labeled_suffix')}"
st.markdown(progress_text)
st.progress(labeled / total if total > 0 else 0)
# ── Thumbnail strip ──────────────────────────────────────────────────
# Show up to 8 thumbnails per row; wrap if there are more.
COLS_PER_ROW = 6
THUMB_HEIGHT = 120 # fixed thumbnail height in pixels
num_images = len(order)
# Paginate the gallery if many images
if "gallery_page" not in st.session_state:
st.session_state.gallery_page = 0
total_pages = max(1, -(-num_images // COLS_PER_ROW)) # ceil division
page = st.session_state.gallery_page
start = page * COLS_PER_ROW
end = min(start + COLS_PER_ROW, num_images)
visible_ids = order[start:end]
# Always use fixed number of columns so thumbnails keep consistent size
cols = st.columns(COLS_PER_ROW)
clicked = False
for i, img_id in enumerate(visible_ids):
img = images[img_id]
badge = _label_badge(img["label"])
is_selected = (img_id == current_id)
with cols[i]:
# Visual border to highlight the selected thumbnail
border_color = "#4CAF50" if is_selected else "transparent"
st.markdown(
f"<div style='border:3px solid {border_color}; border-radius:8px; "
f"padding:2px; text-align:center;'>",
unsafe_allow_html=True,
)
st.image(img["bytes"], width=THUMB_HEIGHT)
st.markdown("</div>", unsafe_allow_html=True)
# Label + filename
short_name = img["filename"]
if len(short_name) > 18:
short_name = short_name[:15] + "…"
if st.button(
f"{badge} {short_name}",
key=f"thumb_{img_id}",
use_container_width=True,
):
sm.set_current_image(img_id)
clicked = True
# ── Gallery pagination ───────────────────────────────────────────────
if total_pages > 1:
gc1, gc2, gc3 = st.columns([1, 3, 1])
with gc1:
if page > 0:
if st.button(t("gallery_prev"), key="gal_prev"):
st.session_state.gallery_page -= 1
clicked = True
with gc2:
st.markdown(
f"<div style='text-align:center; padding-top:6px;'>"
f"{t('page')} {page + 1} / {total_pages}</div>",
unsafe_allow_html=True,
)
with gc3:
if page < total_pages - 1:
if st.button(t("gallery_next"), key="gal_next"):
st.session_state.gallery_page += 1
clicked = True
return clicked