From: Christian Heller Date: Sun, 8 Sep 2024 04:20:44 +0000 (+0200) Subject: In browser, add option for recursive browsing. X-Git-Url: https://plomlompom.com/repos/blog?a=commitdiff_plain;h=589e2223a8acbb412a22afb036fbe06112a7799e;p=stable_plom In browser, add option for recursive browsing. --- diff --git a/browser.py b/browser.py index 99cfad9..c8d5d30 100755 --- a/browser.py +++ b/browser.py @@ -94,6 +94,7 @@ class MainWindow(Gtk.Window): gallery_store_filtered: Gtk.FilterListModel gallery_selection: Gtk.SingleSelection include_dirs: bool + recurse_dirs: bool per_row: int metadata: Gtk.TextBuffer sort_order: list @@ -110,7 +111,7 @@ class MainWindow(Gtk.Window): btn.connect('clicked', on_click) parent_box.append(btn) navbar = Gtk.Box(orientation=OR_H) - add_button('folder_view', lambda _: self.toggle_side_box(), navbar) + add_button('sidebar', lambda _: self.toggle_side_box(), navbar) add_button('reload', lambda _: self.load_directory(), navbar) navbar.append(Gtk.Label(label=' per row: ')) add_button('less', lambda _: self.inc_per_row(-1), navbar) @@ -118,6 +119,9 @@ class MainWindow(Gtk.Window): btn = Gtk.CheckButton(label='show directories') btn.connect('toggled', self.reset_include_dirs) navbar.append(btn) + btn = Gtk.CheckButton(label='recurse directories') + btn.connect('toggled', self.reset_recurse) + navbar.append(btn) return navbar def init_gallery_widgets(): @@ -127,16 +131,17 @@ class MainWindow(Gtk.Window): lambda _: self.update_file_selection()) self.gallery.connect( 'child-activated', lambda _, __: self.hit_file_selection()) - gallery_scroller = Gtk.ScrolledWindow( - child=self.gallery, propagate_natural_height=True) - gallery_scroller.get_vadjustment().connect( + scroller = Gtk.ScrolledWindow(propagate_natural_height=True) + scroller.get_vadjustment().connect( 'value-changed', lambda _: self.update_gallery_view()) - # attach a maximally expanded dummy that will be destroyed once we - # bind self.gallery to a model; seems necessary to pre-stretch the - # gallery_scroller's viewport for our first calculation (in the - # first run of update_gallery) of what images to load into it - self.gallery.append(Gtk.Box(hexpand=True, vexpand=True)) - return gallery_scroller + # We want our viewport at always maximum possible size (so we can + # safely calculate what's in it and what not), even if the gallery + # would be smaller. Therefore we frame the gallery in an expanding + # Fixed, to stretch out the viewport even if the gallery is small. + viewport_stretcher = Gtk.Fixed(hexpand=True, vexpand=True) + viewport_stretcher.put(self.gallery, 0, 0) + scroller.props.child = viewport_stretcher + return scroller def init_metadata_box(): text_view = Gtk.TextView() @@ -174,6 +179,7 @@ class MainWindow(Gtk.Window): self.gallery_selection = Gtk.SingleSelection.new( self.gallery_store_filtered) self.include_dirs = False + self.recurse_dirs = False self.per_row = 3 def init_key_control(): @@ -264,9 +270,9 @@ class MainWindow(Gtk.Window): i = 0 while True: gallery_item_at_i = self.gallery.get_child_at_index(i) - item_path = gallery_item_at_i.props.child.item.full_path if gallery_item_at_i is None: break + item_path = gallery_item_at_i.props.child.item.full_path if suggested_selection.full_path == item_path: to_select = gallery_item_at_i break @@ -278,19 +284,21 @@ class MainWindow(Gtk.Window): def update_gallery_view(self): """Load/unload gallery's file images based on viewport visibility.""" - viewport = self.gallery.get_parent() + viewport = self.gallery.get_parent().get_parent() vp_height = viewport.get_height() vp_width = viewport.get_width() vp_top = viewport.get_vadjustment().get_value() vp_bottom = vp_top + vp_height - max_slot_width = vp_width / self.per_row - 6 - slot_size = min(vp_height, max_slot_width) + margin = 6 + max_slot_width = vp_width / self.per_row - margin + prefered_slot_height = vp_height - margin + slot_size = min(prefered_slot_height, max_slot_width) for i in range(self.gallery_store_filtered.get_n_items()): slot = self.gallery.get_child_at_index(i).props.child if isinstance(slot.item, DirItem): slot.content.set_size_request(slot_size, slot_size) continue - slot_top = (i // self.per_row) * slot_size + slot_top = (i // self.per_row) * (slot_size + margin) slot_bottom = slot_top + slot_size in_viewport = (slot_bottom >= vp_top and slot_top <= vp_bottom) if in_viewport: @@ -371,28 +379,32 @@ class MainWindow(Gtk.Window): def load_directory(self, update_gallery=True): """Load into gallery directory at self.img_dir_absolute.""" - def read_directory_into_gallery_items(cache): - directory = Gio.File.new_for_path(self.img_dir_absolute) + def read_directory_into_gallery_items(cache, dir_path, + make_parent=False): + directory = Gio.File.new_for_path(dir_path) query_attrs = 'standard::name,time::*' - parent_path = abspath(path_join(self.img_dir_absolute, UPPER_DIR)) - parent_dir = directory.get_parent() - parent_dir_info = parent_dir.query_info( - query_attrs, Gio.FileQueryInfoFlags.NONE, None) - parent_dir_item = DirItem( - parent_path, parent_dir_info, is_parent=True) - self.gallery_store.append(parent_dir_item) + if make_parent: + parent_path = abspath(path_join(dir_path, UPPER_DIR)) + parent_dir = directory.get_parent() + parent_dir_info = parent_dir.query_info( + query_attrs, Gio.FileQueryInfoFlags.NONE, None) + parent_dir_item = DirItem( + parent_path, parent_dir_info, is_parent=True) + self.gallery_store.append(parent_dir_item) query_attrs = query_attrs + ',standard::content-type' enumerator = directory.enumerate_children( query_attrs, Gio.FileQueryInfoFlags.NONE, None) to_set_metadata_on = [] for info in enumerator: - if self.include_dirs\ - and info.get_file_type() == Gio.FileType.DIRECTORY: - self.gallery_store.append(DirItem(self.img_dir_absolute, - info)) + if info.get_file_type() == Gio.FileType.DIRECTORY: + if self.include_dirs: + self.gallery_store.append(DirItem(dir_path, info)) + if self.recurse_dirs: + read_directory_into_gallery_items( + cache, path_join(dir_path, info.get_name())) elif info.get_content_type()\ and info.get_content_type().startswith('image/'): - item = ImgItem(self.img_dir_absolute, info, cache) + item = ImgItem(dir_path, info, cache) if '' == item.model: to_set_metadata_on += [item] self.gallery_store.append(item) @@ -409,7 +421,7 @@ class MainWindow(Gtk.Window): json_dump({}, f) with open(CACHE_PATH, 'r', encoding='utf8') as f: cache = json_load(f) - read_directory_into_gallery_items(cache) + read_directory_into_gallery_items(cache, self.img_dir_absolute, True) with open(CACHE_PATH, 'w', encoding='utf8') as f: json_dump(cache, f) if update_gallery: @@ -433,6 +445,11 @@ class MainWindow(Gtk.Window): self.update_gallery(self.gallery_selection.props.selected_item, sort=False) + def reset_recurse(self, button): + """By button's .active, de-/activate recursion on image collection.""" + self.recurse_dirs = button.props.active + self.load_directory() + # movement def move_sort(self, direction):