From: Christian Heller Date: Wed, 13 Nov 2024 02:12:15 +0000 (+0100) Subject: Browser: As prompt summary in by_1st view, only show part actually differing. X-Git-Url: https://plomlompom.com/repos/%7B%7Bprefix%7D%7D/%7B%7Bdb.prefix%7D%7D/%7B%7B%20web_path%20%7D%7D/%27%29;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20chunks.push%28escapeHTML%28span%5B2%5D%29%29;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20chunks.push%28%27?a=commitdiff_plain;h=39d167e59c240056e77e4576a02b39451982216d;p=stable_plom Browser: As prompt summary in by_1st view, only show part actually differing. --- diff --git a/browser.py b/browser.py index 63b20ec..1e6fc42 100755 --- a/browser.py +++ b/browser.py @@ -25,6 +25,8 @@ from stable.gen_params import (GenParams, GEN_PARAMS_FLOAT, # noqa: E402 GEN_PARAMS_INT, GEN_PARAMS_STR, # noqa: E402 GEN_PARAMS) # noqa: E402 +PromptDiff = tuple[str, str, str] +PromptsDiff = dict[str, PromptDiff] BasicItemsAttrs = dict[str, set[str]] AttrVals: TypeAlias = list[str] AttrValsByVisibility: TypeAlias = dict[str, AttrVals] @@ -210,7 +212,7 @@ class SorterAndFilterer(GObject.GObject): 'deleted_text', lambda a, b, c: self.widget.filter_input.add_css_class('temp')) - def passes_filter(self, value: str | int | float) -> bool: + def filter_allows_value(self, value: str | int | float) -> bool: """Return if value passes filter defined by .name and .filter_text.""" number_attributes = (set(s.lower() for s in GEN_PARAMS_INT) | set(s.lower() for s in GEN_PARAMS_FLOAT) | @@ -745,6 +747,7 @@ class Gallery: self.items_attrs: ItemsAttrs = {} self.selected_idx = 0 self.slots: list[GallerySlot] = [] + self._prompts_diff: PromptsDiff = {} self._grid = Gtk.Grid() self._force_width, self._force_height = 0, 0 @@ -812,9 +815,49 @@ class Gallery: else: self.request_update(build_grid=True) - def _make_basic_items_attrs(self, - entries: list[GalleryItem] - ) -> BasicItemsAttrs: + def _prep_items_attrs(self, + entries: list[GalleryItem] + ) -> tuple[BasicItemsAttrs, PromptsDiff]: + + def diff_prompts(basic_items_attrs: BasicItemsAttrs) -> PromptsDiff: + if 'prompt' not in basic_items_attrs: + return {} + prompts_diff: PromptsDiff = {} + prompts = list(basic_items_attrs['prompt']) + + def find_longest_equal(prompts, j, matcher): + longest_total, temp_longest = '', '' + while j < len(prompts[0]): + if 'end' == matcher: + temp_longest = prompts[0][-j] + temp_longest + else: + temp_longest += prompts[0][j] + if len(temp_longest) > len(longest_total): + found_in_all = True + for prompt in prompts[1:]: + if ('start' == matcher + and not prompt.startswith(temp_longest)) or\ + ('end' == matcher + and not prompt.endswith(temp_longest)) or\ + ('in' == matcher + and temp_longest not in prompt): + found_in_all = False + break + if not found_in_all: + break + longest_total = temp_longest + j += 1 + return longest_total + + prefix = find_longest_equal(prompts, 0, 'start') + suffix = find_longest_equal(prompts, 1, matcher='end') + cores = [p[len(prefix):] for p in prompts] + if suffix: + for i, p in enumerate(cores): + cores[i] = p[:-len(suffix)] + for i, p in enumerate(prompts): + prompts_diff[p] = (cores[i], '', '') + return prompts_diff basic_items_attrs = {} for attr_name in (s.name for s in self._sort_order): @@ -825,7 +868,8 @@ class Gallery: if val is not None: vals.add(val) basic_items_attrs[attr_name] = vals - return basic_items_attrs + prompts_diff = diff_prompts(basic_items_attrs) + return basic_items_attrs, prompts_diff def _load_directory(self) -> None: """(Re-)build .dir_entries from ._img_dir_path, ._basic_items_attrs.""" @@ -872,14 +916,15 @@ class Gallery: read_directory(path) read_directory(self._img_dir_path, make_parent=True) - basic_items_attrs = self._make_basic_items_attrs(self.dir_entries) + self._basic_items_attrs, self._prompts_diff = self._prep_items_attrs( + self.dir_entries) ignorable_attrs = [] - for attr_name, attr_vals in basic_items_attrs.items(): + for attr_name, attr_vals in self._basic_items_attrs.items(): if len(attr_vals) < 2: ignorable_attrs += [attr_name] for attr_name in ignorable_attrs: self._sort_order.remove(attr_name) - self._basic_items_attrs = basic_items_attrs + del self._basic_items_attrs[attr_name] self._cache_db.write() @property @@ -923,14 +968,16 @@ class Gallery: sorter = self._sort_order.by_name(attr_name) items_attrs[attr_name] = {'incl': [], 'excl': []} for v in vals: - k = ('incl' if (not sorter or sorter.passes_filter(v)) - else 'excl') + passes_filter = sorter is None + if sorter: + passes_filter = sorter.filter_allows_value(v) + k = 'incl' if passes_filter else 'excl' items_attrs[attr_name][k] += [v] return items_attrs items_attrs_tmp_1 = separate_items_attrs(self._basic_items_attrs) filtered = filter_entries(items_attrs_tmp_1) - reduced_basic_items_attrs = self._make_basic_items_attrs(filtered) + reduced_basic_items_attrs = self._prep_items_attrs(filtered)[0] items_attrs_tmp_2 = separate_items_attrs(reduced_basic_items_attrs) for attr_name in (s.name for s in self._sort_order): final_values: AttrValsByVisibility = {'incl': [], 'semi': []} @@ -982,6 +1029,9 @@ class Gallery: if 1 == len(remaining): for i, attr in enumerate(ancestors): parent_attr_name, parent_attr_value = attr + if 'prompt' == parent_attr_name: + prompt_diff = self._prompts_diff[parent_attr_value] + parent_attr_value = f'…{prompt_diff[0]}…' txt = f'{parent_attr_name}: {parent_attr_value}' vlabel = VerticalLabel(txt, self._slots_geometry) self._grid.attach(vlabel, i, i_row_ref[0], 1, 1) @@ -1026,6 +1076,8 @@ class Gallery: self._col_headers_grid.attach(Gtk.Box(), 0, 0, 1, 1) top_attr_name: str = sort_attrs[-1][0] for i, val in enumerate(sort_attrs[-1][1]): + if 'prompt' == top_attr_name: + val = f'…{self._prompts_diff[val][0]}…' label = Gtk.Label(label=f'{top_attr_name}: {val}', xalign=0, ellipsize=Pango.EllipsizeMode.MIDDLE)