from __future__ import annotations import os from pathlib import Path from typing import Any, cast import gi gi.require_version("Gdk", "4.0") gi.require_version("Gtk", "4.0") gi.require_version("Gst", "1.0") from gi.repository import Gdk, Gst, Gtk # NOQA: E402 class MainWindow(Gtk.ApplicationWindow): file_info_label: Gtk.Label def __init__(self, *args: Any, **kwargs: Any): super().__init__(*args, **kwargs) # Make window fullscreen and borderless self.set_decorated(False) self.fullscreen() # Main horizontal box to split the screen main_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) # Create a grid to handle the 1:2 ratio grid = Gtk.Grid() grid.set_column_homogeneous(True) grid.set_hexpand(True) # Left third (1/3 width) left_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) left_box.set_valign(Gtk.Align.CENTER) left_box.set_halign(Gtk.Align.FILL) self.file_info_label = Gtk.Label(label="") left_box.append(self.file_info_label) # Right two-thirds (2/3 width) right_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) right_box.set_hexpand(True) # Attach boxes to grid with specific column spans grid.attach(left_box, 0, 0, 1, 1) grid.attach(right_box, 1, 0, 2, 1) main_box.append(grid) # Create list store and view list_store = Gtk.StringList() list_view = Gtk.ListView() selection_model = Gtk.SingleSelection.new(list_store) selection_model.connect("selection-changed", self._on_selection_changed) list_view.set_model(selection_model) list_view.set_vexpand(True) def on_activate(widget: Gtk.ListView, index: int): selected_item = selection_model.get_item(index) if selected_item: string_obj = cast(Gtk.StringObject, selected_item) string = string_obj.get_string() print("activated", string) list_view.connect("activate", on_activate) # Factory for list items factory = Gtk.SignalListItemFactory() factory.connect("setup", self._setup_list_item) factory.connect("bind", self._bind_list_item) list_view.set_factory(factory) # Populate the list store self._populate_file_list(list_store) # Add list view to a scrolled window scrolled = Gtk.ScrolledWindow() scrolled.set_child(list_view) right_box.append(scrolled) self.set_child(main_box) def _setup_list_item(self, factory: Gtk.SignalListItemFactory, list_item: Gtk.ListItem): label = Gtk.Label() label.set_halign(Gtk.Align.START) list_item.set_child(label) def _bind_list_item(self, factory: Gtk.SignalListItemFactory, list_item: Gtk.ListItem): label = cast(Gtk.Label, list_item.get_child()) item = cast(Gtk.StringObject, list_item.get_item()) label.set_text(item.get_string()) def _on_selection_changed( self, selection_model: Gtk.SingleSelection, position: int, n_items: int, ): if selection_model.get_selected() == Gtk.INVALID_LIST_POSITION: self.file_info_label.set_text("") else: selected_item = selection_model.get_selected_item() if selected_item: string_obj = cast(Gtk.StringObject, selected_item) self.file_info_label.set_text(string_obj.get_string()) def _populate_file_list(self, list_store: Gtk.StringList) -> None: # TODO: Implement proper version sort (strverscmp equivalent) directories: list[str] = ["../"] files: list[str] = [] with os.scandir(".") as it: for entry in it: if entry.name == ".." or not entry.name.startswith("."): if entry.is_dir(): directories.append(entry.name + "/") else: files.append(entry.name) directories.sort(key=lambda x: x.lower()) files.sort(key=lambda x: x.lower()) while list_store.get_n_items(): list_store.remove(0) for name in directories + files: list_store.append(name) all = directories + files self.file_info_label.set_text(all[0] if all else "") class App(Gtk.Application): def __init__(self): super().__init__() # Initialize GStreamer Gst.init(None) # Load CSS css_provider = Gtk.CssProvider() css_file = Path(__file__).parent / "style.css" css_provider.load_from_path(str(css_file)) display = Gdk.Display.get_default() if display is None: raise RuntimeError("No display available") Gtk.StyleContext.add_provider_for_display( display, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION, ) def do_activate(self): win = MainWindow(application=self) win.present() def main(): app = App() app.run(None)