#!/usr/bin/python3
import gi, os
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf, GLib

EXTS = {'.png','.jpg','.jpeg','.bmp','.gif','.webp','.tiff'}

class App(Gtk.Window):
    def __init__(self):
        super().__init__(title='Image Viewer')
        self.set_default_size(700, 550)
        self.files = []; self.idx = 0
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
        vbox.set_margin_top(4); vbox.set_margin_bottom(4)
        vbox.set_margin_start(4); vbox.set_margin_end(4)
        self.add(vbox)
        toolbar = Gtk.Box(spacing=6)
        open_btn = Gtk.Button(label='Open Image...')
        open_btn.connect('clicked', self.open_file)
        toolbar.pack_start(open_btn, False, False, 0)
        self.prev_btn = Gtk.Button(label='◀ Prev')
        self.prev_btn.connect('clicked', lambda *_: self.navigate(-1))
        self.prev_btn.set_sensitive(False)
        toolbar.pack_start(self.prev_btn, False, False, 0)
        self.next_btn = Gtk.Button(label='Next ▶')
        self.next_btn.connect('clicked', lambda *_: self.navigate(1))
        self.next_btn.set_sensitive(False)
        toolbar.pack_start(self.next_btn, False, False, 0)
        self.info = Gtk.Label(label='Open an image to start', xalign=0)
        toolbar.pack_start(self.info, True, True, 0)
        vbox.pack_start(toolbar, False, False, 0)
        sw = Gtk.ScrolledWindow()
        self.image = Gtk.Image()
        sw.add_with_viewport(self.image)
        vbox.pack_start(sw, True, True, 0)
        self.connect('check-resize', self.on_resize)
        self._pending_path = None
    def open_file(self, *_):
        dlg = Gtk.FileChooserDialog(title='Open Image', parent=self,
            action=Gtk.FileChooserAction.OPEN)
        dlg.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                        Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
        ff = Gtk.FileFilter(); ff.set_name('Images')
        for ext in EXTS: ff.add_pattern(f'*{ext}')
        dlg.add_filter(ff)
        if dlg.run() == Gtk.ResponseType.OK:
            path = dlg.get_filename()
            folder = os.path.dirname(path)
            self.files = sorted([os.path.join(folder, f) for f in os.listdir(folder)
                                  if os.path.splitext(f)[1].lower() in EXTS])
            self.idx = self.files.index(path) if path in self.files else 0
            self.load_current()
        dlg.destroy()
    def load_current(self):
        if not self.files: return
        path = self.files[self.idx]
        try:
            alloc = self.get_allocation()
            pb = GdkPixbuf.Pixbuf.new_from_file(path)
            ow, oh = pb.get_width(), pb.get_height()
            W = max(alloc.width - 20, 400); H = max(alloc.height - 60, 400)
            scale = min(W/ow, H/oh, 1.0)
            nw, nh = int(ow*scale), int(oh*scale)
            scaled = pb.scale_simple(nw, nh, GdkPixbuf.InterpType.BILINEAR)
            self.image.set_from_pixbuf(scaled)
            size = os.path.getsize(path)
            self.info.set_text(f'{os.path.basename(path)}  {ow}×{oh}  {size//1024}KB  ({self.idx+1}/{len(self.files)})')
            self.prev_btn.set_sensitive(self.idx > 0)
            self.next_btn.set_sensitive(self.idx < len(self.files)-1)
        except Exception as e:
            self.info.set_text(f'Error: {e}')
    def navigate(self, delta):
        self.idx = max(0, min(len(self.files)-1, self.idx+delta))
        self.load_current()
    def on_resize(self, *_):
        if self.files: GLib.idle_add(self.load_current)

win = App()
win.connect('destroy', Gtk.main_quit)
win.show_all()
Gtk.main()
