lambda a, b, c: filter_entry.add_css_class('temp'))
-class Sorting():
+class TableConfig():
"""Representation of sort and filtering settings."""
_gallery_update = None
_gallery_items_attrs_full = None
_gallery_items_attrs_filtered = None
+ _gallery_set_by_1st_sorter = None
def __init__(self, sort_order):
def select_sort_order(_a, _b, _c):
if self._last_selected:
self._last_selected.get_last_child().hide()
- list_item = self.selection.props.selected_item.widget
+ list_item = self._selection.props.selected_item.widget
list_item.get_parent().grab_focus()
self._last_selected = list_item
+ def on_by_1st_sorter_toggle(btn):
+ self._btn_per_row.set_sensitive(not btn.props.active)
+ self._btn_show_dirs.set_sensitive(not btn.props.active)
+ if btn.props.active:
+ self._btn_show_dirs.set_active(False)
+ self._gallery_set_by_1st_sorter(btn.props.active)
+
self.order = sort_order
self.filter_inputs = {}
self._last_selected = None
- self.store = Gio.ListStore(item_type=Sorter)
- self.selection = Gtk.SingleSelection.new(self.store)
- self.selection.connect('selection-changed', select_sort_order)
+ self._store = Gio.ListStore(item_type=Sorter)
+ self._selection = Gtk.SingleSelection.new(self._store)
+ self._selection.connect('selection-changed', select_sort_order)
factory = Gtk.SignalListItemFactory()
factory.connect('setup', setup_sort_order_item)
factory.connect('bind', bind_sort_order_item)
- self.view = Gtk.ListView(model=self.selection, factory=factory)
+ self.view = Gtk.ListView(model=self._selection, factory=factory)
+
+ self._btn_show_dirs = Gtk.CheckButton(label='show')
+ self._btn_recurse_dirs = Gtk.CheckButton(label='recurse')
+ self._btn_reload_dir = Gtk.Button(label='reload')
+ self._btn_by_1st_sorter = Gtk.CheckButton(label='by 1st sorter')
+ self._btn_by_1st_sorter.connect('toggled', on_by_1st_sorter_toggle)
+ self._btn_per_row = Gtk.SpinButton.new_with_range(1, 9, 1)
+
+ dirs_box = Gtk.Box(orientation=OR_H)
+ dirs_box.append(Gtk.Label(label='directories:'))
+ dirs_box.append(self._btn_show_dirs)
+ dirs_box.append(self._btn_recurse_dirs)
+ dirs_box.append(self._btn_reload_dir)
+
+ per_row_box = Gtk.Box(orientation=OR_H)
+ per_row_box.append(Gtk.Label(label='cols/row:'))
+ per_row_box.append(self._btn_by_1st_sorter)
+ per_row_box.append(self._btn_per_row)
+
self.box = Gtk.Box(orientation=OR_V)
- self.box.append(Gtk.Label(label='<b>sort order</b>', use_markup=True))
+ title = Gtk.Label(label='<b>table config</b>', use_markup=True)
+ self.box.append(title)
+ self.box.append(dirs_box)
self.box.append(self.view)
- self.btn_activate = Gtk.Button(label='activate')
- self.btn_activate.props.sensitive = False
- self.btn_activate.connect(
- 'clicked', lambda _: self.activate_order())
- self.box.append(self.btn_activate)
+ self.box.append(per_row_box)
@classmethod
def from_suggestion(cls, suggestion_fused):
sort_order.reverse()
return cls(sort_order)
- def bind_gallery(self, on_update, items_attrs_full, items_attrs_filtered):
+ def bind_gallery(self, on_update, update_per_row, per_row_initial, reload,
+ toggle_showdirs, toggle_recurse, set_by_1st_sorter,
+ items_attrs_full, items_attrs_filtered):
"""Connect to Gallery interfaces where necessary."""
self._gallery_update = on_update
+ self._btn_show_dirs.connect('toggled', toggle_showdirs)
+ self._btn_recurse_dirs.connect('toggled', toggle_recurse)
+ self._btn_reload_dir.connect('clicked', reload)
+ self._gallery_set_by_1st_sorter = set_by_1st_sorter
self._gallery_items_attrs_full = items_attrs_full
self._gallery_items_attrs_filtered = items_attrs_filtered
+ self._btn_per_row.set_value(per_row_initial)
+ self._btn_per_row.connect(
+ 'value-changed',
+ lambda btn: update_per_row(btn.get_value_as_int()))
def move_selection(self, direction):
"""Move sort order selection by direction (-1 or +1)."""
min_idx, max_idx = 0, len(self.order) - 1
- cur_idx = self.selection.props.selected
+ cur_idx = self._selection.props.selected
if (1 == direction and cur_idx < max_idx)\
or (-1 == direction and cur_idx > min_idx):
- self.selection.props.selected = cur_idx + direction
+ self._selection.props.selected = cur_idx + direction
def move_sorter(self, direction):
"""Move selected item in sort order view, ensure temporary state."""
tmp_sort_order = []
- for i in range(self.store.get_n_items()):
- tmp_sort_order += [self.store.get_item(i)]
- cur_idx = self.selection.props.selected
+ for i in range(self._store.get_n_items()):
+ tmp_sort_order += [self._store.get_item(i)]
+ cur_idx = self._selection.props.selected
selected = tmp_sort_order[cur_idx]
if direction == -1 and cur_idx > 0:
prev_i = cur_idx - 1
else: # to catch movement beyond limits
return
self.update_box(tmp_sort_order, cur_idx + direction)
- self.selection.props.selected = cur_idx + direction
- for i in range(self.store.get_n_items()):
- sort_item = self.store.get_item(i)
+ self._selection.props.selected = cur_idx + direction
+ for i in range(self._store.get_n_items()):
+ sort_item = self._store.get_item(i)
sort_item.widget.add_css_class('temp')
- self.btn_activate.props.sensitive = True
def update_box(self, alt_order=None, cur_selection=0):
"""Rebuild .store from .order, or alt_order if provided."""
sort_order = alt_order if alt_order else self.order
- self.store.remove_all()
+ self._store.remove_all()
for sorter in sort_order:
- self.store.append(sorter)
- self.selection.props.selected = cur_selection
+ self._store.append(sorter)
+ self._selection.props.selected = cur_selection
def activate_order(self):
"""Write sort order box order into .order, mark finalized."""
self.order.clear()
- for i in range(self.store.get_n_items()):
- sorter = self.store.get_item(i)
+ for i in range(self._store.get_n_items()):
+ sorter = self._store.get_item(i)
sorter.widget.remove_css_class('temp')
self.order += [sorter]
- self.btn_activate.props.sensitive = False
self._gallery_update()
self._on_selection_change = on_selection_change
self.show_dirs = False
- self.per_row_by_first_sorter = False
- self.per_row = GALLERY_PER_ROW_DEFAULT
+ self.per_row_by_1st_sorter = False
+ self._per_row = GALLERY_PER_ROW_DEFAULT
self._slot_margin = GALLERY_SLOT_MARGIN
self._grid = None
self._force_width, self._force_height = 0, 0
self._update_view(refocus=False, force=True)
return True
+ def get_per_row(self):
+ """Wrapper to ._per_row to (for setting) discourage direct access."""
+ return self._per_row
+
+ def update_per_row(self, val):
+ """Wrapper to setting ._per_row to include call to .build_and_show."""
+ self._per_row = val
+ self.build_and_show()
+
+ def set_by_1st_sorter(self, val):
+ """On .per_row_by_1st_sorter update, also call .build_and_show."""
+ self.per_row_by_1st_sorter = val
+ self.build_and_show()
+
@property
def selected_item(self):
"""Return slot.item at self.selected_idx."""
self.slots = []
self._grid = Gtk.Grid()
self._fixed_frame.put(self._grid, 0, 0)
- if self.per_row_by_first_sorter:
+ if self.per_row_by_1st_sorter:
self.show_dirs = False
sort_attrs = []
for sorter in reversed(self._sort_order):
self.items_attrs_filtered[sorter.name])]
i_row_ref = [0]
i_slot_ref = [0]
- self.per_row = len(sort_attrs[-1][1])
+ self._per_row = len(sort_attrs[-1][1])
build_rows_by_attrs(sort_attrs, entries_filtered)
else:
self.dir_entries_filtered_sorted = sorted(
entries_filtered, key=cmp_to_key(self._sort_cmp))
i_row, i_col = 0, 0
for i, item in enumerate(self.dir_entries_filtered_sorted):
- if self.per_row == i_col:
+ if self._per_row == i_col:
i_col = 0
i_row += 1
slot = GallerySlot(item, item_clicker(i))
def move_selection(self, x_inc, y_inc, buf_end):
"""Move .selection, update its dependencies, redraw gallery."""
min_idx, max_idx = 0, len(self.slots) - 1
- if -1 == y_inc and self.selected_idx >= self.per_row:
- new_idx = self.selected_idx - self.per_row
- elif 1 == y_inc and self.selected_idx <= max_idx - self.per_row:
- new_idx = self.selected_idx + self.per_row
+ if -1 == y_inc and self.selected_idx >= self._per_row:
+ new_idx = self.selected_idx - self._per_row
+ elif 1 == y_inc and self.selected_idx <= max_idx - self._per_row:
+ new_idx = self.selected_idx + self._per_row
elif -1 == x_inc and self.selected_idx > 0:
new_idx = self.selected_idx - 1
elif 1 == x_inc and self.selected_idx < max_idx:
vp_bottom = vp_top + self._viewport_height
vp_width = (self._force_width if self._force_width
else self._viewport.get_width())
- max_slot_width = (vp_width // self.per_row) - self._slot_margin
+ max_slot_width = (vp_width // self._per_row) - self._slot_margin
prefered_slot_height = self._viewport_height - self._slot_margin
slot_size = min(prefered_slot_height, max_slot_width)
for idx, slot in enumerate(self.slots):
- slot_top = (idx // self.per_row) * (slot_size + self._slot_margin)
+ slot_top = (idx // self._per_row) * (slot_size + self._slot_margin)
slot_bottom = slot_top + slot_size
in_vp = (slot_bottom >= vp_top and slot_top <= vp_bottom)
slot.update_widget(slot_size, self._slot_margin, in_vp)
if self._col_headers_grid:
self._col_headers_frame.remove(self._col_headers_grid)
self._col_headers_grid = None
- if self.per_row_by_first_sorter:
+ if self.per_row_by_1st_sorter:
self._col_headers_grid = Gtk.Grid()
self._col_headers_frame.put(self._col_headers_grid, 0, 0)
attr_values = self.items_attrs_filtered[self._sort_order[0].name]
return
focused_idx = self.selected_idx
full_slot_height = slot_size + self._slot_margin
- focused_slot_top = (focused_idx // self.per_row) * full_slot_height
+ focused_slot_top = (focused_idx // self._per_row) * full_slot_height
focused_slot_bottom = focused_slot_top + slot_size
if focused_slot_top < vp_top:
vp_scroll.set_value(focused_slot_top)
metadata: Gtk.TextBuffer
prev_key: list
counter: Gtk.Label
- btn_dec_per_row: Gtk.Button
- btn_inc_per_row: Gtk.Button
- btn_show_dirs: Gtk.Button
def __init__(self, app, **kwargs):
super().__init__(**kwargs)
self.counter = Gtk.Label()
navbar.append(self.counter)
add_button('sidebar', lambda _: self.toggle_side_box())
- add_button('reload', lambda _: self.load_directory())
- self.btn_show_dirs = add_button('show directories',
- self.reset_show_dirs, True)
- add_button('recurse directories ', self.reset_recurse, True)
- navbar.append(Gtk.Label(label=' per row: '))
- add_button('by first sorter', self.reset_row_by_first_sorter, True)
- self.btn_dec_per_row = add_button('less',
- lambda _: self.inc_per_row(-1))
- self.btn_inc_per_row = add_button('more',
- lambda _: self.inc_per_row(+1))
return navbar
def init_metadata_box():
on_hit_item=self.hit_gallery_item,
on_grid_built=self.app.sort.update_box,
on_selection_change=self.update_metadata_on_gallery_selection)
- self.app.sort.bind_gallery(
- on_update=self.gallery.build_and_show,
- items_attrs_full=self.gallery.items_attrs,
- items_attrs_filtered=self.gallery.items_attrs_filtered)
self.recurse_dirs = False
setup_css()
self.load_directory(update_gallery_view=False)
self.connect('notify::focus-widget',
lambda _, __: self.on_focus_change())
+ self.app.sort.bind_gallery(
+ on_update=self.gallery.build_and_show,
+ reload=lambda _: self.load_directory(),
+ update_per_row=self.gallery.update_per_row,
+ per_row_initial=self.gallery.get_per_row(),
+ toggle_showdirs=self.reset_show_dirs,
+ toggle_recurse=self.reset_recurse,
+ set_by_1st_sorter=self.gallery.set_by_1st_sorter,
+ items_attrs_full=self.gallery.items_attrs,
+ items_attrs_filtered=self.gallery.items_attrs_filtered)
GLib.idle_add(self.gallery.build_and_show)
def on_focus_change(self):
"""Handle reactions on focus changes in .gallery and .sort."""
focused = self.get_focus()
+ if not focused:
+ return
if isinstance(focused, GallerySlot):
self.gallery.on_focus_slot(focused)
elif focused.get_parent() == self.app.sort.view:
side_box_width = self.side_box.measure(OR_H, -1).natural
self.gallery.on_resize(self.get_width() - side_box_width)
- def reset_row_by_first_sorter(self, button):
- """By button's .active, (un-)mirror top sorter in each gallery row."""
- self.gallery.per_row_by_first_sorter = button.props.active
- self.btn_inc_per_row.set_sensitive(not button.props.active)
- self.btn_dec_per_row.set_sensitive(not button.props.active)
- self.btn_show_dirs.set_sensitive(not button.props.active)
- if button.props.active:
- self.btn_show_dirs.set_active(False)
- self.btn_show_dirs.set_sensitive(not button.props.active)
- self.gallery.build_and_show()
-
def reset_show_dirs(self, button):
"""By button's .active, in-/exclude directories from gallery view."""
self.gallery.show_dirs = button.props.active
self.load_directory()
- def inc_per_row(self, increment):
- """Change by increment how many items max to display in gallery row."""
- if self.gallery.per_row + increment > 0:
- self.gallery.per_row += increment
- self.gallery.build_and_show()
-
def reset_recurse(self, button):
"""By button's .active, de-/activate recursion on image collection."""
self.recurse_dirs = button.props.active
parser.add_argument('-s', '--sort-order', default=SORT_DEFAULT)
opts = parser.parse_args()
self.img_dir_absolute = abspath(opts.directory)
- self.sort = Sorting.from_suggestion(opts.sort_order)
+ self.sort = TableConfig.from_suggestion(opts.sort_order)
def do_activate(self, *args, **kwargs):
"""Parse arguments, start window, keep it open."""